ASoC: rt286: Add RL6347A class device shared support for RT286
authorOder Chiou <oder_chiou@realtek.com>
Fri, 12 Jun 2015 09:06:29 +0000 (17:06 +0800)
committerMark Brown <broonie@kernel.org>
Fri, 12 Jun 2015 10:18:53 +0000 (11:18 +0100)
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>
sound/soc/codecs/Kconfig
sound/soc/codecs/Makefile
sound/soc/codecs/rl6347a.c [new file with mode: 0644]
sound/soc/codecs/rl6347a.h [new file with mode: 0644]
sound/soc/codecs/rt286.c

index 061c465..b826c71 100644 (file)
@@ -507,6 +507,11 @@ config SND_SOC_RL6231
        default m if SND_SOC_RT5670=m
        default m if SND_SOC_RT5677=m
 
+config SND_SOC_RL6347A
+       tristate
+       default y if SND_SOC_RT286=y
+       default m if SND_SOC_RT286=m
+
 config SND_SOC_RT286
        tristate
        depends on I2C
index abe2d7e..15bba4e 100644 (file)
@@ -77,6 +77,7 @@ snd-soc-pcm512x-objs := pcm512x.o
 snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
 snd-soc-pcm512x-spi-objs := pcm512x-spi.o
 snd-soc-rl6231-objs := rl6231.o
+snd-soc-rl6347a-objs := rl6347a.o
 snd-soc-rt286-objs := rt286.o
 snd-soc-rt5631-objs := rt5631.o
 snd-soc-rt5640-objs := rt5640.o
@@ -262,6 +263,7 @@ obj-$(CONFIG_SND_SOC_PCM512x)       += snd-soc-pcm512x.o
 obj-$(CONFIG_SND_SOC_PCM512x_I2C)      += snd-soc-pcm512x-i2c.o
 obj-$(CONFIG_SND_SOC_PCM512x_SPI)      += snd-soc-pcm512x-spi.o
 obj-$(CONFIG_SND_SOC_RL6231)   += snd-soc-rl6231.o
+obj-$(CONFIG_SND_SOC_RL6347A)  += snd-soc-rl6347a.o
 obj-$(CONFIG_SND_SOC_RT286)    += snd-soc-rt286.o
 obj-$(CONFIG_SND_SOC_RT5631)   += snd-soc-rt5631.o
 obj-$(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 (file)
index 0000000..91d5166
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * rl6347a.c - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/dmi.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/initval.h>
+#include <sound/tlv.h>
+#include <sound/jack.h>
+#include <linux/workqueue.h>
+#include <sound/hda_verbs.h>
+
+#include "rl6347a.h"
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value)
+{
+       struct i2c_client *client = context;
+       struct rl6347a_priv *rl6347a = i2c_get_clientdata(client);
+       u8 data[4];
+       int ret, i;
+
+       /* handle index registers */
+       if (reg <= 0xff) {
+               rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+               for (i = 0; i < rl6347a->index_cache_size; i++) {
+                       if (reg == rl6347a->index_cache[i].reg) {
+                               rl6347a->index_cache[i].def = value;
+                               break;
+                       }
+
+               }
+               reg = RL6347A_PROC_COEF;
+       }
+
+       data[0] = (reg >> 24) & 0xff;
+       data[1] = (reg >> 16) & 0xff;
+       /*
+        * 4 bit VID: reg should be 0
+        * 12 bit VID: value should be 0
+        * So we use an OR operator to handle it rather than use if condition.
+        */
+       data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
+       data[3] = value & 0xff;
+
+       ret = i2c_master_send(client, data, 4);
+
+       if (ret == 4)
+               return 0;
+       else
+               pr_err("ret=%d\n", ret);
+       if (ret < 0)
+               return ret;
+       else
+               return -EIO;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_write);
+
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value)
+{
+       struct i2c_client *client = context;
+       struct i2c_msg xfer[2];
+       int ret;
+       __be32 be_reg;
+       unsigned int index, vid, buf = 0x0;
+
+       /* handle index registers */
+       if (reg <= 0xff) {
+               rl6347a_hw_write(client, RL6347A_COEF_INDEX, reg);
+               reg = RL6347A_PROC_COEF;
+       }
+
+       reg = reg | 0x80000;
+       vid = (reg >> 8) & 0xfff;
+
+       if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
+               index = (reg >> 8) & 0xf;
+               reg = (reg & ~0xf0f) | index;
+       }
+       be_reg = cpu_to_be32(reg);
+
+       /* Write register */
+       xfer[0].addr = client->addr;
+       xfer[0].flags = 0;
+       xfer[0].len = 4;
+       xfer[0].buf = (u8 *)&be_reg;
+
+       /* Read data */
+       xfer[1].addr = client->addr;
+       xfer[1].flags = I2C_M_RD;
+       xfer[1].len = 4;
+       xfer[1].buf = (u8 *)&buf;
+
+       ret = i2c_transfer(client->adapter, xfer, 2);
+       if (ret < 0)
+               return ret;
+       else if (ret != 2)
+               return -EIO;
+
+       *value = be32_to_cpu(buf);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rl6347a_hw_read);
+
+MODULE_DESCRIPTION("RL6347A class device shared support");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rl6347a.h b/sound/soc/codecs/rl6347a.h
new file mode 100644 (file)
index 0000000..1cb56e5
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * rl6347a.h - RL6347A class device shared support
+ *
+ * Copyright 2015 Realtek Semiconductor Corp.
+ *
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __RL6347A_H__
+#define __RL6347A_H__
+
+#define VERB_CMD(V, N, D) ((N << 20) | (V << 8) | D)
+
+#define RL6347A_VENDOR_REGISTERS       0x20
+
+#define RL6347A_COEF_INDEX\
+       VERB_CMD(AC_VERB_SET_COEF_INDEX, RL6347A_VENDOR_REGISTERS, 0)
+#define RL6347A_PROC_COEF\
+       VERB_CMD(AC_VERB_SET_PROC_COEF, RL6347A_VENDOR_REGISTERS, 0)
+
+struct rl6347a_priv {
+       struct reg_default *index_cache;
+       int index_cache_size;
+};
+
+int rl6347a_hw_write(void *context, unsigned int reg, unsigned int value);
+int rl6347a_hw_read(void *context, unsigned int reg, unsigned int *value);
+
+#endif /* __RL6347A_H__ */
index 0fcda35..d5be4f9 100644 (file)
 #include <sound/rt286.h>
 #include <sound/hda_verbs.h>
 
+#include "rl6347a.h"
 #include "rt286.h"
 
 #define RT286_VENDOR_ID 0x10ec0286
 #define RT288_VENDOR_ID 0x10ec0288
 
 struct rt286_priv {
+       struct reg_default *index_cache;
+       int index_cache_size;
        struct regmap *regmap;
        struct snd_soc_codec *codec;
        struct rt286_platform_data pdata;
@@ -45,7 +48,6 @@ struct rt286_priv {
        struct delayed_work jack_detect_work;
        int sys_clk;
        int clk_id;
-       struct reg_default *index_cache;
 };
 
 static struct reg_default rt286_index_def[] = {
@@ -185,94 +187,6 @@ static bool rt286_readable_register(struct device *dev, unsigned int reg)
        }
 }
 
-static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
-{
-       struct i2c_client *client = context;
-       struct rt286_priv *rt286 = i2c_get_clientdata(client);
-       u8 data[4];
-       int ret, i;
-
-       /* handle index registers */
-       if (reg <= 0xff) {
-               rt286_hw_write(client, RT286_COEF_INDEX, reg);
-               for (i = 0; i < INDEX_CACHE_SIZE; i++) {
-                       if (reg == rt286->index_cache[i].reg) {
-                               rt286->index_cache[i].def = value;
-                               break;
-                       }
-
-               }
-               reg = RT286_PROC_COEF;
-       }
-
-       data[0] = (reg >> 24) & 0xff;
-       data[1] = (reg >> 16) & 0xff;
-       /*
-        * 4 bit VID: reg should be 0
-        * 12 bit VID: value should be 0
-        * So we use an OR operator to handle it rather than use if condition.
-        */
-       data[2] = ((reg >> 8) & 0xff) | ((value >> 8) & 0xff);
-       data[3] = value & 0xff;
-
-       ret = i2c_master_send(client, data, 4);
-
-       if (ret == 4)
-               return 0;
-       else
-               pr_err("ret=%d\n", ret);
-       if (ret < 0)
-               return ret;
-       else
-               return -EIO;
-}
-
-static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
-{
-       struct i2c_client *client = context;
-       struct i2c_msg xfer[2];
-       int ret;
-       __be32 be_reg;
-       unsigned int index, vid, buf = 0x0;
-
-       /* handle index registers */
-       if (reg <= 0xff) {
-               rt286_hw_write(client, RT286_COEF_INDEX, reg);
-               reg = RT286_PROC_COEF;
-       }
-
-       reg = reg | 0x80000;
-       vid = (reg >> 8) & 0xfff;
-
-       if (AC_VERB_GET_AMP_GAIN_MUTE == (vid & 0xf00)) {
-               index = (reg >> 8) & 0xf;
-               reg = (reg & ~0xf0f) | index;
-       }
-       be_reg = cpu_to_be32(reg);
-
-       /* Write register */
-       xfer[0].addr = client->addr;
-       xfer[0].flags = 0;
-       xfer[0].len = 4;
-       xfer[0].buf = (u8 *)&be_reg;
-
-       /* Read data */
-       xfer[1].addr = client->addr;
-       xfer[1].flags = I2C_M_RD;
-       xfer[1].len = 4;
-       xfer[1].buf = (u8 *)&buf;
-
-       ret = i2c_transfer(client->adapter, xfer, 2);
-       if (ret < 0)
-               return ret;
-       else if (ret != 2)
-               return -EIO;
-
-       *value = be32_to_cpu(buf);
-
-       return 0;
-}
-
 #ifdef CONFIG_PM
 static void rt286_index_sync(struct snd_soc_codec *codec)
 {
@@ -1173,8 +1087,8 @@ static const struct regmap_config rt286_regmap = {
        .max_register = 0x02370100,
        .volatile_reg = rt286_volatile_register,
        .readable_reg = rt286_readable_register,
-       .reg_write = rt286_hw_write,
-       .reg_read = rt286_hw_read,
+       .reg_write = rl6347a_hw_write,
+       .reg_read = rl6347a_hw_read,
        .cache_type = REGCACHE_RBTREE,
        .reg_defaults = rt286_reg,
        .num_reg_defaults = ARRAY_SIZE(rt286_reg),
@@ -1247,6 +1161,7 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
        }
 
        rt286->index_cache = rt286_index_def;
+       rt286->index_cache_size = INDEX_CACHE_SIZE;
        rt286->i2c = i2c;
        i2c_set_clientdata(i2c, rt286);