aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOder Chiou <oder_chiou@realtek.com>2015-06-12 05:06:29 -0400
committerMark Brown <broonie@kernel.org>2015-06-12 06:18:53 -0400
commitbc08f96b5fa783132c278d7a48a1c18feca5813f (patch)
treef01b8608a3e62caef1d157dc86768d56286932f0
parentb787f68c36d49bb1d9236f403813641efa74a031 (diff)
ASoC: rt286: Add RL6347A class device shared support for RT286
The patch separates the IO function from the rt286. It is prepared to share for new chips that support the same IO function. Signed-off-by: Oder Chiou <oder_chiou@realtek.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--sound/soc/codecs/Kconfig5
-rw-r--r--sound/soc/codecs/Makefile2
-rw-r--r--sound/soc/codecs/rl6347a.c128
-rw-r--r--sound/soc/codecs/rl6347a.h32
-rw-r--r--sound/soc/codecs/rt286.c97
5 files changed, 173 insertions, 91 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 061c46587628..b826c716506c 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -507,6 +507,11 @@ config SND_SOC_RL6231
507 default m if SND_SOC_RT5670=m 507 default m if SND_SOC_RT5670=m
508 default m if SND_SOC_RT5677=m 508 default m if SND_SOC_RT5677=m
509 509
510config SND_SOC_RL6347A
511 tristate
512 default y if SND_SOC_RT286=y
513 default m if SND_SOC_RT286=m
514
510config SND_SOC_RT286 515config SND_SOC_RT286
511 tristate 516 tristate
512 depends on I2C 517 depends on I2C
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index abe2d7edf65c..15bba4ee2dfe 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -77,6 +77,7 @@ snd-soc-pcm512x-objs := pcm512x.o
77snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o 77snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
78snd-soc-pcm512x-spi-objs := pcm512x-spi.o 78snd-soc-pcm512x-spi-objs := pcm512x-spi.o
79snd-soc-rl6231-objs := rl6231.o 79snd-soc-rl6231-objs := rl6231.o
80snd-soc-rl6347a-objs := rl6347a.o
80snd-soc-rt286-objs := rt286.o 81snd-soc-rt286-objs := rt286.o
81snd-soc-rt5631-objs := rt5631.o 82snd-soc-rt5631-objs := rt5631.o
82snd-soc-rt5640-objs := rt5640.o 83snd-soc-rt5640-objs := rt5640.o
@@ -262,6 +263,7 @@ obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o
262obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o 263obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o
263obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o 264obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o
264obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o 265obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
266obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
265obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o 267obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o
266obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o 268obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o
267obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o 269obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o
diff --git a/sound/soc/codecs/rl6347a.c b/sound/soc/codecs/rl6347a.c
new file mode 100644
index 000000000000..91d5166bd3a1
--- /dev/null
+++ b/sound/soc/codecs/rl6347a.c
@@ -0,0 +1,128 @@
1/*
2 * rl6347a.c - RL6347A class device shared support
3 *
4 * Copyright 2015 Realtek Semiconductor Corp.
5 *
6 * Author: Oder Chiou <oder_chiou@realtek.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15#include <linux/init.h>
16#include <linux/delay.h>
17#include <linux/pm.h>
18#include <linux/i2c.h>
19#include <linux/platform_device.h>
20#include <linux/spi/spi.h>
21#include <linux/dmi.h>
22#include <linux/acpi.h>
23#include <sound/core.h>
24#include <sound/pcm.h>
25#include <sound/pcm_params.h>
26#include <sound/soc.h>
27#include <sound/soc-dapm.h>
28#include <sound/initval.h>
29#include <sound/tlv.h>
30#include <sound/jack.h>
31#include <linux/workqueue.h>
32#include <sound/hda_verbs.h>
33
34#include "rl6347a.h"
35
36int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
37{
38 struct i2c_client *client = context;
39 struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
40 u8 data[4];
41 int ret, i;
42
43 /* handle index registers */
44 if (reg <= 0xff) {
45 rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
46 for (i = 0; i < rl6347a->index_cache_size; i++) {
47 if (reg == rl6347a->index_cache[i].reg) {
48 rl6347a->index_cache[i].def = value;
49 break;
50 }
51
52 }
53 reg = RL6347A_PROC_COEF;
54 }
55
56 data[0] = (reg >> 24) & 0xff;
57 data[1] = (reg >> 16) & 0xff;
58 /*
59 * 4 bit VID: reg should be 0
60 * 12 bit VID: value should be 0
61 * So we use an OR operator to handle it rather than use if condition.
62 */
63 data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
64 data[3] = value & 0xff;
65
66 ret = i2c_master_send(client, data, 4);
67
68 if (ret == 4)
69 return 0;
70 else
71 pr_err("ret=%d\n", ret);
72 if (ret < 0)
73 return ret;
74 else
75 return -EIO;
76}
77EXPORT_SYMBOL_GPL(rl6347a_hw_write);
78
79int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
80{
81 struct i2c_client *client = context;
82 struct i2c_msg xfer[2];
83 int ret;
84 __be32 be_reg;
85 unsigned int index, vid, buf = 0x0;
86
87 /* handle index registers */
88 if (reg <= 0xff) {
89 rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
90 reg = RL6347A_PROC_COEF;
91 }
92
93 reg = reg | 0x80000;
94 vid = (reg >> 8) & 0xfff;
95
96 if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
97 index = (reg >> 8) & 0xf;
98 reg = (reg & ~0xf0f) | index;
99 }
100 be_reg = cpu_to_be32(reg);
101
102 /* Write register */
103 xfer[0].addr = client->addr;
104 xfer[0].flags = 0;
105 xfer[0].len = 4;
106 xfer[0].buf = (u8 *)&be_reg;
107
108 /* Read data */
109 xfer[1].addr = client->addr;
110 xfer[1].flags = I2C_M_RD;
111 xfer[1].len = 4;
112 xfer[1].buf = (u8 *)&buf;
113
114 ret = i2c_transfer(client->adapter, xfer, 2);
115 if (ret < 0)
116 return ret;
117 else if (ret != 2)
118 return -EIO;
119
120 *value = be32_to_cpu(buf);
121
122 return 0;
123}
124EXPORT_SYMBOL_GPL(rl6347a_hw_read);
125
126MODULE_DESCRIPTION("RL6347A class device shared support");
127MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
128MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6347a.h b/sound/soc/codecs/rl6347a.h
new file mode 100644
index 000000000000..1cb56e50b7f3
--- /dev/null
+++ b/sound/soc/codecs/rl6347a.h
@@ -0,0 +1,32 @@
1/*
2 * rl6347a.h - RL6347A class device shared support
3 *
4 * Copyright 2015 Realtek Semiconductor Corp.
5 *
6 * Author: Oder Chiou <oder_chiou@realtek.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12#ifndef __RL6347A_H__
13#define __RL6347A_H__
14
15#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
16
17#define RL6347A_VENDOR_REGISTERS 0x20
18
19#define RL6347A_COEF_INDEX\
20 VERB_CMD(AC_VERB_SET_COEF_INDEX, RL6347A_VENDOR_REGISTERS, 0)
21#define RL6347A_PROC_COEF\
22 VERB_CMD(AC_VERB_SET_PROC_COEF, RL6347A_VENDOR_REGISTERS, 0)
23
24struct rl6347a_priv {
25 struct reg_default *index_cache;
26 int index_cache_size;
27};
28
29int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value);
30int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value);
31
32#endif /* __RL6347A_H__ */
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 0fcda35a3a93..d5be4f9a5781 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -31,12 +31,15 @@
31#include <sound/rt286.h> 31#include <sound/rt286.h>
32#include <sound/hda_verbs.h> 32#include <sound/hda_verbs.h>
33 33
34#include "rl6347a.h"
34#include "rt286.h" 35#include "rt286.h"
35 36
36#define RT286_VENDOR_ID 0x10ec0286 37#define RT286_VENDOR_ID 0x10ec0286
37#define RT288_VENDOR_ID 0x10ec0288 38#define RT288_VENDOR_ID 0x10ec0288
38 39
39struct rt286_priv { 40struct rt286_priv {
41 struct reg_default *index_cache;
42 int index_cache_size;
40 struct regmap *regmap; 43 struct regmap *regmap;
41 struct snd_soc_codec *codec; 44 struct snd_soc_codec *codec;
42 struct rt286_platform_data pdata; 45 struct rt286_platform_data pdata;
@@ -45,7 +48,6 @@ struct rt286_priv {
45 struct delayed_work jack_detect_work; 48 struct delayed_work jack_detect_work;
46 int sys_clk; 49 int sys_clk;
47 int clk_id; 50 int clk_id;
48 struct reg_default *index_cache;
49}; 51};
50 52
51static struct reg_default rt286_index_def[] = { 53static struct reg_default rt286_index_def[] = {
@@ -185,94 +187,6 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg)
185 } 187 }
186} 188}
187 189
188static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
189{
190 struct i2c_client *client = context;
191 struct rt286_priv *rt286 = i2c_get_clientdata(client);
192 u8 data[4];
193 int ret, i;
194
195 /* handle index registers */
196 if (reg <= 0xff) {
197 rt286_hw_write(client, RT286_COEF_INDEX, reg);
198 for (i = 0; i < INDEX_CACHE_SIZE; i++) {
199 if (reg == rt286->index_cache[i].reg) {
200 rt286->index_cache[i].def = value;
201 break;
202 }
203
204 }
205 reg = RT286_PROC_COEF;
206 }
207
208 data[0] = (reg >> 24) & 0xff;
209 data[1] = (reg >> 16) & 0xff;
210 /*
211 * 4 bit VID: reg should be 0
212 * 12 bit VID: value should be 0
213 * So we use an OR operator to handle it rather than use if condition.
214 */
215 data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
216 data[3] = value & 0xff;
217
218 ret = i2c_master_send(client, data, 4);
219
220 if (ret == 4)
221 return 0;
222 else
223 pr_err("ret=%d\n", ret);
224 if (ret < 0)
225 return ret;
226 else
227 return -EIO;
228}
229
230static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
231{
232 struct i2c_client *client = context;
233 struct i2c_msg xfer[2];
234 int ret;
235 __be32 be_reg;
236 unsigned int index, vid, buf = 0x0;
237
238 /* handle index registers */
239 if (reg <= 0xff) {
240 rt286_hw_write(client, RT286_COEF_INDEX, reg);
241 reg = RT286_PROC_COEF;
242 }
243
244 reg = reg | 0x80000;
245 vid = (reg >> 8) & 0xfff;
246
247 if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
248 index = (reg >> 8) & 0xf;
249 reg = (reg & ~0xf0f) | index;
250 }
251 be_reg = cpu_to_be32(reg);
252
253 /* Write register */
254 xfer[0].addr = client->addr;
255 xfer[0].flags = 0;
256 xfer[0].len = 4;
257 xfer[0].buf = (u8 *)&be_reg;
258
259 /* Read data */
260 xfer[1].addr = client->addr;
261 xfer[1].flags = I2C_M_RD;
262 xfer[1].len = 4;
263 xfer[1].buf = (u8 *)&buf;
264
265 ret = i2c_transfer(client->adapter, xfer, 2);
266 if (ret < 0)
267 return ret;
268 else if (ret != 2)
269 return -EIO;
270
271 *value = be32_to_cpu(buf);
272
273 return 0;
274}
275
276#ifdef CONFIG_PM 190#ifdef CONFIG_PM
277static void rt286_index_sync(struct snd_soc_codec *codec) 191static void rt286_index_sync(struct snd_soc_codec *codec)
278{ 192{
@@ -1173,8 +1087,8 @@ static const struct regmap_config rt286_regmap = {
1173 .max_register = 0x02370100, 1087 .max_register = 0x02370100,
1174 .volatile_reg = rt286_volatile_register, 1088 .volatile_reg = rt286_volatile_register,
1175 .readable_reg = rt286_readable_register, 1089 .readable_reg = rt286_readable_register,
1176 .reg_write = rt286_hw_write, 1090 .reg_write = rl6347a_hw_write,
1177 .reg_read = rt286_hw_read, 1091 .reg_read = rl6347a_hw_read,
1178 .cache_type = REGCACHE_RBTREE, 1092 .cache_type = REGCACHE_RBTREE,
1179 .reg_defaults = rt286_reg, 1093 .reg_defaults = rt286_reg,
1180 .num_reg_defaults = ARRAY_SIZE(rt286_reg), 1094 .num_reg_defaults = ARRAY_SIZE(rt286_reg),
@@ -1247,6 +1161,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
1247 } 1161 }
1248 1162
1249 rt286->index_cache = rt286_index_def; 1163 rt286->index_cache = rt286_index_def;
1164 rt286->index_cache_size = INDEX_CACHE_SIZE;
1250 rt286->i2c = i2c; 1165 rt286->i2c = i2c;
1251 i2c_set_clientdata(i2c, rt286); 1166 i2c_set_clientdata(i2c, rt286);
1252 1167