]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/i2c/chips/tlv320aic23.c
i2c: Merge omap i2c drivers from omap-historic
[linux-2.6-omap-h63xx.git] / drivers / i2c / chips / tlv320aic23.c
1 /*
2  *   Texas Instrumens TLV320AIC23 audio codec's i2c interface.
3  *
4  *   Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
5  *   Copyright (c) by Jussi Laako <jussi.laako@nokia.com>
6  *
7  *   This program is free software; you can redistribute it and/or modify
8  *   it under the terms of the GNU General Public License as published by
9  *   the Free Software Foundation; either version 2 of the License, or
10  *   (at your option) any later version.
11  *
12  *   This program is distributed in the hope that it will be useful,
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *   GNU General Public License for more details.
16  *
17  *   You should have received a copy of the GNU General Public License
18  *   along with this program; if not, write to the Free Software
19  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
20  *
21  */
22
23 #include <linux/module.h>
24 #include <linux/init.h>
25 #include <linux/i2c.h>
26 #include <linux/slab.h>
27 #include <linux/device.h>
28 #include <linux/platform_device.h>
29 #include <asm/io.h>
30 #include <asm/arch/aic23.h>
31 #include <asm/arch/mcbsp.h>
32
33 #define TLV320AIC23_VERSION     "1.8"
34 #define TLV320AIC23_DATE        "10-Feb-2006"
35 #define MAX_VOL                 100
36 #define MIN_VOL                 0
37 #define MAX_GAIN                100
38 #define MIN_GAIN                0
39 #define OUTPUT_VOLUME_MIN       LHV_MIN
40 #define OUTPUT_VOLUME_MAX       LHV_MAX
41 #define OUTPUT_VOLUME_RANGE     (OUTPUT_VOLUME_MAX - OUTPUT_VOLUME_MIN)
42 #define INPUT_VOLUME_MIN        LIV_MIN
43 #define INPUT_VOLUME_MAX        LIV_MAX
44 #define INPUT_VOLUME_RANGE      (INPUT_VOLUME_MAX - INPUT_VOLUME_MIN)
45
46 /* I2C Addresses to scan */
47 static unsigned short normal_i2c[] = { TLV320AIC23ID1, TLV320AIC23ID2, \
48                                        I2C_CLIENT_END };
49 /*static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };*/
50
51 /* This makes all addr_data:s */
52 I2C_CLIENT_INSMOD;
53
54 static struct i2c_driver aic23_driver;
55 static struct i2c_client *new_client;
56 static int selftest;
57
58 static struct aic23_info {
59         u16 volume_reg_left;
60         u16 volume_reg_right;
61         u16 input_gain_reg_left;
62         u16 input_gain_reg_right;
63         u16 power;                      /* For POWER_DOWN_CONTROL_ADDR */
64         u16 mask;                       /* For ANALOG_AUDIO_CONTROL_ADDR */
65         int mic_loopback;
66         int mic_enable;
67         int sta;
68         int power_down;
69         int initialized;
70 } aic23_info_l;
71
72 static int _aic23_write_value(struct i2c_client *client, u8 reg, u16 value)
73 {
74         u8 val, wreg;
75
76         /* TLV320AIC23 has 7 bit address and 9 bits of data
77          * so we need to switch one data bit into reg and rest
78          * of data into val
79          */
80
81         wreg = (reg << 1);
82         val = (0x01 & (value >> 8));
83         wreg = (wreg | val);
84         val = (0x00ff & value);
85
86         return i2c_smbus_write_byte_data(client, wreg, val);
87 }
88
89 int aic23_write_value(u8 reg, u16 value)
90 {
91         static struct i2c_client *client;
92         client = new_client;
93         _aic23_write_value(client, reg, value);
94
95         return 0;
96 }
97
98 static int aic23_detect_client(struct i2c_adapter *adapter, int address,
99                                      int kind)
100 {
101         int err = 0;
102         const char *client_name = "TLV320AIC23 Audio Codec";
103
104         if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA |
105                                      I2C_FUNC_SMBUS_WRITE_BYTE)) {
106                 printk(KERN_WARNING "%s functinality check failed\n",
107                        client_name);
108                 return err;
109         }
110
111         if (!(new_client = kmalloc(sizeof(struct i2c_client),
112                                    GFP_KERNEL))) {
113                 err = -ENOMEM;
114                 printk(KERN_WARNING "Couldn't allocate memory for %s\n",
115                        client_name);
116                 return err;
117         }
118
119         memset(new_client, 0x00, sizeof(struct i2c_client));
120         new_client->addr = address;
121         new_client->adapter = adapter;
122         new_client->driver = &aic23_driver;
123         new_client->flags = 0;
124         strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
125
126         if ((err = i2c_attach_client(new_client))) {
127                 printk(KERN_WARNING "Couldn't attach %s\n", client_name);
128                 kfree(new_client);
129                 return err;
130         }
131         return 0;
132 }
133
134 static int aic23_detach_client(struct i2c_client *client)
135 {
136         int err;
137
138         if ((err = i2c_detach_client(client))) {
139                 printk("aic23.o: Client deregistration failed, \
140                        client not detached.\n");
141                 return err;
142         }
143         kfree(client);
144         return 0;
145 }
146
147 static int aic23_attach_adapter(struct i2c_adapter *adapter)
148 {
149         int res;
150
151         res = i2c_probe(adapter, &addr_data, &aic23_detect_client);
152         return res;
153 }
154
155 static struct i2c_driver aic23_driver = {
156         .driver = {
157                 .name   = "OMAP+TLV320AIC23 codec",
158                 /*.flags        = I2C_DF_NOTIFY,*/
159         },
160         .id             = I2C_DRIVERID_MISC, /* Experimental ID */
161         .attach_adapter = aic23_attach_adapter,
162         .detach_client  = aic23_detach_client,
163 };
164
165 /*
166  * Configures the McBSP3 which is used to send clock to the AIC23 codec.
167  * The input clock rate from DSP is 12MHz.
168  * The DSP clock must be on before this is called.
169  */
170 static int omap_mcbsp3_aic23_clock_init(void)
171 {
172         u16 w;
173
174         /* enable 12MHz clock to mcbsp 1 & 3 */
175         __raw_writew(__raw_readw(DSP_IDLECT2) | (1<<1), DSP_IDLECT2);
176         __raw_writew(__raw_readw(DSP_RSTCT2) | 1 | 1<<1, DSP_RSTCT2);
177
178         /* disable sample rate generator */
179         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR1, 0x0000);
180         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, 0x0000);
181
182         /* pin control register */
183         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, PCR0,(CLKXM | CLKXP | CLKRP));
184
185         /* configure srg to send 12MHz pulse from dsp peripheral clock */
186         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR1, 0x0000);
187         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SRGR2, CLKSM);
188
189         /* enable sample rate generator */
190         w = OMAP_MCBSP_READ(OMAP1610_MCBSP3_BASE, SPCR2);
191         OMAP_MCBSP_WRITE(OMAP1610_MCBSP3_BASE, SPCR2, (w | FREE | GRST));
192         printk("Clock enabled to MCBSP1 & 3 \n");
193
194         return 0;
195 }
196
197 static void update_volume_left(int volume)
198 {
199         u16 val = 0;
200         val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
201         aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, val);
202         aic23_info_l.volume_reg_left = volume;
203 }
204
205 static void update_volume_right(int volume)
206 {
207         u16 val = 0;
208         val = ((volume * OUTPUT_VOLUME_RANGE) / 100) + OUTPUT_VOLUME_MIN;
209         aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, val);
210         aic23_info_l.volume_reg_right = volume;
211 }
212
213 static void set_mic(int mic_en)
214 {
215         u16 dg_ctrl;
216
217         if (mic_en) {
218                 aic23_info_l.power = OSC_OFF | LINE_OFF;
219                 dg_ctrl = ADCHP_ON;
220                 aic23_info_l.mask &= ~MICM_MUTED;
221                 aic23_info_l.mask |= MICB_20DB; /* STE_ENABLED */
222         } else {
223                 aic23_info_l.power =
224                         OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
225                 dg_ctrl = 0x00;
226                 aic23_info_l.mask =
227                         DAC_SELECTED | INSEL_MIC | MICM_MUTED;
228         }
229         aic23_write_value(POWER_DOWN_CONTROL_ADDR,
230                                 aic23_info_l.power);
231         aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, dg_ctrl);
232         aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
233                                 aic23_info_l.mask);
234         aic23_info_l.mic_enable = mic_en;
235
236         printk(KERN_INFO "aic23 mic state: %i\n", mic_en);
237 }
238
239 static void aic23_init_power(void)
240 {
241         aic23_write_value(RESET_CONTROL_ADDR, 0x00);
242
243         if (aic23_info_l.initialized == 0) {
244                 aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
245                 aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
246         }
247         else {
248                 update_volume_left(aic23_info_l.volume_reg_left);
249                 update_volume_right(aic23_info_l.volume_reg_right);
250         }
251
252         aic23_info_l.mask = DAC_SELECTED | INSEL_MIC | MICM_MUTED;
253         aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
254                                 aic23_info_l.mask);
255         aic23_write_value(DIGITAL_AUDIO_CONTROL_ADDR, 0x00);
256         aic23_write_value(DIGITAL_AUDIO_FORMAT_ADDR, LRP_ON | FOR_DSP);
257         aic23_write_value(SAMPLE_RATE_CONTROL_ADDR, USB_CLK_ON);
258         aic23_write_value(DIGITAL_INTERFACE_ACT_ADDR, ACT_ON);
259         aic23_info_l.power = OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF;
260         aic23_write_value(POWER_DOWN_CONTROL_ADDR,
261                                 aic23_info_l.power);
262
263         /* enable mic input */
264         if (aic23_info_l.mic_enable)
265                 set_mic(aic23_info_l.mic_enable);
266
267         printk(KERN_INFO "aic23_init_power() done\n");
268 }
269
270 void aic23_power_down(void)
271 {
272         if (aic23_info_l.initialized) {
273                 printk("aic23 powering down\n");
274                 aic23_write_value(POWER_DOWN_CONTROL_ADDR, 0xff);
275         }
276         aic23_info_l.power_down = 1;
277 }
278
279 void aic23_power_up(void)
280 {
281         if (aic23_info_l.initialized) {
282                 printk("aic23 powering up\n");
283                 aic23_init_power();
284         }
285         aic23_info_l.power_down = 0;
286 }
287
288 /*----------------------------------------------------------------------*/
289 /*                      sysfs initializations                           */
290 /*----------------------------------------------------------------------*/
291
292 static ssize_t store_volume_left(struct device *dev,
293                                  struct device_attribute *attr,
294                                  const char *buf, size_t count)
295 {
296         signed volume;
297
298         sscanf(buf, "%i", &volume);
299
300         if (volume < MIN_VOL) {
301                 aic23_power_down();
302                 return count;
303         } else if (volume > MIN_VOL && aic23_info_l.power_down) {
304                 aic23_info_l.volume_reg_left = volume;
305                 aic23_power_up();
306                 return count;
307         }
308         if (volume > MAX_VOL)
309                 volume = MAX_VOL;
310
311         update_volume_left(volume);
312         return count;
313 }
314
315 static ssize_t show_volume_left(struct device *dev,
316                                 struct device_attribute *attr, char *buf)
317 {
318         return sprintf(buf, "%u\n", aic23_info_l.volume_reg_left);
319 }
320
321 static DEVICE_ATTR(volume_left, S_IRUGO | S_IWUGO,
322                    show_volume_left, store_volume_left);
323
324 static ssize_t store_volume_right(struct device *dev,
325                                   struct device_attribute *attr,
326                                   const char *buf, size_t count)
327 {
328         signed volume;
329
330         sscanf(buf, "%i", &volume);
331         if (volume < MIN_VOL) {
332                 aic23_power_down();
333                 return count;
334         } else if (volume > MIN_VOL && aic23_info_l.power_down) {
335                 aic23_info_l.volume_reg_right = volume;
336                 aic23_power_up();
337                 return count;
338         }
339         if (volume > MAX_VOL)
340                 volume = MAX_VOL;
341
342         update_volume_right(volume);
343         return count;
344 }
345
346 static ssize_t show_volume_right(struct device *dev,
347                                  struct device_attribute *attr, char *buf)
348 {
349         return sprintf(buf, "%u\n", aic23_info_l.volume_reg_right);
350 }
351
352 static DEVICE_ATTR(volume_right, S_IRUGO | S_IWUGO,
353                    show_volume_right, store_volume_right);
354
355 static ssize_t store_gain_left(struct device *dev,
356                                struct device_attribute *attr,
357                                const char *buf, size_t count)
358 {
359         u16 val = 0;
360         unsigned gain;
361
362         sscanf(buf, "%u", &gain);
363         if (gain > MAX_VOL)
364                 gain = MAX_VOL;
365
366         val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
367         aic23_write_value(LEFT_LINE_VOLUME_ADDR, val);
368         aic23_info_l.input_gain_reg_left = gain;
369
370         return count;
371 }
372
373 static ssize_t show_gain_left(struct device *dev,
374                               struct device_attribute *attr, char *buf)
375 {
376         return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_left);
377 }
378
379 static DEVICE_ATTR(gain_left, S_IRUGO | S_IWUSR, show_gain_left,
380                    store_gain_left);
381
382 static ssize_t store_gain_right(struct device *dev,
383                                 struct device_attribute *attr,
384                                 const char *buf, size_t count)
385 {
386         u16 val = 0;
387         unsigned gain;
388
389         sscanf(buf, "%u", &gain);
390         if (gain > MAX_VOL)
391                 gain = MAX_VOL;
392
393         val = ((gain * INPUT_VOLUME_RANGE) / 100) + INPUT_VOLUME_MIN;
394         aic23_write_value(RIGHT_LINE_VOLUME_ADDR, val);
395         aic23_info_l.input_gain_reg_right = gain;
396
397         return count;
398 }
399
400 static ssize_t show_gain_right(struct device *dev,
401                                struct device_attribute *attr, char *buf)
402 {
403         return sprintf(buf, "%u\n", aic23_info_l.input_gain_reg_right);
404 }
405
406 static DEVICE_ATTR(gain_right, S_IRUGO | S_IWUSR, show_gain_right,
407                    store_gain_right);
408
409 static ssize_t store_mic_loopback(struct device *dev,
410                                   struct device_attribute *attr,
411                                   const char *buf, size_t count)
412 {
413         int mic;
414
415         sscanf(buf, "%i", &mic);
416         if (mic > 0) {
417                 aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
418                                         OSC_OFF | ADC_OFF | LINE_OFF);
419                 aic23_info_l.mask = STE_ENABLED | DAC_SELECTED \
420                                           | INSEL_MIC | MICB_20DB;
421                 aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
422                                         aic23_info_l.mask);
423                 mic = 1;
424         }
425         else {
426                 aic23_write_value(POWER_DOWN_CONTROL_ADDR, \
427                                         OSC_OFF | ADC_OFF | MIC_OFF | LINE_OFF);
428                 mic = 0;
429         }
430         aic23_info_l.mic_loopback = mic;
431
432         return count;
433 }
434
435 static ssize_t show_mic_loopback(struct device *dev,
436                                  struct device_attribute *attr, char *buf)
437 {
438         return sprintf(buf, "%i\n", aic23_info_l.mic_loopback);
439 }
440
441 static DEVICE_ATTR(mic_loopback, S_IRUGO | S_IWUSR,
442                    show_mic_loopback, store_mic_loopback);
443
444 static ssize_t store_st_attenuation(struct device *dev,
445                                     struct device_attribute *attr,
446                                     const char *buf, size_t count)
447 {
448         unsigned sta;
449         u16 tmp;
450
451         sscanf(buf, "%u", &sta);
452         if (sta > 3)
453                 sta = 3;
454
455         tmp = aic23_info_l.mask;
456         tmp &= 0x3f;
457
458         aic23_info_l.mask =  tmp | STA_REG(sta);
459         aic23_write_value(ANALOG_AUDIO_CONTROL_ADDR,
460                                 aic23_info_l.mask);
461         aic23_info_l.sta = sta;
462
463         return count;
464 }
465
466 static ssize_t show_st_attenuation(struct device *dev,
467                                    struct device_attribute *attr, char *buf)
468 {
469         return sprintf(buf, "%i\n", aic23_info_l.sta);
470 }
471
472 static DEVICE_ATTR(st_attenuation, S_IRUGO | S_IWUSR,
473                    show_st_attenuation, store_st_attenuation);
474
475 static ssize_t store_mic_enable(struct device *dev,
476                                 struct device_attribute *attr,
477                                 const char *buf, size_t count)
478 {
479         int mic;
480
481         sscanf(buf, "%i", &mic);
482         set_mic(mic);
483
484         return count;
485 }
486
487 static ssize_t show_mic_enable(struct device *dev,
488                                struct device_attribute *attr, char *buf)
489 {
490         return sprintf(buf, "%i\n", aic23_info_l.mic_enable);
491 }
492
493 static DEVICE_ATTR(mic_enable, S_IRUGO | S_IWUSR,
494         show_mic_enable, store_mic_enable);
495
496 static ssize_t show_audio_selftest(struct device *dev,
497                                    struct device_attribute *attr, char *buf)
498 {
499         return sprintf(buf, "%i\n", selftest);
500 }
501
502 static DEVICE_ATTR(audio_selftest, S_IRUGO | S_IWUSR,
503                 show_audio_selftest, NULL);
504
505 static int audio_i2c_probe(struct platform_device *dev)
506 {
507         int r;
508
509         if ((r = device_create_file(&dev->dev, &dev_attr_volume_left)) != 0)
510                 return r;
511         else if ((r = device_create_file(&dev->dev,
512                 &dev_attr_volume_right)) != 0)
513                 goto err_volume_left;
514         else if ((r = device_create_file(&dev->dev,
515                 &dev_attr_gain_right)) != 0)
516                 goto err_volume_right;
517         else if ((r = device_create_file(&dev->dev,
518                 &dev_attr_gain_left)) != 0)
519                 goto err_gain_right;
520         else if ((r = device_create_file(&dev->dev,
521                 &dev_attr_mic_loopback)) != 0)
522                 goto err_gain_left;
523         else if ((r = device_create_file(&dev->dev,
524                 &dev_attr_mic_enable)) != 0)
525                 goto err_mic_loopback;
526         else if ((r = device_create_file(&dev->dev,
527                 &dev_attr_st_attenuation)) != 0)
528                 goto err_mic_enable;
529         else if ((r = device_create_file(&dev->dev,
530                 &dev_attr_audio_selftest)) != 0)
531                 goto err_st_attenuation;
532         else
533                 return r;
534
535 err_st_attenuation:
536         device_remove_file(&dev->dev, &dev_attr_st_attenuation);
537 err_mic_enable:
538         device_remove_file(&dev->dev, &dev_attr_mic_enable);
539 err_mic_loopback:
540         device_remove_file(&dev->dev, &dev_attr_mic_loopback);
541 err_gain_left:
542         device_remove_file(&dev->dev, &dev_attr_gain_left);
543 err_gain_right:
544         device_remove_file(&dev->dev, &dev_attr_gain_right);
545 err_volume_right:
546         device_remove_file(&dev->dev, &dev_attr_volume_right);
547 err_volume_left:
548         device_remove_file(&dev->dev, &dev_attr_volume_left);
549
550         return r;
551 }
552
553 static int audio_i2c_remove(struct platform_device *dev)
554 {
555         device_remove_file(&dev->dev, &dev_attr_st_attenuation);
556         device_remove_file(&dev->dev, &dev_attr_mic_enable);
557         device_remove_file(&dev->dev, &dev_attr_mic_loopback);
558         device_remove_file(&dev->dev, &dev_attr_gain_left);
559         device_remove_file(&dev->dev, &dev_attr_gain_right);
560         device_remove_file(&dev->dev, &dev_attr_volume_right);
561         device_remove_file(&dev->dev, &dev_attr_volume_left);
562
563         return 0;
564 }
565
566 /*----------------------------------------------------------------*/
567 /*                      PM functions                              */
568 /*----------------------------------------------------------------*/
569
570 static void audio_i2c_shutdown(struct platform_device *dev)
571 {
572         /* Let's mute the codec before powering off to prevent
573         * glitch in the sound
574         */
575         aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
576         aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
577         aic23_power_down();
578 }
579
580 static int audio_i2c_suspend(struct platform_device *dev, pm_message_t state)
581 {
582         /* Let's mute the codec before powering off to prevent
583          * glitch in the sound
584          */
585         aic23_write_value(LEFT_CHANNEL_VOLUME_ADDR, LHV_MIN);
586         aic23_write_value(RIGHT_CHANNEL_VOLUME_ADDR, LHV_MIN);
587         aic23_power_down();
588
589         return 0;
590 }
591
592 static int audio_i2c_resume(struct platform_device *dev)
593 {
594         aic23_power_up();
595
596         return 0;
597 }
598
599 static struct platform_driver audio_i2c_driver = {
600         .driver = {
601                 .owner  = THIS_MODULE,
602                 .name   = "audio-i2c",
603         },
604         .shutdown       = audio_i2c_shutdown,
605         .probe          = audio_i2c_probe,
606         .remove         = audio_i2c_remove,
607         .suspend        = audio_i2c_suspend,
608         .resume         = audio_i2c_resume,
609 };
610
611 static struct platform_device audio_i2c_device = {
612         .name           = "audio-i2c",
613         .id             = -1,
614 };
615
616 /*----------------------------------------------------------------*/
617
618 static int __init aic23_init(void)
619 {
620         selftest =  0;
621         aic23_info_l.initialized = 0;
622
623         if (i2c_add_driver(&aic23_driver)) {
624                 printk("aic23 i2c: Driver registration failed, \
625                       module not inserted.\n");
626                 selftest = -ENODEV;
627                 return selftest;
628         }
629
630         if (platform_driver_register(&audio_i2c_driver)) {
631                 printk(KERN_WARNING "Failed to register audio i2c driver\n");
632                 selftest = -ENODEV;
633                 return selftest;
634         }
635
636         if (platform_device_register(&audio_i2c_device)) {
637                 printk(KERN_WARNING "Failed to register audio i2c device\n");
638                 platform_driver_unregister(&audio_i2c_driver);
639                 selftest = -ENODEV;
640                 return selftest;
641         }
642         /* FIXME: Do in board-specific file */
643         omap_mcbsp3_aic23_clock_init();
644         if (!aic23_info_l.power_down)
645                 aic23_power_up();
646         aic23_info_l.initialized = 1;
647         printk("TLV320AIC23 I2C version %s (%s)\n",
648                TLV320AIC23_VERSION, TLV320AIC23_DATE);
649
650         return selftest;
651 }
652
653 static void __exit aic23_exit(void)
654 {
655         int res;
656
657         aic23_power_down();
658         if ((res = i2c_del_driver(&aic23_driver)))
659                 printk("aic23 i2c: Driver remove failed, module not removed.\n");
660
661         platform_device_unregister(&audio_i2c_device);
662         platform_driver_unregister(&audio_i2c_driver);
663 }
664
665 MODULE_AUTHOR("Kai Svahn <kai.svahn@nokia.com>");
666 MODULE_DESCRIPTION("I2C interface for TLV320AIC23 codec.");
667 MODULE_LICENSE("GPL");
668
669 module_init(aic23_init)
670 module_exit(aic23_exit)
671
672 EXPORT_SYMBOL(aic23_write_value);
673 EXPORT_SYMBOL(aic23_power_up);
674 EXPORT_SYMBOL(aic23_power_down);