1/* 2 * Driver for the i2c/i2s based DAC3550a sound chip used 3 * on some Apple iBooks. Also known as "DACA". 4 * 5 * This file is subject to the terms and conditions of the GNU General Public 6 * License. See the file COPYING in the main directory of this archive 7 * for more details. 8 */ 9 10#include <linux/version.h> 11#include <linux/module.h> 12#include <linux/slab.h> 13#include <linux/proc_fs.h> 14#include <linux/ioport.h> 15#include <linux/sysctl.h> 16#include <linux/types.h> 17#include <linux/i2c.h> 18#include <linux/init.h> 19#include <asm/uaccess.h> 20#include <asm/errno.h> 21#include <asm/io.h> 22 23#include "dmasound.h" 24 25/* FYI: This code was derived from the tas3001c.c Texas/Tumbler mixer 26 * control code, as well as info derived from the AppleDACAAudio driver 27 * from Darwin CVS (main thing I derived being register numbers and 28 * values, as well as when to make the calls). */ 29 30#define I2C_DRIVERID_DACA (0xFDCB) 31 32#define DACA_VERSION "0.1" 33#define DACA_DATE "20010930" 34 35static int cur_left_vol; 36static int cur_right_vol; 37static struct i2c_client * daca_client = NULL; 38 39static int daca_attach_adapter(struct i2c_adapter *adapter); 40 41static int daca_attach_adapter(struct i2c_adapter *adapter); 42static int daca_detect_client(struct i2c_adapter *adapter, int address); 43static int daca_detach_client(struct i2c_client *client); 44 45/* Unique ID allocation */ 46static int daca_id; 47static int daca_initialized; 48 49struct daca_data 50{ 51 int arf; /* place holder for furture use */ 52}; 53 54struct i2c_driver daca_driver = { 55 name: "DAC3550A driver V " DACA_VERSION, 56 id: I2C_DRIVERID_DACA, 57 flags: I2C_DF_NOTIFY, 58 attach_adapter: &daca_attach_adapter, 59 detach_client: &daca_detach_client, 60 command: NULL, 61 inc_use: NULL, /* &daca_inc_use, */ 62 dec_use: NULL /* &daca_dev_use */ 63 }; 64 65 66#define VOL_MAX ((1<<20) - 1) 67 68void 69daca_get_volume(uint * left_vol, uint *right_vol) 70{ 71 *left_vol = cur_left_vol >> 5; 72 *right_vol = cur_right_vol >> 5; 73} 74 75int 76daca_set_volume(uint left_vol, uint right_vol) 77{ 78 unsigned short voldata; 79 80 if (!daca_client) 81 return -1; 82 83 /* Derived from experience, not from any specific values */ 84 left_vol <<= 5; 85 right_vol <<= 5; 86 87 if (left_vol > VOL_MAX) 88 left_vol = VOL_MAX; 89 if (right_vol > VOL_MAX) 90 right_vol = VOL_MAX; 91 92 voldata = ((left_vol >> 14) & 0x3f) << 8; 93 voldata |= (right_vol >> 14) & 0x3f; 94 95 if (i2c_smbus_write_word_data(daca_client, 2, voldata) < 0) { 96 printk("daca: failed to set volume \n"); 97 return -1; 98 } 99 100 cur_left_vol = left_vol; 101 cur_right_vol = right_vol; 102 103 return 0; 104} 105 106int 107daca_leave_sleep(void) 108{ 109 if (!daca_client) 110 return -1; 111 112 /* Do a short sleep, just to make sure I2C bus is awake and paying 113 * attention to us 114 */ 115 wait_ms(20); 116 /* Write the sample rate reg the value it needs */ 117 i2c_smbus_write_byte_data(daca_client, 1, 8); 118 daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); 119 /* Another short delay, just to make sure the other I2C bus writes 120 * have taken... 121 */ 122 wait_ms(20); 123 /* Write the global config reg - invert right power amp, 124 * DAC on, use 5-volt mode */ 125 i2c_smbus_write_byte_data(daca_client, 3, 0x45); 126 127 return 0; 128} 129 130int 131daca_enter_sleep(void) 132{ 133 if (!daca_client) 134 return -1; 135 136 i2c_smbus_write_byte_data(daca_client, 1, 8); 137 daca_set_volume(cur_left_vol >> 5, cur_right_vol >> 5); 138 139 /* Write the global config reg - invert right power amp, 140 * DAC on, enter low-power mode, use 5-volt mode 141 */ 142 i2c_smbus_write_byte_data(daca_client, 3, 0x65); 143 144 return 0; 145} 146 147static int 148daca_attach_adapter(struct i2c_adapter *adapter) 149{ 150 if (!strncmp(adapter->name, "mac-io", 6)) 151 daca_detect_client(adapter, 0x4d); 152 return 0; 153} 154 155static int 156daca_init_client(struct i2c_client * new_client) 157{ 158 159 /* Write the global config reg - invert right power amp, 160 * DAC on, use 5-volt mode 161 */ 162 if (i2c_smbus_write_byte_data(new_client, 3, 0x45)) 163 return -1; 164 165 i2c_smbus_write_byte_data(new_client, 1, 8); 166 daca_client = new_client; 167 daca_set_volume(15000, 15000); 168 169 return 0; 170} 171 172static int 173daca_detect_client(struct i2c_adapter *adapter, int address) 174{ 175 int rc = 0; 176 struct i2c_client *new_client; 177 178 struct daca_data *data; 179 const char *client_name = "DAC 3550A Digital Equalizer"; 180 181 new_client = kmalloc( 182 sizeof(struct i2c_client) + sizeof(struct daca_data), 183 GFP_KERNEL); 184 if (!new_client) { 185 rc = -ENOMEM; 186 goto bail; 187 } 188 189 /* This is tricky, but it will set the data to the right value. */ 190 new_client->data = new_client + 1; 191 data = (struct daca_data *) (new_client->data); 192 193 new_client->addr = address; 194 new_client->data = data; 195 new_client->adapter = adapter; 196 new_client->driver = &daca_driver; 197 new_client->flags = 0; 198 199 strcpy(new_client->name,client_name); 200 201 new_client->id = daca_id++; /* Automatically unique */ 202 203 if (daca_init_client(new_client)) { 204 rc = -ENODEV; 205 goto bail; 206 } 207 208 /* Tell the i2c layer a new client has arrived */ 209 if (i2c_attach_client(new_client)) { 210 rc = -ENODEV; 211 goto bail; 212 } 213bail: 214 if (rc && new_client) 215 kfree(new_client); 216 return rc; 217} 218 219 220static int 221daca_detach_client(struct i2c_client *client) 222{ 223 if (client == daca_client) 224 daca_client = NULL; 225 226 i2c_detach_client(client); 227 kfree(client); 228 229 return 0; 230} 231 232int 233daca_cleanup(void) 234{ 235 if (!daca_initialized) 236 return -ENODEV; 237 i2c_del_driver(&daca_driver); 238 daca_initialized = 0; 239 240 return 0; 241} 242 243int 244daca_init(void) 245{ 246 int rc; 247 248 if (daca_initialized) 249 return 0; 250 251 printk("dac3550a driver version %s (%s)\n",DACA_VERSION,DACA_DATE); 252 253 if ((rc = i2c_add_driver(&daca_driver))) { 254 printk("dac3550a: Driver registration failed, module not inserted.\n"); 255 daca_cleanup(); 256 return rc; 257 } 258 daca_initialized = 1; 259 260 return 0; 261} 262