ASoC: codecs: add support for rk3328
[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 #define MODEM_ON 1
31 #define MODEM_OFF 0
32
33 static struct i2c_client *i2c_client;
34 static int status;
35
36 static int codec_write(struct i2c_client *client, unsigned int reg,
37                               unsigned int value)
38 {
39         u8 data[3];
40
41         data[0] = reg;
42         data[1] = (value >> 8) & 0xff;
43         data[2] = value & 0xff;
44
45         //printk("%s: reg=0x%x value=0x%x\n",__func__,reg,value);
46         if (i2c_master_send(client, data, 3) == 3)
47                 return 0;
48         else
49                 return -EIO;
50 }
51
52 static unsigned int codec_read(struct i2c_client *client,
53                                           unsigned int r)
54 {
55         struct i2c_msg xfer[2];
56         u8 reg = r;
57         u16 data;
58         int ret;
59
60         /* Write register */
61         xfer[0].addr = client->addr;
62         xfer[0].flags = 0;
63         xfer[0].len = 1;
64         xfer[0].buf = &reg;
65         xfer[0].scl_rate = 100 * 1000;
66
67         /* Read data */
68         xfer[1].addr = client->addr;
69         xfer[1].flags = I2C_M_RD;
70         xfer[1].len = 2;
71         xfer[1].buf = (u8 *)&data;
72         xfer[1].scl_rate = 100 * 1000;
73
74         ret = i2c_transfer(client->adapter, xfer, 2);
75         if (ret != 2) {
76                 dev_err(&client->dev, "i2c_transfer() returned %d\n", ret);
77                 return 0;
78         }
79         //printk("%s: reg=0x%x value=0x%x\n",__func__,reg,(data >> 8) | ((data & 0xff) << 8));
80
81         return (data >> 8) | ((data & 0xff) << 8);
82 }
83
84 struct rt5623_reg {
85         u8 reg_index;
86         u16 reg_value;
87 };
88
89 static struct rt5623_reg init_data[] = {
90         {RT5623_PWR_MANAG_ADD3                  , 0x8000},
91         {RT5623_PWR_MANAG_ADD2                  , 0x2000},
92         {RT5623_LINE_IN_VOL                     , 0xa808},
93         {RT5623_STEREO_DAC_VOL                  , 0x6808},
94         {RT5623_OUTPUT_MIXER_CTRL               , 0x1400},
95         {RT5623_ADC_REC_GAIN                    , 0xf58b},
96         {RT5623_ADC_REC_MIXER                   , 0x7d7d},
97         {RT5623_AUDIO_INTERFACE                 , 0x8083},
98         {RT5623_STEREO_AD_DA_CLK_CTRL           , 0x0a2d},
99         {RT5623_PWR_MANAG_ADD1                  , 0x8000},
100         {RT5623_PWR_MANAG_ADD2                  , 0xb7f3},
101         {RT5623_PWR_MANAG_ADD3                  , 0x90c0},
102         {RT5623_SPK_OUT_VOL                     , 0x0000},
103         {RT5623_PLL_CTRL                        , 0x481f},
104         {RT5623_GLOBAL_CLK_CTRL_REG             , 0x8000},
105         {RT5623_STEREO_AD_DA_CLK_CTRL           , 0x3a2d},
106 };
107 #define RT5623_INIT_REG_NUM ARRAY_SIZE(init_data)
108
109 static int rt5623_reg_init(struct i2c_client *client)
110 {
111         int i;
112
113         for (i = 0; i < RT5623_INIT_REG_NUM; i++)
114                 codec_write(client, init_data[i].reg_index,
115                                 init_data[i].reg_value);
116
117         return 0;
118 }
119
120 static int rt5623_reset(struct i2c_client *client)
121 {
122         return codec_write(client, RT5623_RESET, 0);
123 }
124
125 void rt5623_on(void)
126 {
127         if(status == MODEM_OFF) 
128         {
129                 printk("enter %s\n",__func__);
130                 rt5623_reset(i2c_client);
131                 rt5623_reg_init(i2c_client);
132                 status = MODEM_ON;
133         }
134 }
135 EXPORT_SYMBOL(rt5623_on);
136
137 void rt5623_off(void)
138 {
139         if(status == MODEM_ON)  
140         {
141                 printk("enter %s\n",__func__);
142                 codec_write(i2c_client, RT5623_SPK_OUT_VOL, 0x8080);
143                 rt5623_reset(i2c_client);
144                 codec_write(i2c_client, RT5623_PWR_MANAG_ADD3, 0x0000);
145                 codec_write(i2c_client, RT5623_PWR_MANAG_ADD2, 0x0000);
146                 codec_write(i2c_client, RT5623_PWR_MANAG_ADD1, 0x0000);
147                 status = MODEM_OFF;
148         }
149 }
150 EXPORT_SYMBOL(rt5623_off);
151
152 static const struct i2c_device_id rt5623_i2c_id[] = {
153         { "rt5623", 0 },
154         { }
155 };
156 MODULE_DEVICE_TABLE(i2c, rt5623_i2c_id);
157
158
159 static int rt5623_i2c_probe(struct i2c_client *i2c,
160                     const struct i2c_device_id *id)
161 {
162         pr_info("%s(%d)\n", __func__, __LINE__);
163
164         i2c_client = i2c;
165         rt5623_reset(i2c);
166         status = MODEM_ON;
167         rt5623_off( );
168         return 0;
169 }
170
171 static int rt5623_i2c_remove(struct i2c_client *i2c)
172 {
173         return 0;
174 }
175
176 struct i2c_driver rt5623_i2c_driver = {
177         .driver = {
178                 .name = "rt5623",
179                 .owner = THIS_MODULE,
180         },
181         .probe = rt5623_i2c_probe,
182         .remove   = rt5623_i2c_remove,
183         .id_table = rt5623_i2c_id,
184 };
185
186 static int __init rt5623_modinit(void)
187 {
188         return i2c_add_driver(&rt5623_i2c_driver);
189 }
190 late_initcall(rt5623_modinit);
191
192 static void __exit rt5623_modexit(void)
193 {
194         i2c_del_driver(&rt5623_i2c_driver);
195 }
196 module_exit(rt5623_modexit);
197
198 MODULE_DESCRIPTION("ASoC RT5623 driver");
199 MODULE_AUTHOR("Johnny Hsu <johnnyhsu@realtek.com>");
200 MODULE_LICENSE("GPL");
201
202
203
204
205
206