rt3261: add first version, playback is ok.
[firefly-linux-kernel-4.4.55.git] / sound / soc / codecs / rt5623.c
1 /*
2  * rt5623.c  --  RT5623 ALSA SoC audio codec driver
3  *
4  * Copyright 2011 Realtek Semiconductor Corp.
5  * Author: Johnny Hsu <johnnyhsu@realtek.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 version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/module.h>
13 #include <linux/moduleparam.h>
14 #include <linux/init.h>
15 #include <linux/delay.h>
16 #include <linux/pm.h>
17 #include <linux/i2c.h>
18 #include <linux/platform_device.h>
19 #include <linux/spi/spi.h>
20 #include <sound/core.h>
21 #include <sound/pcm.h>
22 #include <sound/pcm_params.h>
23 #include <sound/soc.h>
24 #include <sound/soc-dapm.h>
25 #include <sound/initval.h>
26 #include <sound/tlv.h>
27
28 #include "rt5623.h"
29
30 static struct i2c_client *i2c_client;
31
32 static int codec_write(struct i2c_client *client, unsigned int reg,
33                               unsigned int value)
34 {
35         u8 data[3];
36         int ret;
37
38         data[0] = reg;
39         data[1] = (value >> 8) & 0xff;
40         data[2] = value & 0xff;
41
42         //printk("%s: reg=0x%x value=0x%x\n",__func__,reg,value);
43         if (i2c_master_send(client, data, 3) == 3)
44                 return 0;
45         else
46                 return -EIO;
47 }
48
49 static unsigned int codec_read(struct i2c_client *client,
50                                           unsigned int r)
51 {
52         struct i2c_msg xfer[2];
53         u8 reg = r;
54         u16 data;
55         int ret;
56
57         /* Write register */
58         xfer[0].addr = client->addr;
59         xfer[0].flags = 0;
60         xfer[0].len = 1;
61         xfer[0].buf = &reg;
62
63         /* Read data */
64         xfer[1].addr = client->addr;
65         xfer[1].flags = I2C_M_RD;
66         xfer[1].len = 2;
67         xfer[1].buf = (u8 *)&data;
68
69         ret = i2c_transfer(client->adapter, xfer, 2);
70         if (ret != 2) {
71                 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
72                 return 0;
73         }
74         //printk("%s: reg=0x%x value=0x%x\n",__func__,reg,(data >> 8) | ((data & 0xff) << 8));
75
76         return (data >> 8) | ((data & 0xff) << 8);
77 }
78
79 struct rt5623_reg {
80         u8 reg_index;
81         u16 reg_value;
82 };
83
84 static struct rt5623_reg init_data[] = {
85         {RT5623_PWR_MANAG_ADD3          , 0x8000},
86         {RT5623_PWR_MANAG_ADD2          , 0x2000},
87         {RT5623_LINE_IN_VOL             , 0xe808},
88         {RT5623_STEREO_DAC_VOL          , 0x6808},
89         {RT5623_OUTPUT_MIXER_CTRL       , 0x1400},
90         {RT5623_ADC_REC_GAIN            , 0xf58b},
91         {RT5623_ADC_REC_MIXER           , 0x6f6f},
92         {RT5623_AUDIO_INTERFACE         , 0x8000},
93         {RT5623_STEREO_AD_DA_CLK_CTRL   , 0x0a2d},
94         {RT5623_PWR_MANAG_ADD1          , 0x8000},
95         {RT5623_PWR_MANAG_ADD2          , 0x27f3},
96         {RT5623_PWR_MANAG_ADD3          , 0x9c00},
97         {RT5623_SPK_OUT_VOL             , 0x0000},
98 };
99 #define RT5623_INIT_REG_NUM ARRAY_SIZE(init_data)
100
101 static int rt5623_reg_init(struct i2c_client *client)
102 {
103         int i;
104
105         for (i = 0; i < RT5623_INIT_REG_NUM; i++)
106                 codec_write(client, init_data[i].reg_index,
107                                 init_data[i].reg_value);
108
109         return 0;
110 }
111
112 static int rt5623_reset(struct i2c_client *client)
113 {
114         return codec_write(client, RT5623_RESET, 0);
115 }
116
117 void rt5623_on(void)
118 {
119         printk("enter %s\n",__func__);
120         rt5623_reset(i2c_client);
121         rt5623_reg_init(i2c_client);
122 }
123 EXPORT_SYMBOL(rt5623_on);
124
125 void rt5623_off(void)
126 {
127         printk("enter %s\n",__func__);
128         codec_write(i2c_client, RT5623_SPK_OUT_VOL, 0x8080);
129         rt5623_reset(i2c_client);
130         codec_write(i2c_client, RT5623_PWR_MANAG_ADD3, 0x0000);
131         codec_write(i2c_client, RT5623_PWR_MANAG_ADD2, 0x0000);
132         codec_write(i2c_client, RT5623_PWR_MANAG_ADD1, 0x0000);
133 }
134 EXPORT_SYMBOL(rt5623_off);
135
136 static const struct i2c_device_id rt5623_i2c_id[] = {
137         { "rt5623", 0 },
138         { }
139 };
140 MODULE_DEVICE_TABLE(i2c, rt5623_i2c_id);
141
142 static int __devinit rt5623_i2c_probe(struct i2c_client *i2c,
143                     const struct i2c_device_id *id)
144 {
145         pr_info("%s(%d)\n", __func__, __LINE__);
146
147         i2c_client = i2c;
148         rt5623_reset(i2c);
149
150         rt5623_on( );
151
152         return 0;
153 }
154
155 static int __devexit rt5623_i2c_remove(struct i2c_client *i2c)
156 {
157         return 0;
158 }
159
160 struct i2c_driver rt5623_i2c_driver = {
161         .driver = {
162                 .name = "rt5623",
163                 .owner = THIS_MODULE,
164         },
165         .probe = rt5623_i2c_probe,
166         .remove   = __devexit_p(rt5623_i2c_remove),
167         .id_table = rt5623_i2c_id,
168 };
169
170 static int __init rt5623_modinit(void)
171 {
172         return i2c_add_driver(&rt5623_i2c_driver);
173 }
174 module_init(rt5623_modinit);
175
176 static void __exit rt5623_modexit(void)
177 {
178         i2c_del_driver(&rt5623_i2c_driver);
179 }
180 module_exit(rt5623_modexit);
181
182 MODULE_DESCRIPTION("ASoC RT5623 driver");
183 MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
184 MODULE_LICENSE("GPL");