diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk1000-codec.txt b/Documentation/devicetree/bindings/sound/rockchip,rk1000-codec.txt
new file mode 100644
index 000000000000..529749c8fed2
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk1000-codec.txt
@@ -0,0 +1,20 @@
+* Rockchip RK1000 codec
+
+Required properties:
+
+- compatible: "rockchip,rk1000-codec"
+- reg : the I2C address of the device.
+- rockchip,spk-en-gpio: the enable gpio of spk.
+- rockchip,pa-en-time-ms: pa enable dealy time(ms).
+- rockchip,ctl: phandle to the rk1000 core controller.
+
+Example for rk1000 codec:
+
+rk1000_codec: rk1000-codec@60 {
+ compatible = "rockchip,rk1000_codec";
+ reg = <0x60>;
+ rockchip,spk-en-gpio = <&gpio3 31 GPIO_ACTIVE_LOW>;
+ rockchip,pa-en-time-ms = <5000>;
+ rockchip,ctl = <&rk1000_ctl>;
+ status = "okay";
+};
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 73396e2acace..3792cf494451 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -91,6 +91,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_PCM3008
select SND_SOC_PCM512x_I2C if I2C
select SND_SOC_PCM512x_SPI if SPI_MASTER
+ select SND_SOC_RK1000 if I2C
select SND_SOC_RK3328
select SND_SOC_RT286 if I2C
select SND_SOC_RT298 if I2C
@@ -549,6 +550,10 @@ config SND_SOC_PCM512x_SPI
select SND_SOC_PCM512x
select REGMAP_SPI
+config SND_SOC_RK1000
+ tristate "Rockchip RK1000 CODEC"
+ depends on MFD_RK1000
+
config SND_SOC_RK3328
select REGMAP_MMIO
tristate "Rockchip RK3328 CODEC"
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 313eca65fb42..aff1c31eab05 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -86,6 +86,7 @@ snd-soc-pcm3008-objs := pcm3008.o
snd-soc-pcm512x-objs := pcm512x.o
snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o
snd-soc-pcm512x-spi-objs := pcm512x-spi.o
+snd-soc-rk1000-objs := rk1000_codec.o
snd-soc-rk3328-objs := rk3328_codec.o
snd-soc-rl6231-objs := rl6231.o
snd-soc-rl6347a-objs := rl6347a.o
@@ -289,6 +290,7 @@ obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o
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_RK1000) += snd-soc-rk1000.o
obj-$(CONFIG_SND_SOC_RK3328) += snd-soc-rk3328.o
obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o
obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o
diff --git a/sound/soc/codecs/rk1000_codec.c b/sound/soc/codecs/rk1000_codec.c
old mode 100755
new mode 100644
index 8237ec0b8630..06aaa617969b
--- a/sound/soc/codecs/rk1000_codec.c
+++ b/sound/soc/codecs/rk1000_codec.c
@@ -1,448 +1,131 @@
/*
- * rk1000.c -- RK1000 ALSA SoC audio driver
+ * rk1000_codec.c -- rk1000 ALSA Soc Audio driver
*
- * Copyright (C) 2009 rockchip lhh
+ * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd All rights reserved.
*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
*
- * Based on RK1000.c
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
*
- * 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
-#include
-#include
-#include
-#include
#include
-#include
+#include
#include
-#include
+#include
#include
#include
#include
#include
#include
-#include
-#include
-#include
#include "rk1000_codec.h"
-
-/*
- * Debug
- */
-#define RK1000_CODEC_DBG 0
-#if RK1000_CODEC_DBG
-#define DBG(x...) pr_info(x)
-#else
-#define DBG(x...)
-#endif
-
-/*rk1000 codec proc debug*/
-#define RK1000_CODEC_PROC 1
-
-#define HP_OUT 0
-#define HP_IN 1
-#define USE_MIC_IN
-#define USE_LPF
-
-#define FREQ441KHZ (0x11 << 1)
-/* rk1000 output volume,DAC Digital Gain */
+#define FREQ441KHZ (0x11 << 1)
+/* rk1000 output volume, DAC Digital Gain */
/* 0x0000 ~ 0xF42 */
-#define VOLUME_OUTPUT 0xF42
-/* 0x0 ~ 0x3f(bit0-bit5) max=0x0(+6DB) min=0x3f(-60DB) Analog Gain */
-#define VOLUME_CODEC_PA 0x0
+#define VOLUME_OUTPUT 0xF42
+/* 0x0 ~ 0x3f(bit0-bit5) max=0x0(+6DB) min=0x3f(-60DB) Analog Gain */
+#define VOLUME_CODEC_PA 0x0
-/* rk1000 input volume,rk610 can not adjust the recording volume */
-#define VOLUME_INPUT 0x07
+/* rk1000 input volume, rk610 can not adjust the recording volume */
+#define VOLUME_INPUT 0x07
-#define OUT_CAPLESS (1)
+#define OUT_CAPLESS (1)
-/* 1:set pll from rk1000 */
-#define RK1000_CTL_PLL 0
-
-static u8 g_r0_a_reg;
-static u8 g_r0_b_reg;
-
-/*
- * rk1000 register cache
- * We can't read the RK1000 register space when we
- * are using 2 wire for device control, so we cache them instead.
- */
-static const u16 rk1000_codec_reg[] = {
- 0x0005, 0x0004, 0x00fd, 0x00f3, /* 0 */
- 0x0003, 0x0000, 0x0000, 0x0000, /* 4 */
- 0x0000, 0x0005, 0x0000, 0x0000, /* 8 */
- 0x0097, 0x0097, 0x0097, 0x0097, /* 0x0a */
- 0x0097, 0x0097, 0x00cc, 0x0000, /* 0x10 */
- 0x0000, 0x00f1, 0x0090, 0x00ff, /* 0x14 */
- 0x00ff, 0x00ff, 0x009c, 0x0000, /* 0x18 */
- 0x0000, 0x00ff, 0x00ff, 0x00ff, /* 0x1a */
+static const struct reg_default rk1000_codec_reg[] = {
+ { 0x00, 0x05 },
+ { 0x01, 0x04 },
+ { 0x02, 0xfd },
+ { 0x03, 0xf3 },
+ { 0x04, 0x03 },
+ { 0x05, 0x00 },
+ { 0x06, 0x00 },
+ { 0x07, 0x00 },
+ { 0x08, 0x00 },
+ { 0x09, 0x05 },
+ { 0x0a, 0x00 },
+ { 0x0b, 0x00 },
+ { 0x0c, 0x97 },
+ { 0x0d, 0x97 },
+ { 0x0e, 0x97 },
+ { 0x0f, 0x97 },
+ { 0x10, 0x97 },
+ { 0x11, 0x97 },
+ { 0x12, 0xcc },
+ { 0x13, 0x00 },
+ { 0x14, 0x00 },
+ { 0x15, 0xf1 },
+ { 0x16, 0x90 },
+ { 0x17, 0xff },
+ { 0x18, 0xff },
+ { 0x19, 0xff },
+ { 0x1a, 0x9c },
+ { 0x1b, 0x00 },
+ { 0x1c, 0x00 },
+ { 0x1d, 0xff },
+ { 0x1e, 0xff },
+ { 0x1f, 0xff },
};
-static struct snd_soc_codec *rk1000_codec_codec;
-/* codec private data */
struct rk1000_codec_priv {
- enum snd_soc_control_type control_type;
- unsigned int sysclk;
- struct snd_soc_codec codec;
- struct snd_pcm_hw_constraint_list *sysclk_constraints;
- u16 reg_cache[RK1000_CODEC_NUM_REG];
-
- struct delayed_work rk1000_delayed_work;
- unsigned int spk_ctrl_io;
- enum of_gpio_flags flags;
+ struct regmap *regmap;
+ struct regmap *ctlmap;
+ struct snd_soc_codec *codec;
+ struct delayed_work pa_delayed_work;
+ struct gpio_desc *spk_en_gpio;
/*
- Some amplifiers enable a longer time.
- config after pa_enable_io delay pa_enable_time(ms)
- so value range is 0 - 8000.
- */
+ * Some amplifiers enable a longer time.
+ * config after pa_enable_io delay pa_enable_time(ms)
+ * so value range is 0 - 8000.
+ */
unsigned int pa_enable_time;
- /* if found boot pop,set boot_depop 1 test */
- int boot_depop;
- int call_enable;
- int headset_status;
};
-
-static void spk_ctrl_fun(int status)
+static void spk_ctrl_fun(struct snd_soc_codec *codec, int status)
{
struct rk1000_codec_priv *rk1000_codec;
- if (rk1000_codec_codec == NULL)
- return;
- rk1000_codec = snd_soc_codec_get_drvdata(rk1000_codec_codec);
- if (rk1000_codec == NULL)
- return;
- if (!rk1000_codec->spk_ctrl_io)
- return;
- DBG("%s:: spk status = %d\n", __func__, status);
- if (status)
- gpio_set_value(rk1000_codec->spk_ctrl_io,
- rk1000_codec->flags);
- else
- gpio_set_value(rk1000_codec->spk_ctrl_io,
- !rk1000_codec->flags);
+ rk1000_codec = snd_soc_codec_get_drvdata(codec);
+
+ if (rk1000_codec->spk_en_gpio)
+ gpiod_set_value(rk1000_codec->spk_en_gpio, status);
}
-
-/*
- * read rk1000 register cache
- */
-static unsigned int rk1000_codec_read_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
-
- if (reg > RK1000_CACHE_REGNUM)
- return -1;
- return cache[reg];
-}
-
-static unsigned int rk1000_codec_read(struct snd_soc_codec *codec,
- unsigned int r)
-{
- struct i2c_msg xfer[1];
- int reg;
- int ret;
- struct i2c_client *i2c;
-
- reg = r;
- i2c = to_i2c_client(codec->dev);
- /* Read register */
- xfer[0].addr = (i2c->addr & 0x60) | (reg);
- xfer[0].flags = I2C_M_RD;
- xfer[0].len = 1;
- xfer[0].buf = (unsigned char *)®
- xfer[0].scl_rate = 100000;
- ret = i2c_transfer(i2c->adapter, xfer, 1);
- if (ret != 1) {
- dev_err(&i2c->dev, "i2c_transfer() returned %d\n", ret);
- return 0;
- }
- return reg;
-}
-
-/*
- * write rk1000 register cache
- */
-static inline void rk1000_codec_write_reg_cache(struct snd_soc_codec *codec,
- unsigned int reg,
- unsigned int value)
-{
- u16 *cache;
-
- cache = codec->reg_cache;
- if (reg > RK1000_CACHE_REGNUM)
- return;
- cache[reg] = value;
-}
-
-static int rk1000_codec_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int value)
-{
-#ifdef CONFIG_MODEM_SOUND
- struct rk1000_codec_priv *rk1000_codec;
-#endif
- u8 data[2];
- struct i2c_client *i2c;
-
- i2c = to_i2c_client(codec->dev);
-#ifdef CONFIG_MODEM_SOUND
- rk1000_codec = snd_soc_codec_get_drvdata(rk1000_codec_codec);
- if (rk1000_codec->call_enable)
- return 0;
-#endif
- DBG("Enter::%s, %d, reg=0x%02X, value=0x%02X\n", __func__,
- __LINE__, reg, value);
- data[0] = value & 0x00ff;
- i2c->addr = (i2c->addr & 0x60)|reg;
- if (codec->hw_write(i2c, data, 1) == 1) {
- DBG("====%s %d Run OK=======\n", __func__, __LINE__);
- rk1000_codec_write_reg_cache(codec, reg, value);
- return 0;
- } else {
- DBG("====%s %d Run EIO=====\n", __func__, __LINE__);
- return -EIO;
- }
-}
-
-#ifdef CONFIG_MODEM_SOUND
-static int rk1000_codec_write_incall(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- u8 data[2];
- struct i2c_client *i2c;
-
- DBG("Enter::%s, %d, reg=0x%02X, value=0x%02X\n",
- __func__, __LINE__, reg, value);
- i2c = to_i2c_client(codec->dev);
- data[0] = value & 0x00ff;
- rk1000_codec_write_reg_cache(codec, reg, value);
- i2c = (struct i2c_client *)codec->control_data;
- i2c->addr = (i2c->addr & 0x60) | reg;
- if (codec->hw_write(i2c, data, 1) == 1)
- return 0;
- else
- return -EIO;
-}
-
-void call_set_spk(int on)
-{
- struct rk1000_codec_priv *rk1000_codec;
-
- if (!rk1000_codec_codec)
- return;
- rk1000_codec = snd_soc_codec_get_drvdata(rk1000codec_codec);
- if (!rk1000_codec)
- return;
-
- switch (on) {
- case 0:
- /* modem exit call,codec disable loopback */
- DBG("%s modem exit call\n", __func__);
- rk1000_codec_write_incall(rk1000_codec_codec,
- ACCELCODEC_R0E, 0x80);
- rk1000_codec->call_enable = 0;
- break;
- case 1:
- /* modem calling,codec enable loopback,
- * spk hp different volume */
- DBG("%s spk incalling\n", __func__);
- rk1000_codec->call_enable = 1;
- rk1000_codec_write_incall(rk1000_codec_codec,
- ACCELCODEC_R0E, 0x00);
- return;
- case 2:
- DBG("%s hp incalling\n", __func__);
- rk1000_codec->call_enable = 1;
- rk1000_codec_write_incall(rk1000_codec_codec,
- ACCELCODEC_R0E, 0x00);
- break;
- case 3:
- DBG("%s bt incalling\n", __func__);
- rk1000_codec->call_enable = 1;
- rk1000_codec_write_incall(rk1000_codec_codec,
- ACCELCODEC_R0E, 0x00);
- break;
- }
-}
-#endif
-
-
-
-struct _coeff_div {
- u32 mclk;
- u32 rate;
- u16 fs;
- u8 sr:5;
- u8 usb:1;
- u8 bclk;
-};
-
-/* codec hifi mclk clock divider coefficients */
-static const struct _coeff_div coeff_div[] = {
- /* 8k */
- {12288000, 8000, 1536, 0x6, 0x0, ASC_BCLKDIV_16},
- {11289600, 8000, 1408, 0x16, 0x0, ASC_BCLKDIV_16},
- {18432000, 8000, 2304, 0x7, 0x0, ASC_BCLKDIV_16},
- {16934400, 8000, 2112, 0x17, 0x0, ASC_BCLKDIV_16},
- {8192000, 8000, 1024, 0x0, 0x0, ASC_BCLKDIV_16},
- {12000000, 8000, 1500, 0x6, 0x1, ASC_BCLKDIV_16},
- /* 11.025k */
- {11289600, 11025, 1024, 0x18, 0x0, ASC_BCLKDIV_16},
- {16934400, 11025, 1536, 0x19, 0x0, ASC_BCLKDIV_16},
- {12000000, 11025, 1088, 0x19, 0x1, ASC_BCLKDIV_16},
- /* 12k */
- {12288000, 12000, 1024, 0x8, 0x0, ASC_BCLKDIV_16},
- {18432000, 12000, 1536, 0x9, 0x0, ASC_BCLKDIV_16},
- {12000000, 12000, 1000, 0x8, 0x1, ASC_BCLKDIV_16},
- /* 16k */
- {12288000, 16000, 768, 0xa, 0x0, ASC_BCLKDIV_8},
- {18432000, 16000, 1152, 0xb, 0x0, ASC_BCLKDIV_8},
- {12000000, 16000, 750, 0xa, 0x1, ASC_BCLKDIV_8},
- /* 22.05k */
- {11289600, 22050, 512, 0x1a, 0x0, ASC_BCLKDIV_8},
- {16934400, 22050, 768, 0x1b, 0x0, ASC_BCLKDIV_8},
- {12000000, 22050, 544, 0x1b, 0x1, ASC_BCLKDIV_8},
- /* 24k */
- {12288000, 24000, 512, 0x1c, 0x0, ASC_BCLKDIV_8},
- {18432000, 24000, 768, 0x1d, 0x0, ASC_BCLKDIV_8},
- {12000000, 24000, 500, 0x1c, 0x1, ASC_BCLKDIV_8},
- /* 32k */
- {12288000, 32000, 384, 0xc, 0x0, ASC_BCLKDIV_8},
- {18432000, 32000, 576, 0xd, 0x0, ASC_BCLKDIV_8},
- {12000000, 32000, 375, 0xa, 0x1, ASC_BCLKDIV_8},
- /* 44.1k */
- {11289600, 44100, 256, 0x10, 0x0, ASC_BCLKDIV_4},
- {16934400, 44100, 384, 0x11, 0x0, ASC_BCLKDIV_8},
- {12000000, 44100, 272, 0x11, 0x1, ASC_BCLKDIV_8},
- /* 48k */
- {12288000, 48000, 256, 0x0, 0x0, ASC_BCLKDIV_4},
- {18432000, 48000, 384, 0x1, 0x0, ASC_BCLKDIV_4},
- {12000000, 48000, 250, 0x0, 0x1, ASC_BCLKDIV_4},
- /* 88.2k */
- {11289600, 88200, 128, 0x1e, 0x0, ASC_BCLKDIV_4},
- {16934400, 88200, 192, 0x1f, 0x0, ASC_BCLKDIV_4},
- {12000000, 88200, 136, 0x1f, 0x1, ASC_BCLKDIV_4},
- /* 96k */
- {12288000, 96000, 128, 0xe, 0x0, ASC_BCLKDIV_4},
- {18432000, 96000, 192, 0xf, 0x0, ASC_BCLKDIV_4},
- {12000000, 96000, 125, 0xe, 0x1, ASC_BCLKDIV_4},
-};
-
-static inline int get_coeff(int mclk, int rate)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(coeff_div); i++) {
- if (coeff_div[i].rate == rate && coeff_div[i].mclk == mclk)
- return i;
- }
- return -EINVAL;
-}
-
-/* The set of rates we can generate from the above for each SYSCLK */
-
-static unsigned int rates_12288[] = {
- 8000, 12000, 16000, 24000, 24000, 32000, 48000, 96000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_12288 = {
- .count = ARRAY_SIZE(rates_12288),
- .list = rates_12288,
-};
-
-static unsigned int rates_112896[] = {
- 8000, 11025, 22050, 44100,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_112896 = {
- .count = ARRAY_SIZE(rates_112896),
- .list = rates_112896,
-};
-
-static unsigned int rates_12[] = {
- 8000, 11025, 12000, 16000, 22050, 2400, 32000, 41100, 48000,
- 48000, 88235, 96000,
-};
-
-static struct snd_pcm_hw_constraint_list constraints_12 = {
- .count = ARRAY_SIZE(rates_12),
- .list = rates_12,
-};
-
static int rk1000_codec_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
- DBG("Enter::%s----%d now_level =%d old_level = %d\n",
- __func__, __LINE__, level, codec->dapm.bias_level);
switch (level) {
case SND_SOC_BIAS_ON:
break;
+
case SND_SOC_BIAS_PREPARE:
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40);
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0x49);
- /*VREF, VMID=2x50k, digital enabled */
+ snd_soc_write(codec, ACCELCODEC_R1D, 0x2a);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0x40);
+ snd_soc_write(codec, ACCELCODEC_R1F, 0x49);
break;
case SND_SOC_BIAS_STANDBY:
- DBG("rk1000 standby\n");
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40);
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0x49);
+ snd_soc_write(codec, ACCELCODEC_R1D, 0x2a);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0x40);
+ snd_soc_write(codec, ACCELCODEC_R1F, 0x49);
break;
case SND_SOC_BIAS_OFF:
- DBG("rk1000 power off\n");
- spk_ctrl_fun(GPIO_LOW);
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0xFF);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0xFF);
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0xFF);
+ spk_ctrl_fun(codec, GPIO_LOW);
+ snd_soc_write(codec, ACCELCODEC_R1D, 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R1F, 0xFF);
break;
}
- codec->dapm.bias_level = level;
return 0;
}
-/*
- * Note that this should be called from init rather than from hw_params.
- */
-static int rk1000_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
- int clk_id, unsigned int freq, int dir)
-{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct rk1000_codec_priv *rk1000_codec;
-
- DBG("Enter::%s----%d\n", __func__, __LINE__);
- rk1000_codec = snd_soc_codec_get_drvdata(codec);
- switch (freq) {
- case 11289600:
- case 18432000:
- case 22579200:
- case 36864000:
- rk1000_codec->sysclk_constraints = &constraints_112896;
- rk1000_codec->sysclk = freq;
- return 0;
-
- case 12288000:
- case 16934400:
- case 24576000:
- case 33868800:
- rk1000_codec->sysclk_constraints = &constraints_12288;
- rk1000_codec->sysclk = freq;
- return 0;
-
- case 12000000:
- case 24000000:
- rk1000_codec->sysclk_constraints = &constraints_12;
- rk1000_codec->sysclk = freq;
- return 0;
- }
- return -EINVAL;
-}
static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
@@ -453,16 +136,18 @@ static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
rk1000_codec = snd_soc_codec_get_drvdata(codec);
/* setup Vmid and Vref, other module power down */
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40);
+ snd_soc_write(codec, ACCELCODEC_R1D, 0x2a);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0x40);
/* set master/slave audio interface */
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
iface = 0x0040;
break;
+
case SND_SOC_DAIFMT_CBS_CFS:
iface = 0x0000;
break;
+
default:
return -EINVAL;
}
@@ -471,145 +156,135 @@ static int rk1000_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
case SND_SOC_DAIFMT_I2S:
iface |= 0x0002;
break;
+
case SND_SOC_DAIFMT_RIGHT_J:
break;
+
case SND_SOC_DAIFMT_LEFT_J:
iface |= 0x0001;
break;
+
case SND_SOC_DAIFMT_DSP_A:
iface |= 0x0003;
break;
+
case SND_SOC_DAIFMT_DSP_B:
iface |= 0x0013;
break;
+
default:
return -EINVAL;
}
+
/* clock inversion */
switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
case SND_SOC_DAIFMT_NB_NF:
break;
+
case SND_SOC_DAIFMT_IB_IF:
iface |= 0x0090;
break;
+
case SND_SOC_DAIFMT_IB_NF:
iface |= 0x0080;
break;
+
case SND_SOC_DAIFMT_NB_IF:
iface |= 0x0010;
break;
+
default:
return -EINVAL;
}
- DBG("Enter::%s----%d iface=%x\n", __func__, __LINE__, iface);
- rk1000_codec_write(codec, ACCELCODEC_R09, iface);
+
+ snd_soc_write(codec, ACCELCODEC_R09, iface);
return 0;
}
-
-
static int rk1000_codec_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
u16 iface;
- int coeff;
- struct snd_soc_pcm_runtime *rtd;
- struct snd_soc_codec *codec;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->codec;
unsigned int dai_fmt;
- rtd = substream->private_data;
- codec = rtd->codec;
dai_fmt = rtd->card->dai_link[0].dai_fmt;
- iface = rk1000_codec_read_reg_cache(codec, ACCELCODEC_R09) & 0x1f3;
- coeff = 0;
- rk1000_codec_write(codec, ACCELCODEC_R0C, 0x17);
- rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_MUTE_L|ASC_INT_MUTE_R|
- ASC_SIDETONE_L_OFF|ASC_SIDETONE_R_OFF);
- rk1000_codec_write(codec, ACCELCODEC_R0B,
- ASC_DEC_DISABLE|ASC_INT_DISABLE);
- /* set iface & srate */
+ iface = snd_soc_read(codec, ACCELCODEC_R09) & 0x1f3;
+ snd_soc_write(codec, ACCELCODEC_R0C, 0x17);
+ snd_soc_write(codec, ACCELCODEC_R04,
+ ASC_INT_MUTE_L | ASC_INT_MUTE_R |
+ ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF);
+ snd_soc_write(codec, ACCELCODEC_R0B,
+ ASC_DEC_DISABLE | ASC_INT_DISABLE);
+
if ((dai_fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM)
iface |= ASC_INVERT_BCLK;
- rk1000_codec_write(codec, ACCELCODEC_R09, iface);
- if (coeff >= 0)
- rk1000_codec_write(codec, ACCELCODEC_R0A, 0xa0);
- rk1000_codec_write(codec, ACCELCODEC_R0B, g_r0_b_reg);
+ snd_soc_write(codec, ACCELCODEC_R09, iface);
+ snd_soc_write(codec, ACCELCODEC_R0A, 0xa0);
+ snd_soc_write(codec, ACCELCODEC_R0B, ASC_DEC_ENABLE | ASC_INT_ENABLE);
return 0;
}
-
-
static int rk1000_codec_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
struct rk1000_codec_priv *rk1000_codec;
- DBG("Enter::%s----%d--mute=%d\n", __func__, __LINE__, mute);
rk1000_codec = snd_soc_codec_get_drvdata(codec);
if (mute) {
/* AOL */
- rk1000_codec_write(codec, ACCELCODEC_R17, 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R17, 0xFF);
/* AOR */
- rk1000_codec_write(codec, ACCELCODEC_R18, 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R18, 0xFF);
/* AOM */
- rk1000_codec_write(codec, ACCELCODEC_R19, 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R19, 0xFF);
/* soft mute */
- rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_MUTE_L|
- ASC_INT_MUTE_R | ASC_SIDETONE_L_OFF |
- ASC_SIDETONE_R_OFF);
+ snd_soc_write(codec, ACCELCODEC_R04,
+ ASC_INT_MUTE_L | ASC_INT_MUTE_R |
+ ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF);
} else {
/* setup Vmid and Vref, other module power down */
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0x2a);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40);
+ snd_soc_write(codec, ACCELCODEC_R1D, 0x2a);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0x40);
/* AOL */
- rk1000_codec_write(codec, ACCELCODEC_R17, VOLUME_CODEC_PA |
- ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
+ snd_soc_write(codec, ACCELCODEC_R17,
+ VOLUME_CODEC_PA | ASC_OUTPUT_ACTIVE |
+ ASC_CROSSZERO_EN);
/* AOR */
- rk1000_codec_write(codec, ACCELCODEC_R18, VOLUME_CODEC_PA |
- ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
- rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_ACTIVE_L|
- ASC_INT_ACTIVE_R | ASC_SIDETONE_L_OFF|
- ASC_SIDETONE_R_OFF);
+ snd_soc_write(codec, ACCELCODEC_R18,
+ VOLUME_CODEC_PA | ASC_OUTPUT_ACTIVE |
+ ASC_CROSSZERO_EN);
+ snd_soc_write(codec, ACCELCODEC_R04,
+ ASC_INT_ACTIVE_L | ASC_INT_ACTIVE_R |
+ ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF);
/* AOM */
- rk1000_codec_write(codec, ACCELCODEC_R19, 0x7F);
+ snd_soc_write(codec, ACCELCODEC_R19, 0x7F);
#if OUT_CAPLESS
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09|
- ASC_PDMIXM_ENABLE);
+ snd_soc_write(codec, ACCELCODEC_R1F,
+ 0x09 | ASC_PDMIXM_ENABLE);
#else
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09|
- ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE);
+ snd_soc_write(codec, ACCELCODEC_R1F,
+ 0x09 | ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE);
#endif
}
return 0;
}
-static void rk1000_delayedwork_fun(struct work_struct *work)
+static void pa_delayedwork(struct work_struct *work)
{
- struct snd_soc_codec *codec;
- struct rk1000_codec_priv *rk1000_codec;
+ struct rk1000_codec_priv *priv = container_of(work,
+ struct rk1000_codec_priv,
+ pa_delayed_work.work);
+ struct snd_soc_codec *codec = priv->codec;
- DBG("--------%s----------\n", __func__);
- codec = rk1000_codec_codec;
- rk1000_codec = snd_soc_codec_get_drvdata(codec);
- if (!rk1000_codec->boot_depop) {
- #if OUT_CAPLESS
- rk1000_codec_write(codec, ACCELCODEC_R1F,
- 0x09 | ASC_PDMIXM_ENABLE);
- #else
- rk1000_codec_write(codec, ACCELCODEC_R1F,
- 0x09 | ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE);
- #endif
- }
- spk_ctrl_fun(GPIO_HIGH);
+ spk_ctrl_fun(codec, GPIO_HIGH);
}
-
-
static struct snd_soc_dai_ops rk1000_codec_ops = {
.hw_params = rk1000_codec_pcm_hw_params,
.set_fmt = rk1000_codec_set_dai_fmt,
- .set_sysclk = rk1000_codec_set_dai_sysclk,
.digital_mute = rk1000_codec_mute,
};
@@ -622,14 +297,14 @@ static struct snd_soc_dai_driver rk1000_codec_dai[] = {
.name = "rk1000_codec",
.playback = {
.stream_name = "Playback",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 8,
.rates = RK1000_CODEC_RATES,
.formats = RK1000_CODEC_FORMATS,
},
.capture = {
.stream_name = "Capture",
- .channels_min = 1,
+ .channels_min = 2,
.channels_max = 2,
.rates = RK1000_CODEC_RATES,
.formats = RK1000_CODEC_FORMATS,
@@ -639,105 +314,90 @@ static struct snd_soc_dai_driver rk1000_codec_dai[] = {
}
};
-
-void rk1000_codec_reg_set(void)
+static void rk1000_codec_reg_init(struct snd_soc_codec *codec)
{
- struct snd_soc_codec *codec;
struct rk1000_codec_priv *rk1000_codec;
unsigned int digital_gain;
unsigned int mic_vol;
+ int ret;
mic_vol = VOLUME_INPUT;
- codec = rk1000_codec_codec;
rk1000_codec = snd_soc_codec_get_drvdata(codec);
- rk1000_codec_write(codec, ACCELCODEC_R1D, 0x30);
- rk1000_codec_write(codec, ACCELCODEC_R1E, 0x40);
-#ifdef USE_LPF
+ ret = snd_soc_write(codec, ACCELCODEC_R1D, 0x30);
+ snd_soc_write(codec, ACCELCODEC_R1E, 0x40);
/*Route R-LPF->R-Mixer, L-LPF->L-Mixer*/
- rk1000_codec_write(codec, ACCELCODEC_R15, 0xC1);
-#else
- /*Route RDAC->R-Mixer, LDAC->L->Mixer*/
- rk1000_codec_write(codec, ACCELCODEC_R15, 0x0C);
-#endif
+ snd_soc_write(codec, ACCELCODEC_R15, 0xC1);
/*With Cap Output, VMID ramp up slow*/
- rk1000_codec_write(codec, ACCELCODEC_R1A, 0x14);
+ snd_soc_write(codec, ACCELCODEC_R1A, 0x14);
mdelay(10);
- rk1000_codec_write(codec, ACCELCODEC_R0C, 0x10 | ASC_INPUT_VOL_0DB);
- rk1000_codec_write(codec, ACCELCODEC_R0D, 0x10 | ASC_INPUT_VOL_0DB);
-#ifdef USE_MIC_IN
+ snd_soc_write(codec, ACCELCODEC_R0C, 0x10 | ASC_INPUT_VOL_0DB);
+ snd_soc_write(codec, ACCELCODEC_R0D, 0x10 | ASC_INPUT_VOL_0DB);
if (mic_vol > 0x07) {
/*Select MIC input*/
- rk1000_codec_write(codec, ACCELCODEC_R12,
- 0x4c | ASC_MIC_INPUT | ASC_MIC_BOOST_20DB);
+ snd_soc_write(codec, ACCELCODEC_R12,
+ 0x4c | ASC_MIC_INPUT | ASC_MIC_BOOST_20DB);
mic_vol -= 0x07;
} else
/*Select MIC input*/
- rk1000_codec_write(codec, ACCELCODEC_R12, 0x4c | ASC_MIC_INPUT);
+ snd_soc_write(codec, ACCELCODEC_R12, 0x4c | ASC_MIC_INPUT);
/*use default value*/
- rk1000_codec_write(codec, ACCELCODEC_R1C, ASC_DEM_ENABLE);
-#else
- /*Select Line input*/
- rk1000_codec_write(codec, ACCELCODEC_R12, 0x4c);
-#endif
- rk1000_codec_write(codec, ACCELCODEC_R0E, 0x10|mic_vol);
- /*Diable route PGA->R/L Mixer, PGA gain 0db.*/
- rk1000_codec_write(codec, ACCELCODEC_R13, 0x05 | 0 << 3);
- rk1000_codec_write(codec, ACCELCODEC_R14, 0x05 | 0 << 3);
+ snd_soc_write(codec, ACCELCODEC_R1C, ASC_DEM_ENABLE);
+ snd_soc_write(codec, ACCELCODEC_R0E, 0x10 | mic_vol);
+ /* disable route PGA->R/L Mixer, PGA gain 0db. */
+ snd_soc_write(codec, ACCELCODEC_R13, 0x05 | 0 << 3);
+ snd_soc_write(codec, ACCELCODEC_R14, 0x05 | 0 << 3);
/*2soft mute*/
- rk1000_codec_write(codec, ACCELCODEC_R04,
- ASC_INT_MUTE_L | ASC_INT_MUTE_R |
- ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF);
+ snd_soc_write(codec, ACCELCODEC_R04,
+ ASC_INT_MUTE_L | ASC_INT_MUTE_R |
+ ASC_SIDETONE_L_OFF | ASC_SIDETONE_R_OFF);
/*2set default SR and clk*/
- rk1000_codec_write(codec, ACCELCODEC_R0A, FREQ441KHZ | ASC_NORMAL_MODE |
- (0x10 << 1) | ASC_CLKNODIV | ASC_CLK_ENABLE);
- g_r0_a_reg = ASC_NORMAL_MODE | (0x10 << 1) |
- ASC_CLKNODIV | ASC_CLK_DISABLE;
+ snd_soc_write(codec, ACCELCODEC_R0A, FREQ441KHZ | ASC_NORMAL_MODE |
+ (0x10 << 1) | ASC_CLKNODIV | ASC_CLK_ENABLE);
/*2Config audio interface*/
- rk1000_codec_write(codec, ACCELCODEC_R09, ASC_I2S_MODE |
- ASC_16BIT_MODE | ASC_NORMAL_LRCLK |
- ASC_LRSWAP_DISABLE | ASC_NORMAL_BCLK);
- rk1000_codec_write(codec, ACCELCODEC_R00, ASC_HPF_ENABLE
- | ASC_DSM_MODE_ENABLE | ASC_SCRAMBLE_ENABLE
- | ASC_DITHER_ENABLE | ASC_BCLKDIV_4);
+ snd_soc_write(codec, ACCELCODEC_R09, ASC_I2S_MODE |
+ ASC_16BIT_MODE | ASC_NORMAL_LRCLK |
+ ASC_LRSWAP_DISABLE | ASC_NORMAL_BCLK);
+ snd_soc_write(codec, ACCELCODEC_R00, ASC_HPF_ENABLE |
+ ASC_DSM_MODE_ENABLE | ASC_SCRAMBLE_ENABLE |
+ ASC_DITHER_ENABLE | ASC_BCLKDIV_4);
/*2volume,input,output*/
digital_gain = VOLUME_OUTPUT;
- if (rk1000_codec_read(codec, ACCELCODEC_R05) != 0x0f) {
- rk1000_codec_write(codec, ACCELCODEC_R05,
- (digital_gain >> 8) & 0xFF);
- rk1000_codec_write(codec, ACCELCODEC_R06, digital_gain & 0xFF);
+ if (snd_soc_read(codec, ACCELCODEC_R05) != 0x0f) {
+ snd_soc_write(codec, ACCELCODEC_R05,
+ (digital_gain >> 8) & 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R06, digital_gain & 0xFF);
}
- if (rk1000_codec_read(codec, ACCELCODEC_R07) != 0x0f) {
- rk1000_codec_write(codec, ACCELCODEC_R07,
- (digital_gain >> 8) & 0xFF);
- rk1000_codec_write(codec, ACCELCODEC_R08, digital_gain & 0xFF);
- }
- rk1000_codec_write(codec, ACCELCODEC_R0B,
- ASC_DEC_ENABLE | ASC_INT_ENABLE);
- g_r0_b_reg = ASC_DEC_ENABLE | ASC_INT_ENABLE;
- if (rk1000_codec->boot_depop) {
- #if OUT_CAPLESS
- rk1000_codec_write(codec, ACCELCODEC_R1F,
- 0x09 | ASC_PDMIXM_ENABLE);
- #else
- rk1000_codec_write(codec, ACCELCODEC_R1F, 0x09 |
- ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE);
- #endif
- }
- rk1000_codec_write(codec, ACCELCODEC_R17, VOLUME_CODEC_PA |
- ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
- rk1000_codec_write(codec, ACCELCODEC_R18, VOLUME_CODEC_PA |
- ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
- rk1000_codec_write(codec, ACCELCODEC_R04, ASC_INT_ACTIVE_L |
- ASC_INT_ACTIVE_R | ASC_SIDETONE_L_OFF |
- ASC_SIDETONE_R_OFF);
- rk1000_codec_write(codec, ACCELCODEC_R19, 0x7F);
-}
+ if (snd_soc_read(codec, ACCELCODEC_R07) != 0x0f) {
+ snd_soc_write(codec, ACCELCODEC_R07,
+ (digital_gain >> 8) & 0xFF);
+ snd_soc_write(codec, ACCELCODEC_R08, digital_gain & 0xFF);
+ }
+
+ snd_soc_write(codec, ACCELCODEC_R0B,
+ ASC_DEC_ENABLE | ASC_INT_ENABLE);
+
+ #if OUT_CAPLESS
+ snd_soc_write(codec, ACCELCODEC_R1F,
+ 0x09 | ASC_PDMIXM_ENABLE);
+ #else
+ snd_soc_write(codec, ACCELCODEC_R1F, 0x09 |
+ ASC_PDMIXM_ENABLE | ASC_PDPAM_ENABLE);
+ #endif
+
+ snd_soc_write(codec, ACCELCODEC_R17, VOLUME_CODEC_PA |
+ ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
+ snd_soc_write(codec, ACCELCODEC_R18, VOLUME_CODEC_PA |
+ ASC_OUTPUT_ACTIVE | ASC_CROSSZERO_EN);
+ snd_soc_write(codec, ACCELCODEC_R04, ASC_INT_ACTIVE_L |
+ ASC_INT_ACTIVE_R | ASC_SIDETONE_L_OFF |
+ ASC_SIDETONE_R_OFF);
+ snd_soc_write(codec, ACCELCODEC_R19, 0x7F);
+}
static int rk1000_codec_suspend(struct snd_soc_codec *codec)
{
- DBG("Enter::%s----%d\n", __func__, __LINE__);
- spk_ctrl_fun(GPIO_LOW);
+ spk_ctrl_fun(codec, GPIO_LOW);
rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -745,57 +405,26 @@ static int rk1000_codec_suspend(struct snd_soc_codec *codec)
static int rk1000_codec_resume(struct snd_soc_codec *codec)
{
rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- spk_ctrl_fun(GPIO_HIGH);
+ spk_ctrl_fun(codec, GPIO_HIGH);
return 0;
}
static int rk1000_codec_probe(struct snd_soc_codec *codec)
{
struct rk1000_codec_priv *rk1000_codec;
- int ret;
- rk1000_codec_codec = codec;
rk1000_codec = snd_soc_codec_get_drvdata(codec);
- DBG("[%s] start\n", __func__);
- ret = snd_soc_codec_set_cache_io(codec, 8, 16,
- rk1000_codec->control_type);
- if (ret != 0) {
- dev_err(codec->dev, "Failed to set cache I/O: %d\n", ret);
- return ret;
- }
- /*For RK1000, i2c write&read method is special
- *do not use system default method.*/
- codec->write = rk1000_codec_write;
- codec->read = rk1000_codec_read;
- codec->hw_write = (hw_write_t)i2c_master_send;
- if (rk1000_codec_codec == NULL) {
- dev_err(codec->dev, "Codec device not registered\n");
- return -ENODEV;
- }
- INIT_DELAYED_WORK(&rk1000_codec->rk1000_delayed_work,
- rk1000_delayedwork_fun);
+ rk1000_codec->codec = codec;
+
+ INIT_DELAYED_WORK(&rk1000_codec->pa_delayed_work,
+ pa_delayedwork);
- if (rk1000_codec->spk_ctrl_io) {
- ret = gpio_request(rk1000_codec->spk_ctrl_io,
- "rk1000-spk-ctrl");
- if (ret) {
- DBG("rk1000 codec request gpio fail!\n");
- return ret;
- }
- /*set hight disable codec lr output*/
- gpio_direction_output(rk1000_codec->spk_ctrl_io,
- !rk1000_codec->flags);
- gpio_set_value(rk1000_codec->spk_ctrl_io,
- !rk1000_codec->flags);
- }
- rk1000_codec->call_enable = 0;
- rk1000_codec->headset_status = HP_OUT;
rk1000_codec_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- schedule_delayed_work(&rk1000_codec->rk1000_delayed_work,
+ schedule_delayed_work(&rk1000_codec->pa_delayed_work,
msecs_to_jiffies(rk1000_codec->pa_enable_time));
- rk1000_codec_reg_set();
- DBG("rk1000_codec_probe ret=0x%x\n", ret);
- return ret;
+ rk1000_codec_reg_init(codec);
+
+ return 0;
}
static int rk1000_codec_remove(struct snd_soc_codec *codec)
@@ -805,53 +434,128 @@ static int rk1000_codec_remove(struct snd_soc_codec *codec)
}
static struct snd_soc_codec_driver soc_codec_dev_rk1000_codec = {
- .probe = rk1000_codec_probe,
- .remove = rk1000_codec_remove,
- .suspend = rk1000_codec_suspend,
- .resume = rk1000_codec_resume,
+ .probe = rk1000_codec_probe,
+ .remove = rk1000_codec_remove,
+ .suspend = rk1000_codec_suspend,
+ .resume = rk1000_codec_resume,
.set_bias_level = rk1000_codec_set_bias_level,
- .reg_cache_size = ARRAY_SIZE(rk1000_codec_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = rk1000_codec_reg,
};
+static int rk1000_reg_write(void *context, unsigned int reg,
+ unsigned int value)
+{
+ struct i2c_client *i2c = context;
+ struct i2c_msg msg;
+ u8 buf;
+ int ret;
+
+ buf = value;
+ msg.addr = i2c->addr | reg;
+ msg.flags = i2c->flags & I2C_M_TEN;
+ msg.len = 1;
+ msg.buf = &buf;
+
+ ret = i2c_transfer(i2c->adapter, &msg, 1);
+
+ return (ret == 1) ? 0 : ret;
+}
+
+static int rk1000_reg_read(void *context, unsigned int reg,
+ unsigned int *value)
+{
+ struct i2c_client *i2c = context;
+ struct i2c_msg msg;
+ u8 buf;
+ int ret;
+
+ msg.addr = i2c->addr | reg;
+ msg.flags = I2C_M_RD;
+ msg.len = 1;
+ msg.buf = &buf;
+
+ ret = i2c_transfer(i2c->adapter, &msg, 1);
+ if (ret != 1)
+ return ret;
+
+ *value = buf;
+
+ return 0;
+}
+
+static const struct regmap_config rk1000_codec_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_write = rk1000_reg_write,
+ .reg_read = rk1000_reg_read,
+ .max_register = ACCELCODEC_R1F,
+ .cache_type = REGCACHE_FLAT,
+ .reg_defaults = rk1000_codec_reg,
+ .num_reg_defaults = ARRAY_SIZE(rk1000_codec_reg),
+};
+
+static const struct regmap_config rk1000_ctl_regmap = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = CODEC_CON,
+ .cache_type = REGCACHE_FLAT,
+};
static int rk1000_codec_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
- struct rk1000_codec_priv *rk1000_codec;
- struct device_node *rk1000_np = i2c->dev.of_node;
- int ret;
+ struct rk1000_codec_priv *rk1000;
+ struct device_node *np = i2c->dev.of_node;
+ struct device_node *ctl;
+ struct i2c_client *ctl_client;
- DBG("%s::%d\n", __func__, __LINE__);
- rk1000_codec = kmalloc(sizeof(*rk1000_codec), GFP_KERNEL);
- if (rk1000_codec == NULL)
+ rk1000 = devm_kzalloc(&i2c->dev, sizeof(*rk1000), GFP_KERNEL);
+ if (!rk1000)
return -ENOMEM;
- rk1000_codec->spk_ctrl_io = of_get_named_gpio_flags(rk1000_np,
- "spk_ctl_io", 0, &(rk1000_codec->flags));
- if (!gpio_is_valid(rk1000_codec->spk_ctrl_io)) {
- DBG("invalid core_info->reset_gpio: %d\n",
- rk1000_codec->spk_ctrl_io);
- return -1;
+
+ i2c_set_clientdata(i2c, rk1000);
+
+ of_property_read_u32(np, "rockchip,pa-en-time-ms",
+ &rk1000->pa_enable_time);
+
+ rk1000->spk_en_gpio = devm_gpiod_get_optional(&i2c->dev, "rockchip,spk-en",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(rk1000->spk_en_gpio))
+ return PTR_ERR(rk1000->spk_en_gpio);
+
+ ctl = of_parse_phandle(np, "rockchip,ctl", 0);
+ if (!ctl)
+ return -EINVAL;
+
+ ctl_client = of_find_i2c_device_by_node(ctl);
+ if (!ctl_client) {
+ dev_err(&i2c->dev, "can't find control client\n");
+ return -EPROBE_DEFER;
}
- of_property_read_u32(rk1000_np, "pa_enable_time",
- &(rk1000_codec->pa_enable_time));
- of_property_read_u32(rk1000_np, "boot_depop",
- &(rk1000_codec->boot_depop));
- i2c_set_clientdata(i2c, rk1000_codec);
- rk1000_codec->control_type = SND_SOC_I2C;
- ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rk1000_codec,
- rk1000_codec_dai,
- ARRAY_SIZE(rk1000_codec_dai));
- if (ret < 0)
- kfree(rk1000_codec);
- return ret;
+
+ rk1000->regmap = devm_regmap_init(&i2c->dev, NULL,
+ i2c, &rk1000_codec_regmap);
+ if (IS_ERR(rk1000->regmap))
+ return PTR_ERR(rk1000->regmap);
+
+ rk1000->ctlmap = devm_regmap_init_i2c(ctl_client,
+ &rk1000_ctl_regmap);
+ if (IS_ERR(rk1000->ctlmap))
+ return PTR_ERR(rk1000->ctlmap);
+
+ regmap_write(rk1000->ctlmap, CODEC_CON, CODEC_ON);
+
+ return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rk1000_codec,
+ rk1000_codec_dai,
+ ARRAY_SIZE(rk1000_codec_dai));
}
-static int rk1000_codec_i2c_remove(struct i2c_client *client)
+static int rk1000_codec_i2c_remove(struct i2c_client *i2c)
{
- snd_soc_unregister_codec(&client->dev);
- kfree(i2c_get_clientdata(client));
+ struct rk1000_codec_priv *rk1000 = i2c_get_clientdata(i2c);
+
+ regmap_write(rk1000->ctlmap, CODEC_CON, CODEC_OFF);
+ snd_soc_unregister_codec(&i2c->dev);
+
return 0;
}
@@ -861,167 +565,22 @@ static const struct i2c_device_id rk1000_codec_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, rk1000_codec_i2c_id);
-/* corgi i2c codec control layer */
+static const struct of_device_id rk1000_codec_of_match[] = {
+ { .compatible = "rockchip,rk1000-codec", },
+ {},
+};
+
static struct i2c_driver rk1000_codec_i2c_driver = {
.driver = {
.name = "rk1000_codec",
- .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rk1000_codec_of_match),
},
.probe = rk1000_codec_i2c_probe,
- .remove = rk1000_codec_i2c_remove,
+ .remove = rk1000_codec_i2c_remove,
.id_table = rk1000_codec_i2c_id,
};
+module_i2c_driver(rk1000_codec_i2c_driver);
-
-static int __init rk1000_codec_modinit(void)
-{
- int ret;
-
- DBG("[%s] start\n", __func__);
- ret = i2c_add_driver(&rk1000_codec_i2c_driver);
- if (ret != 0)
- pr_err("rk1000 codec: register I2C driver err=: %d\n", ret);
- return ret;
-}
-/* late_initcall(rk1000_codec_modinit); */
-module_init(rk1000_codec_modinit);
-
-static void __exit rk1000_codec_exit(void)
-{
- i2c_del_driver(&rk1000_codec_i2c_driver);
-}
-module_exit(rk1000_codec_exit);
-
-
-
-#ifdef RK1000_CODEC_PROC
-#include
-#include
-
-static int debug_write_read;
-
-void rk1000_codec_reg_read(void)
-{
- struct snd_soc_codec *codec;
- int i;
- unsigned int data;
-
- codec = rk1000_codec_codec;
- for (i = 0; i <= 0x1f; i++) {
- data = rk1000_codec_read(codec, i);
- pr_info("reg[0x%x]=0x%x\n", i, data);
- }
-}
-
-
-static ssize_t rk1000_codec_proc_write(struct file *file,
- const char __user *buffer,
- size_t len, loff_t *data)
-{
- char *cookie_pot;
- char *p;
- long reg;
- long value;
- int ret;
-
- cookie_pot = vmalloc(len);
- if (!cookie_pot) {
- pr_err("malloc cookie error for rk1000 codec proc debug\n");
- return -ENOMEM;
- } else {
- if (copy_from_user(cookie_pot, buffer, len))
- return -EFAULT;
- }
- switch (cookie_pot[0]) {
- case 'd':
- case 'D':
- debug_write_read++;
- debug_write_read %= 2;
- if (debug_write_read != 0)
- pr_info("Debug read and write reg on\n");
- else
- pr_info("Debug read and write reg off\n");
- break;
- case 'r':
- case 'R':
- pr_info("Read reg debug\n");
- if (cookie_pot[1] == ':') {
- debug_write_read = 1;
- strsep(&cookie_pot, ":");
- while ((p = strsep(&cookie_pot, ","))) {
- ret = kstrtol((const char *)p, 0, ®);
- if (ret < 0) {
- pr_err("string to long error\n");
- return ret;
- }
- value = rk1000_codec_read(rk1000_codec_codec,
- reg);
- pr_info("rk1000_codec_read:0x%04lx = 0x%04lx",
- reg, value);
- }
- debug_write_read = 0;
- pr_info("\n");
- } else {
- pr_info("Error Read reg debug.\n");
- }
- break;
- case 'w':
- case 'W':
- pr_info("Write reg debug\n");
- if (cookie_pot[1] == ':') {
- debug_write_read = 1;
- strsep(&cookie_pot, ":");
- while ((p = strsep(&cookie_pot, "="))) {
- ret = kstrtol(p, 0, ®);
- if (ret < 0) {
- pr_err("string to long error\n");
- return ret;
- }
- p = strsep(&cookie_pot, ",");
- ret = kstrtol(p, 0, &value);
- if (ret < 0) {
- pr_err("string to long error\n");
- return ret;
- }
- rk1000_codec_write(rk1000_codec_codec, reg,
- value);
- pr_info("rk1000_codec_write:0x%04lx = 0x%04lx\n",
- reg, value);
- }
- debug_write_read = 0;
- pr_info("\n");
- } else {
- pr_info("Error Write reg debug.\n");
- pr_info("For example: w:22=0,23=0,24=0,25=0\n");
- }
- break;
- case 'p':
- rk1000_codec_reg_read();
- break;
- default:
- pr_info("Help for rk1000_codec_ts .\n-->The Cmd list:\n");
- pr_info("-->'d&&D' Open or Off the debug\n");
- pr_info("-->'r&&R' Read reg debug,Example:");
- pr_info("echo 'r:22,23,24,25'>rk1000_codec_ts\n");
- pr_info("-->'w&&W' Write reg debug,Example:");
- pr_info("echo 'w:22=0,23=0,24=0,25=0'>rk1000_codec_ts\n");
- break;
- }
- vfree(cookie_pot);
- return len;
-}
-
-
-static const struct file_operations rk1000_codec_proc_fops = {
- .owner = THIS_MODULE,
- .write = rk1000_codec_proc_write,
-};
-
-static int rk1000_codec_proc_init(void)
-{
- proc_create("rk1000_codec_reg", 0,
- NULL, &rk1000_codec_proc_fops);
- return 0;
-}
-late_initcall(rk1000_codec_proc_init);
-#endif
+MODULE_DESCRIPTION("Rockchip RK1000 CODEC driver");
+MODULE_AUTHOR("Sugar Zhang ");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rk1000_codec.h b/sound/soc/codecs/rk1000_codec.h
old mode 100755
new mode 100644
index 8340e90fc1d0..c213c7ce2fd4
--- a/sound/soc/codecs/rk1000_codec.h
+++ b/sound/soc/codecs/rk1000_codec.h
@@ -323,4 +323,9 @@
#define GPIO_HIGH 1
#define GPIO_LOW 0
+/* rk1000 ctl register */
+#define CODEC_CON 0x01
+#define CODEC_ON 0X00
+#define CODEC_OFF 0x0d
+
#endif