diff options
| -rw-r--r-- | Documentation/devicetree/bindings/sound/rockchip-i2s.txt | 37 | ||||
| -rw-r--r-- | sound/soc/Kconfig | 1 | ||||
| -rw-r--r-- | sound/soc/Makefile | 1 | ||||
| -rw-r--r-- | sound/soc/codecs/rl6231.c | 19 | ||||
| -rw-r--r-- | sound/soc/codecs/rt286.c | 74 | ||||
| -rw-r--r-- | sound/soc/codecs/rt5640.c | 10 | ||||
| -rw-r--r-- | sound/soc/codecs/rt5645.c | 10 | ||||
| -rw-r--r-- | sound/soc/rockchip/Kconfig | 12 | ||||
| -rw-r--r-- | sound/soc/rockchip/Makefile | 4 | ||||
| -rw-r--r-- | sound/soc/rockchip/rockchip_i2s.c | 529 | ||||
| -rw-r--r-- | sound/soc/rockchip/rockchip_i2s.h | 223 |
11 files changed, 847 insertions, 73 deletions
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt new file mode 100644 index 000000000000..6c55fcfe5e1d --- /dev/null +++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | * Rockchip I2S controller | ||
| 2 | |||
| 3 | The I2S bus (Inter-IC sound bus) is a serial link for digital | ||
| 4 | audio data transfer between devices in the system. | ||
| 5 | |||
| 6 | Required properties: | ||
| 7 | |||
| 8 | - compatible: should be one of the followings | ||
| 9 | - "rockchip,rk3066-i2s": for rk3066 | ||
| 10 | - "rockchip,rk3188-i2s", "rockchip,rk3066-i2s": for rk3188 | ||
| 11 | - "rockchip,rk3288-i2s", "rockchip,rk3066-i2s": for rk3288 | ||
| 12 | - reg: physical base address of the controller and length of memory mapped | ||
| 13 | region. | ||
| 14 | - interrupts: should contain the I2S interrupt. | ||
| 15 | - #address-cells: should be 1. | ||
| 16 | - #size-cells: should be 0. | ||
| 17 | - dmas: DMA specifiers for tx and rx dma. See the DMA client binding, | ||
| 18 | Documentation/devicetree/bindings/dma/dma.txt | ||
| 19 | - dma-names: should include "tx" and "rx". | ||
| 20 | - clocks: a list of phandle + clock-specifer pairs, one for each entry in clock-names. | ||
| 21 | - clock-names: should contain followings: | ||
| 22 | - "i2s_hclk": clock for I2S BUS | ||
| 23 | - "i2s_clk" : clock for I2S controller | ||
| 24 | |||
| 25 | Example for rk3288 I2S controller: | ||
| 26 | |||
| 27 | i2s@ff890000 { | ||
| 28 | compatible = "rockchip,rk3288-i2s", "rockchip,rk3066-i2s"; | ||
| 29 | reg = <0xff890000 0x10000>; | ||
| 30 | interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>; | ||
| 31 | #address-cells = <1>; | ||
| 32 | #size-cells = <0>; | ||
| 33 | dmas = <&pdma1 0>, <&pdma1 1>; | ||
| 34 | dma-names = "rx", "tx"; | ||
| 35 | clock-names = "i2s_hclk", "i2s_clk"; | ||
| 36 | clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; | ||
| 37 | }; | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 0060b31cc3f3..0e9623368ab0 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
| @@ -47,6 +47,7 @@ source "sound/soc/kirkwood/Kconfig" | |||
| 47 | source "sound/soc/intel/Kconfig" | 47 | source "sound/soc/intel/Kconfig" |
| 48 | source "sound/soc/mxs/Kconfig" | 48 | source "sound/soc/mxs/Kconfig" |
| 49 | source "sound/soc/pxa/Kconfig" | 49 | source "sound/soc/pxa/Kconfig" |
| 50 | source "sound/soc/rockchip/Kconfig" | ||
| 50 | source "sound/soc/samsung/Kconfig" | 51 | source "sound/soc/samsung/Kconfig" |
| 51 | source "sound/soc/s6000/Kconfig" | 52 | source "sound/soc/s6000/Kconfig" |
| 52 | source "sound/soc/sh/Kconfig" | 53 | source "sound/soc/sh/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 5f1df02984f8..534714a1ca44 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
| @@ -24,6 +24,7 @@ obj-$(CONFIG_SND_SOC) += nuc900/ | |||
| 24 | obj-$(CONFIG_SND_SOC) += omap/ | 24 | obj-$(CONFIG_SND_SOC) += omap/ |
| 25 | obj-$(CONFIG_SND_SOC) += kirkwood/ | 25 | obj-$(CONFIG_SND_SOC) += kirkwood/ |
| 26 | obj-$(CONFIG_SND_SOC) += pxa/ | 26 | obj-$(CONFIG_SND_SOC) += pxa/ |
| 27 | obj-$(CONFIG_SND_SOC) += rockchip/ | ||
| 27 | obj-$(CONFIG_SND_SOC) += samsung/ | 28 | obj-$(CONFIG_SND_SOC) += samsung/ |
| 28 | obj-$(CONFIG_SND_SOC) += s6000/ | 29 | obj-$(CONFIG_SND_SOC) += s6000/ |
| 29 | obj-$(CONFIG_SND_SOC) += sh/ | 30 | obj-$(CONFIG_SND_SOC) += sh/ |
diff --git a/sound/soc/codecs/rl6231.c b/sound/soc/codecs/rl6231.c index 7b82fbe0d14c..56650d6c2f53 100644 --- a/sound/soc/codecs/rl6231.c +++ b/sound/soc/codecs/rl6231.c | |||
| @@ -11,25 +11,6 @@ | |||
| 11 | */ | 11 | */ |
| 12 | 12 | ||
| 13 | #include <linux/module.h> | 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/gpio.h> | ||
| 19 | #include <linux/i2c.h> | ||
| 20 | #include <linux/regmap.h> | ||
| 21 | #include <linux/of.h> | ||
| 22 | #include <linux/of_gpio.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | #include <linux/spi/spi.h> | ||
| 25 | #include <linux/acpi.h> | ||
| 26 | #include <sound/core.h> | ||
| 27 | #include <sound/pcm.h> | ||
| 28 | #include <sound/pcm_params.h> | ||
| 29 | #include <sound/soc.h> | ||
| 30 | #include <sound/soc-dapm.h> | ||
| 31 | #include <sound/initval.h> | ||
| 32 | #include <sound/tlv.h> | ||
| 33 | 14 | ||
| 34 | #include "rl6231.h" | 15 | #include "rl6231.h" |
| 35 | 16 | ||
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c index 218f86efd196..e4f6102efc1a 100644 --- a/sound/soc/codecs/rt286.c +++ b/sound/soc/codecs/rt286.c | |||
| @@ -36,7 +36,6 @@ | |||
| 36 | 36 | ||
| 37 | struct rt286_priv { | 37 | struct rt286_priv { |
| 38 | struct regmap *regmap; | 38 | struct regmap *regmap; |
| 39 | struct snd_soc_codec *codec; | ||
| 40 | struct rt286_platform_data pdata; | 39 | struct rt286_platform_data pdata; |
| 41 | struct i2c_client *i2c; | 40 | struct i2c_client *i2c; |
| 42 | struct snd_soc_jack *jack; | 41 | struct snd_soc_jack *jack; |
| @@ -295,9 +294,8 @@ static int rt286_support_power_controls[] = { | |||
| 295 | }; | 294 | }; |
| 296 | #define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) | 295 | #define RT286_POWER_REG_LEN ARRAY_SIZE(rt286_support_power_controls) |
| 297 | 296 | ||
| 298 | static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) | 297 | static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic) |
| 299 | { | 298 | { |
| 300 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | ||
| 301 | unsigned int val, buf; | 299 | unsigned int val, buf; |
| 302 | int i; | 300 | int i; |
| 303 | 301 | ||
| @@ -305,23 +303,23 @@ static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) | |||
| 305 | *mic = false; | 303 | *mic = false; |
| 306 | 304 | ||
| 307 | if (rt286->pdata.cbj_en) { | 305 | if (rt286->pdata.cbj_en) { |
| 308 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | 306 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); |
| 309 | *hp = buf & 0x80000000; | 307 | *hp = buf & 0x80000000; |
| 310 | if (*hp) { | 308 | if (*hp) { |
| 311 | /* power on HV,VERF */ | 309 | /* power on HV,VERF */ |
| 312 | snd_soc_update_bits(codec, | 310 | regmap_update_bits(rt286->regmap, |
| 313 | RT286_POWER_CTRL1, 0x1001, 0x0); | 311 | RT286_POWER_CTRL1, 0x1001, 0x0); |
| 314 | /* power LDO1 */ | 312 | /* power LDO1 */ |
| 315 | snd_soc_update_bits(codec, | 313 | regmap_update_bits(rt286->regmap, |
| 316 | RT286_POWER_CTRL2, 0x4, 0x4); | 314 | RT286_POWER_CTRL2, 0x4, 0x4); |
| 317 | snd_soc_write(codec, RT286_SET_MIC1, 0x24); | 315 | regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24); |
| 318 | val = snd_soc_read(codec, RT286_CBJ_CTRL2); | 316 | regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val); |
| 319 | 317 | ||
| 320 | msleep(200); | 318 | msleep(200); |
| 321 | i = 40; | 319 | i = 40; |
| 322 | while (((val & 0x0800) == 0) && (i > 0)) { | 320 | while (((val & 0x0800) == 0) && (i > 0)) { |
| 323 | val = snd_soc_read(codec, | 321 | regmap_read(rt286->regmap, |
| 324 | RT286_CBJ_CTRL2); | 322 | RT286_CBJ_CTRL2, &val); |
| 325 | i--; | 323 | i--; |
| 326 | msleep(20); | 324 | msleep(20); |
| 327 | } | 325 | } |
| @@ -329,53 +327,53 @@ static int rt286_jack_detect(struct snd_soc_codec *codec, bool *hp, bool *mic) | |||
| 329 | if (0x0400 == (val & 0x0700)) { | 327 | if (0x0400 == (val & 0x0700)) { |
| 330 | *mic = false; | 328 | *mic = false; |
| 331 | 329 | ||
| 332 | snd_soc_write(codec, | 330 | regmap_write(rt286->regmap, |
| 333 | RT286_SET_MIC1, 0x20); | 331 | RT286_SET_MIC1, 0x20); |
| 334 | /* power off HV,VERF */ | 332 | /* power off HV,VERF */ |
| 335 | snd_soc_update_bits(codec, | 333 | regmap_update_bits(rt286->regmap, |
| 336 | RT286_POWER_CTRL1, 0x1001, 0x1001); | 334 | RT286_POWER_CTRL1, 0x1001, 0x1001); |
| 337 | snd_soc_update_bits(codec, | 335 | regmap_update_bits(rt286->regmap, |
| 338 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); | 336 | RT286_A_BIAS_CTRL3, 0xc000, 0x0000); |
| 339 | snd_soc_update_bits(codec, | 337 | regmap_update_bits(rt286->regmap, |
| 340 | RT286_CBJ_CTRL1, 0x0030, 0x0000); | 338 | RT286_CBJ_CTRL1, 0x0030, 0x0000); |
| 341 | snd_soc_update_bits(codec, | 339 | regmap_update_bits(rt286->regmap, |
| 342 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); | 340 | RT286_A_BIAS_CTRL2, 0xc000, 0x0000); |
| 343 | } else if ((0x0200 == (val & 0x0700)) || | 341 | } else if ((0x0200 == (val & 0x0700)) || |
| 344 | (0x0100 == (val & 0x0700))) { | 342 | (0x0100 == (val & 0x0700))) { |
| 345 | *mic = true; | 343 | *mic = true; |
| 346 | snd_soc_update_bits(codec, | 344 | regmap_update_bits(rt286->regmap, |
| 347 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); | 345 | RT286_A_BIAS_CTRL3, 0xc000, 0x8000); |
| 348 | snd_soc_update_bits(codec, | 346 | regmap_update_bits(rt286->regmap, |
| 349 | RT286_CBJ_CTRL1, 0x0030, 0x0020); | 347 | RT286_CBJ_CTRL1, 0x0030, 0x0020); |
| 350 | snd_soc_update_bits(codec, | 348 | regmap_update_bits(rt286->regmap, |
| 351 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); | 349 | RT286_A_BIAS_CTRL2, 0xc000, 0x8000); |
| 352 | } else { | 350 | } else { |
| 353 | *mic = false; | 351 | *mic = false; |
| 354 | } | 352 | } |
| 355 | 353 | ||
| 356 | snd_soc_update_bits(codec, | 354 | regmap_update_bits(rt286->regmap, |
| 357 | RT286_MISC_CTRL1, | 355 | RT286_MISC_CTRL1, |
| 358 | 0x0060, 0x0000); | 356 | 0x0060, 0x0000); |
| 359 | } else { | 357 | } else { |
| 360 | snd_soc_update_bits(codec, | 358 | regmap_update_bits(rt286->regmap, |
| 361 | RT286_MISC_CTRL1, | 359 | RT286_MISC_CTRL1, |
| 362 | 0x0060, 0x0020); | 360 | 0x0060, 0x0020); |
| 363 | snd_soc_update_bits(codec, | 361 | regmap_update_bits(rt286->regmap, |
| 364 | RT286_A_BIAS_CTRL3, | 362 | RT286_A_BIAS_CTRL3, |
| 365 | 0xc000, 0x8000); | 363 | 0xc000, 0x8000); |
| 366 | snd_soc_update_bits(codec, | 364 | regmap_update_bits(rt286->regmap, |
| 367 | RT286_CBJ_CTRL1, | 365 | RT286_CBJ_CTRL1, |
| 368 | 0x0030, 0x0020); | 366 | 0x0030, 0x0020); |
| 369 | snd_soc_update_bits(codec, | 367 | regmap_update_bits(rt286->regmap, |
| 370 | RT286_A_BIAS_CTRL2, | 368 | RT286_A_BIAS_CTRL2, |
| 371 | 0xc000, 0x8000); | 369 | 0xc000, 0x8000); |
| 372 | 370 | ||
| 373 | *mic = false; | 371 | *mic = false; |
| 374 | } | 372 | } |
| 375 | } else { | 373 | } else { |
| 376 | buf = snd_soc_read(codec, RT286_GET_HP_SENSE); | 374 | regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf); |
| 377 | *hp = buf & 0x80000000; | 375 | *hp = buf & 0x80000000; |
| 378 | buf = snd_soc_read(codec, RT286_GET_MIC1_SENSE); | 376 | regmap_read(rt286->regmap, RT286_GET_MIC1_SENSE, &buf); |
| 379 | *mic = buf & 0x80000000; | 377 | *mic = buf & 0x80000000; |
| 380 | } | 378 | } |
| 381 | 379 | ||
| @@ -390,7 +388,7 @@ static void rt286_jack_detect_work(struct work_struct *work) | |||
| 390 | bool hp = false; | 388 | bool hp = false; |
| 391 | bool mic = false; | 389 | bool mic = false; |
| 392 | 390 | ||
| 393 | rt286_jack_detect(rt286->codec, &hp, &mic); | 391 | rt286_jack_detect(rt286, &hp, &mic); |
| 394 | 392 | ||
| 395 | if (hp == true) | 393 | if (hp == true) |
| 396 | status |= SND_JACK_HEADPHONE; | 394 | status |= SND_JACK_HEADPHONE; |
| @@ -940,11 +938,10 @@ static irqreturn_t rt286_irq(int irq, void *data) | |||
| 940 | bool mic = false; | 938 | bool mic = false; |
| 941 | int status = 0; | 939 | int status = 0; |
| 942 | 940 | ||
| 943 | rt286_jack_detect(rt286->codec, &hp, &mic); | 941 | rt286_jack_detect(rt286, &hp, &mic); |
| 944 | 942 | ||
| 945 | /* Clear IRQ */ | 943 | /* Clear IRQ */ |
| 946 | snd_soc_update_bits(rt286->codec, | 944 | regmap_update_bits(rt286->regmap, RT286_IRQ_CTRL, 0x1, 0x1); |
| 947 | RT286_IRQ_CTRL, 0x1, 0x1); | ||
| 948 | 945 | ||
| 949 | if (hp == true) | 946 | if (hp == true) |
| 950 | status |= SND_JACK_HEADPHONE; | 947 | status |= SND_JACK_HEADPHONE; |
| @@ -965,7 +962,16 @@ static int rt286_probe(struct snd_soc_codec *codec) | |||
| 965 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); | 962 | struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec); |
| 966 | 963 | ||
| 967 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 964 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
| 968 | rt286->codec = codec; | 965 | |
| 966 | if (rt286->i2c->irq) { | ||
| 967 | regmap_update_bits(rt286->regmap, | ||
| 968 | RT286_IRQ_CTRL, 0x2, 0x2); | ||
| 969 | |||
| 970 | INIT_DELAYED_WORK(&rt286->jack_detect_work, | ||
| 971 | rt286_jack_detect_work); | ||
| 972 | schedule_delayed_work(&rt286->jack_detect_work, | ||
| 973 | msecs_to_jiffies(1250)); | ||
| 974 | } | ||
| 969 | 975 | ||
| 970 | return 0; | 976 | return 0; |
| 971 | } | 977 | } |
| @@ -1171,14 +1177,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c, | |||
| 1171 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); | 1177 | regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f); |
| 1172 | 1178 | ||
| 1173 | if (rt286->i2c->irq) { | 1179 | if (rt286->i2c->irq) { |
| 1174 | regmap_update_bits(rt286->regmap, | ||
| 1175 | RT286_IRQ_CTRL, 0x2, 0x2); | ||
| 1176 | |||
| 1177 | INIT_DELAYED_WORK(&rt286->jack_detect_work, | ||
| 1178 | rt286_jack_detect_work); | ||
| 1179 | schedule_delayed_work(&rt286->jack_detect_work, | ||
| 1180 | msecs_to_jiffies(1250)); | ||
| 1181 | |||
| 1182 | ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, | 1180 | ret = request_threaded_irq(rt286->i2c->irq, NULL, rt286_irq, |
| 1183 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); | 1181 | IRQF_TRIGGER_HIGH | IRQF_ONESHOT, "rt286", rt286); |
| 1184 | if (ret != 0) { | 1182 | if (ret != 0) { |
diff --git a/sound/soc/codecs/rt5640.c b/sound/soc/codecs/rt5640.c index de80e89b5fd8..6bc6efdec550 100644 --- a/sound/soc/codecs/rt5640.c +++ b/sound/soc/codecs/rt5640.c | |||
| @@ -2215,14 +2215,8 @@ static int rt5640_i2c_probe(struct i2c_client *i2c, | |||
| 2215 | 2215 | ||
| 2216 | rt5640->hp_mute = 1; | 2216 | rt5640->hp_mute = 1; |
| 2217 | 2217 | ||
| 2218 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, | 2218 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5640, |
| 2219 | rt5640_dai, ARRAY_SIZE(rt5640_dai)); | 2219 | rt5640_dai, ARRAY_SIZE(rt5640_dai)); |
| 2220 | if (ret < 0) | ||
| 2221 | goto err; | ||
| 2222 | |||
| 2223 | return 0; | ||
| 2224 | err: | ||
| 2225 | return ret; | ||
| 2226 | } | 2220 | } |
| 2227 | 2221 | ||
| 2228 | static int rt5640_i2c_remove(struct i2c_client *i2c) | 2222 | static int rt5640_i2c_remove(struct i2c_client *i2c) |
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c index 02147be2b302..a7762d0a623e 100644 --- a/sound/soc/codecs/rt5645.c +++ b/sound/soc/codecs/rt5645.c | |||
| @@ -2345,14 +2345,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c, | |||
| 2345 | 2345 | ||
| 2346 | } | 2346 | } |
| 2347 | 2347 | ||
| 2348 | ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, | 2348 | return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645, |
| 2349 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); | 2349 | rt5645_dai, ARRAY_SIZE(rt5645_dai)); |
| 2350 | if (ret < 0) | ||
| 2351 | goto err; | ||
| 2352 | |||
| 2353 | return 0; | ||
| 2354 | err: | ||
| 2355 | return ret; | ||
| 2356 | } | 2350 | } |
| 2357 | 2351 | ||
| 2358 | static int rt5645_i2c_remove(struct i2c_client *i2c) | 2352 | static int rt5645_i2c_remove(struct i2c_client *i2c) |
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig new file mode 100644 index 000000000000..c196a466eef6 --- /dev/null +++ b/sound/soc/rockchip/Kconfig | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | config SND_SOC_ROCKCHIP | ||
| 2 | tristate "ASoC support for Rockchip" | ||
| 3 | depends on COMPILE_TEST || ARCH_ROCKCHIP | ||
| 4 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
| 5 | select SND_ROCKCHIP_I2S | ||
| 6 | help | ||
| 7 | Say Y or M if you want to add support for codecs attached to | ||
| 8 | the Rockchip SoCs' Audio interfaces. You will also need to | ||
| 9 | select the audio interfaces to support below. | ||
| 10 | |||
| 11 | config SND_ROCKCHIP_I2S | ||
| 12 | tristate | ||
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile new file mode 100644 index 000000000000..1006418e1394 --- /dev/null +++ b/sound/soc/rockchip/Makefile | |||
| @@ -0,0 +1,4 @@ | |||
| 1 | # ROCKCHIP Platform Support | ||
| 2 | snd-soc-i2s-objs := rockchip_i2s.o | ||
| 3 | |||
| 4 | obj-$(CONFIG_SND_ROCKCHIP_I2S) += snd-soc-i2s.o | ||
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c new file mode 100644 index 000000000000..8d8e4b59049f --- /dev/null +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
| @@ -0,0 +1,529 @@ | |||
| 1 | /* sound/soc/rockchip/rockchip_i2s.c | ||
| 2 | * | ||
| 3 | * ALSA SoC Audio Layer - Rockchip I2S Controller driver | ||
| 4 | * | ||
| 5 | * Copyright (c) 2014 Rockchip Electronics Co. Ltd. | ||
| 6 | * Author: Jianqun <jay.xu@rock-chips.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/delay.h> | ||
| 15 | #include <linux/of_gpio.h> | ||
| 16 | #include <linux/clk.h> | ||
| 17 | #include <linux/pm_runtime.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <sound/pcm_params.h> | ||
| 20 | #include <sound/dmaengine_pcm.h> | ||
| 21 | |||
| 22 | #include "rockchip_i2s.h" | ||
| 23 | |||
| 24 | #define DRV_NAME "rockchip-i2s" | ||
| 25 | |||
| 26 | struct rk_i2s_dev { | ||
| 27 | struct device *dev; | ||
| 28 | |||
| 29 | struct clk *hclk; | ||
| 30 | struct clk *mclk; | ||
| 31 | |||
| 32 | struct snd_dmaengine_dai_dma_data capture_dma_data; | ||
| 33 | struct snd_dmaengine_dai_dma_data playback_dma_data; | ||
| 34 | |||
| 35 | struct regmap *regmap; | ||
| 36 | |||
| 37 | /* | ||
| 38 | * Used to indicate the tx/rx status. | ||
| 39 | * I2S controller hopes to start the tx and rx together, | ||
| 40 | * also to stop them when they are both try to stop. | ||
| 41 | */ | ||
| 42 | bool tx_start; | ||
| 43 | bool rx_start; | ||
| 44 | }; | ||
| 45 | |||
| 46 | static int i2s_runtime_suspend(struct device *dev) | ||
| 47 | { | ||
| 48 | struct rk_i2s_dev *i2s = dev_get_drvdata(dev); | ||
| 49 | |||
| 50 | clk_disable_unprepare(i2s->mclk); | ||
| 51 | |||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | |||
| 55 | static int i2s_runtime_resume(struct device *dev) | ||
| 56 | { | ||
| 57 | struct rk_i2s_dev *i2s = dev_get_drvdata(dev); | ||
| 58 | int ret; | ||
| 59 | |||
| 60 | ret = clk_prepare_enable(i2s->mclk); | ||
| 61 | if (ret) { | ||
| 62 | dev_err(i2s->dev, "clock enable failed %d\n", ret); | ||
| 63 | return ret; | ||
| 64 | } | ||
| 65 | |||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | static inline struct rk_i2s_dev *to_info(struct snd_soc_dai *dai) | ||
| 70 | { | ||
| 71 | return snd_soc_dai_get_drvdata(dai); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) | ||
| 75 | { | ||
| 76 | unsigned int val = 0; | ||
| 77 | int retry = 10; | ||
| 78 | |||
| 79 | if (on) { | ||
| 80 | regmap_update_bits(i2s->regmap, I2S_DMACR, | ||
| 81 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); | ||
| 82 | |||
| 83 | regmap_update_bits(i2s->regmap, I2S_XFER, | ||
| 84 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, | ||
| 85 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); | ||
| 86 | |||
| 87 | i2s->tx_start = true; | ||
| 88 | } else { | ||
| 89 | i2s->tx_start = false; | ||
| 90 | |||
| 91 | regmap_update_bits(i2s->regmap, I2S_DMACR, | ||
| 92 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); | ||
| 93 | |||
| 94 | if (!i2s->rx_start) { | ||
| 95 | regmap_update_bits(i2s->regmap, I2S_XFER, | ||
| 96 | I2S_XFER_TXS_START | | ||
| 97 | I2S_XFER_RXS_START, | ||
| 98 | I2S_XFER_TXS_STOP | | ||
| 99 | I2S_XFER_RXS_STOP); | ||
| 100 | |||
| 101 | regmap_update_bits(i2s->regmap, I2S_CLR, | ||
| 102 | I2S_CLR_TXC | I2S_CLR_RXC, | ||
| 103 | I2S_CLR_TXC | I2S_CLR_RXC); | ||
| 104 | |||
| 105 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
| 106 | |||
| 107 | /* Should wait for clear operation to finish */ | ||
| 108 | while (val) { | ||
| 109 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
| 110 | retry--; | ||
| 111 | if (!retry) | ||
| 112 | dev_warn(i2s->dev, "fail to clear\n"); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) | ||
| 119 | { | ||
| 120 | unsigned int val = 0; | ||
| 121 | int retry = 10; | ||
| 122 | |||
| 123 | if (on) { | ||
| 124 | regmap_update_bits(i2s->regmap, I2S_DMACR, | ||
| 125 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); | ||
| 126 | |||
| 127 | regmap_update_bits(i2s->regmap, I2S_XFER, | ||
| 128 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, | ||
| 129 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); | ||
| 130 | |||
| 131 | i2s->rx_start = true; | ||
| 132 | } else { | ||
| 133 | i2s->rx_start = false; | ||
| 134 | |||
| 135 | regmap_update_bits(i2s->regmap, I2S_DMACR, | ||
| 136 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); | ||
| 137 | |||
| 138 | if (!i2s->tx_start) { | ||
| 139 | regmap_update_bits(i2s->regmap, I2S_XFER, | ||
| 140 | I2S_XFER_TXS_START | | ||
| 141 | I2S_XFER_RXS_START, | ||
| 142 | I2S_XFER_TXS_STOP | | ||
| 143 | I2S_XFER_RXS_STOP); | ||
| 144 | |||
| 145 | regmap_update_bits(i2s->regmap, I2S_CLR, | ||
| 146 | I2S_CLR_TXC | I2S_CLR_RXC, | ||
| 147 | I2S_CLR_TXC | I2S_CLR_RXC); | ||
| 148 | |||
| 149 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
| 150 | |||
| 151 | /* Should wait for clear operation to finish */ | ||
| 152 | while (val) { | ||
| 153 | regmap_read(i2s->regmap, I2S_CLR, &val); | ||
| 154 | retry--; | ||
| 155 | if (!retry) | ||
| 156 | dev_warn(i2s->dev, "fail to clear\n"); | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | ||
| 163 | unsigned int fmt) | ||
| 164 | { | ||
| 165 | struct rk_i2s_dev *i2s = to_info(cpu_dai); | ||
| 166 | unsigned int mask = 0, val = 0; | ||
| 167 | |||
| 168 | mask = I2S_CKR_MSS_SLAVE; | ||
| 169 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 170 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 171 | val = I2S_CKR_MSS_SLAVE; | ||
| 172 | break; | ||
| 173 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 174 | val = I2S_CKR_MSS_MASTER; | ||
| 175 | break; | ||
| 176 | default: | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | |||
| 180 | regmap_update_bits(i2s->regmap, I2S_CKR, mask, val); | ||
| 181 | |||
| 182 | mask = I2S_TXCR_IBM_MASK; | ||
| 183 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 184 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 185 | val = I2S_TXCR_IBM_RSJM; | ||
| 186 | break; | ||
| 187 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 188 | val = I2S_TXCR_IBM_LSJM; | ||
| 189 | break; | ||
| 190 | case SND_SOC_DAIFMT_I2S: | ||
| 191 | val = I2S_TXCR_IBM_NORMAL; | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | return -EINVAL; | ||
| 195 | } | ||
| 196 | |||
| 197 | regmap_update_bits(i2s->regmap, I2S_TXCR, mask, val); | ||
| 198 | |||
| 199 | mask = I2S_RXCR_IBM_MASK; | ||
| 200 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 201 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 202 | val = I2S_RXCR_IBM_RSJM; | ||
| 203 | break; | ||
| 204 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 205 | val = I2S_RXCR_IBM_LSJM; | ||
| 206 | break; | ||
| 207 | case SND_SOC_DAIFMT_I2S: | ||
| 208 | val = I2S_RXCR_IBM_NORMAL; | ||
| 209 | break; | ||
| 210 | default: | ||
| 211 | return -EINVAL; | ||
| 212 | } | ||
| 213 | |||
| 214 | regmap_update_bits(i2s->regmap, I2S_RXCR, mask, val); | ||
| 215 | |||
| 216 | return 0; | ||
| 217 | } | ||
| 218 | |||
| 219 | static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, | ||
| 220 | struct snd_pcm_hw_params *params, | ||
| 221 | struct snd_soc_dai *dai) | ||
| 222 | { | ||
| 223 | struct rk_i2s_dev *i2s = to_info(dai); | ||
| 224 | unsigned int val = 0; | ||
| 225 | |||
| 226 | switch (params_format(params)) { | ||
| 227 | case SNDRV_PCM_FORMAT_S8: | ||
| 228 | val |= I2S_TXCR_VDW(8); | ||
| 229 | break; | ||
| 230 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 231 | val |= I2S_TXCR_VDW(16); | ||
| 232 | break; | ||
| 233 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 234 | val |= I2S_TXCR_VDW(20); | ||
| 235 | break; | ||
| 236 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 237 | val |= I2S_TXCR_VDW(24); | ||
| 238 | break; | ||
| 239 | default: | ||
| 240 | return -EINVAL; | ||
| 241 | } | ||
| 242 | |||
| 243 | regmap_update_bits(i2s->regmap, I2S_TXCR, I2S_TXCR_VDW_MASK, val); | ||
| 244 | regmap_update_bits(i2s->regmap, I2S_RXCR, I2S_RXCR_VDW_MASK, val); | ||
| 245 | |||
| 246 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 247 | dai->playback_dma_data = &i2s->playback_dma_data; | ||
| 248 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, | ||
| 249 | I2S_DMACR_TDL(1) | I2S_DMACR_TDE_ENABLE); | ||
| 250 | } else { | ||
| 251 | dai->capture_dma_data = &i2s->capture_dma_data; | ||
| 252 | regmap_update_bits(i2s->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, | ||
| 253 | I2S_DMACR_RDL(1) | I2S_DMACR_RDE_ENABLE); | ||
| 254 | } | ||
| 255 | |||
| 256 | return 0; | ||
| 257 | } | ||
| 258 | |||
| 259 | static int rockchip_i2s_trigger(struct snd_pcm_substream *substream, | ||
| 260 | int cmd, struct snd_soc_dai *dai) | ||
| 261 | { | ||
| 262 | struct rk_i2s_dev *i2s = to_info(dai); | ||
| 263 | int ret = 0; | ||
| 264 | |||
| 265 | switch (cmd) { | ||
| 266 | case SNDRV_PCM_TRIGGER_START: | ||
| 267 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 268 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 269 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
| 270 | rockchip_snd_rxctrl(i2s, 1); | ||
| 271 | else | ||
| 272 | rockchip_snd_txctrl(i2s, 1); | ||
| 273 | break; | ||
| 274 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 275 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 276 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 277 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
| 278 | rockchip_snd_rxctrl(i2s, 0); | ||
| 279 | else | ||
| 280 | rockchip_snd_txctrl(i2s, 0); | ||
| 281 | break; | ||
| 282 | default: | ||
| 283 | ret = -EINVAL; | ||
| 284 | break; | ||
| 285 | } | ||
| 286 | |||
| 287 | return ret; | ||
| 288 | } | ||
| 289 | |||
| 290 | static int rockchip_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, | ||
| 291 | unsigned int freq, int dir) | ||
| 292 | { | ||
| 293 | struct rk_i2s_dev *i2s = to_info(cpu_dai); | ||
| 294 | int ret; | ||
| 295 | |||
| 296 | ret = clk_set_rate(i2s->mclk, freq); | ||
| 297 | if (ret) | ||
| 298 | dev_err(i2s->dev, "Fail to set mclk %d\n", ret); | ||
| 299 | |||
| 300 | return ret; | ||
| 301 | } | ||
| 302 | |||
| 303 | static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = { | ||
| 304 | .hw_params = rockchip_i2s_hw_params, | ||
| 305 | .set_sysclk = rockchip_i2s_set_sysclk, | ||
| 306 | .set_fmt = rockchip_i2s_set_fmt, | ||
| 307 | .trigger = rockchip_i2s_trigger, | ||
| 308 | }; | ||
| 309 | |||
| 310 | static struct snd_soc_dai_driver rockchip_i2s_dai = { | ||
| 311 | .playback = { | ||
| 312 | .channels_min = 2, | ||
| 313 | .channels_max = 8, | ||
| 314 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 315 | .formats = (SNDRV_PCM_FMTBIT_S8 | | ||
| 316 | SNDRV_PCM_FMTBIT_S16_LE | | ||
| 317 | SNDRV_PCM_FMTBIT_S20_3LE | | ||
| 318 | SNDRV_PCM_FMTBIT_S24_LE), | ||
| 319 | }, | ||
| 320 | .capture = { | ||
| 321 | .channels_min = 2, | ||
| 322 | .channels_max = 2, | ||
| 323 | .rates = SNDRV_PCM_RATE_8000_192000, | ||
| 324 | .formats = (SNDRV_PCM_FMTBIT_S8 | | ||
| 325 | SNDRV_PCM_FMTBIT_S16_LE | | ||
| 326 | SNDRV_PCM_FMTBIT_S20_3LE | | ||
| 327 | SNDRV_PCM_FMTBIT_S24_LE), | ||
| 328 | }, | ||
| 329 | .ops = &rockchip_i2s_dai_ops, | ||
| 330 | }; | ||
| 331 | |||
| 332 | static const struct snd_soc_component_driver rockchip_i2s_component = { | ||
| 333 | .name = DRV_NAME, | ||
| 334 | }; | ||
| 335 | |||
| 336 | static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg) | ||
| 337 | { | ||
| 338 | switch (reg) { | ||
| 339 | case I2S_TXCR: | ||
| 340 | case I2S_RXCR: | ||
| 341 | case I2S_CKR: | ||
| 342 | case I2S_DMACR: | ||
| 343 | case I2S_INTCR: | ||
| 344 | case I2S_XFER: | ||
| 345 | case I2S_CLR: | ||
| 346 | case I2S_TXDR: | ||
| 347 | return true; | ||
| 348 | default: | ||
| 349 | return false; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | |||
| 353 | static bool rockchip_i2s_rd_reg(struct device *dev, unsigned int reg) | ||
| 354 | { | ||
| 355 | switch (reg) { | ||
| 356 | case I2S_TXCR: | ||
| 357 | case I2S_RXCR: | ||
| 358 | case I2S_CKR: | ||
| 359 | case I2S_DMACR: | ||
| 360 | case I2S_INTCR: | ||
| 361 | case I2S_XFER: | ||
| 362 | case I2S_CLR: | ||
| 363 | case I2S_RXDR: | ||
| 364 | return true; | ||
| 365 | default: | ||
| 366 | return false; | ||
| 367 | } | ||
| 368 | } | ||
| 369 | |||
| 370 | static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg) | ||
| 371 | { | ||
| 372 | switch (reg) { | ||
| 373 | case I2S_FIFOLR: | ||
| 374 | case I2S_INTSR: | ||
| 375 | return true; | ||
| 376 | default: | ||
| 377 | return false; | ||
| 378 | } | ||
| 379 | } | ||
| 380 | |||
| 381 | static bool rockchip_i2s_precious_reg(struct device *dev, unsigned int reg) | ||
| 382 | { | ||
| 383 | switch (reg) { | ||
| 384 | case I2S_FIFOLR: | ||
| 385 | return true; | ||
| 386 | default: | ||
| 387 | return false; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | |||
| 391 | static const struct regmap_config rockchip_i2s_regmap_config = { | ||
| 392 | .reg_bits = 32, | ||
| 393 | .reg_stride = 4, | ||
| 394 | .val_bits = 32, | ||
| 395 | .max_register = I2S_RXDR, | ||
| 396 | .writeable_reg = rockchip_i2s_wr_reg, | ||
| 397 | .readable_reg = rockchip_i2s_rd_reg, | ||
| 398 | .volatile_reg = rockchip_i2s_volatile_reg, | ||
| 399 | .precious_reg = rockchip_i2s_precious_reg, | ||
| 400 | .cache_type = REGCACHE_FLAT, | ||
| 401 | }; | ||
| 402 | |||
| 403 | static int rockchip_i2s_probe(struct platform_device *pdev) | ||
| 404 | { | ||
| 405 | struct rk_i2s_dev *i2s; | ||
| 406 | struct resource *res; | ||
| 407 | void __iomem *regs; | ||
| 408 | int ret; | ||
| 409 | |||
| 410 | i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); | ||
| 411 | if (!i2s) { | ||
| 412 | dev_err(&pdev->dev, "Can't allocate rk_i2s_dev\n"); | ||
| 413 | return -ENOMEM; | ||
| 414 | } | ||
| 415 | |||
| 416 | /* try to prepare related clocks */ | ||
| 417 | i2s->hclk = devm_clk_get(&pdev->dev, "i2s_hclk"); | ||
| 418 | if (IS_ERR(i2s->hclk)) { | ||
| 419 | dev_err(&pdev->dev, "Can't retrieve i2s bus clock\n"); | ||
| 420 | return PTR_ERR(i2s->hclk); | ||
| 421 | } | ||
| 422 | |||
| 423 | i2s->mclk = devm_clk_get(&pdev->dev, "i2s_clk"); | ||
| 424 | if (IS_ERR(i2s->mclk)) { | ||
| 425 | dev_err(&pdev->dev, "Can't retrieve i2s master clock\n"); | ||
| 426 | return PTR_ERR(i2s->mclk); | ||
| 427 | } | ||
| 428 | |||
| 429 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 430 | regs = devm_ioremap_resource(&pdev->dev, res); | ||
| 431 | if (IS_ERR(regs)) | ||
| 432 | return PTR_ERR(regs); | ||
| 433 | |||
| 434 | i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, | ||
| 435 | &rockchip_i2s_regmap_config); | ||
| 436 | if (IS_ERR(i2s->regmap)) { | ||
| 437 | dev_err(&pdev->dev, | ||
| 438 | "Failed to initialise managed register map\n"); | ||
| 439 | return PTR_ERR(i2s->regmap); | ||
| 440 | } | ||
| 441 | |||
| 442 | i2s->playback_dma_data.addr = res->start + I2S_TXDR; | ||
| 443 | i2s->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 444 | i2s->playback_dma_data.maxburst = 16; | ||
| 445 | |||
| 446 | i2s->capture_dma_data.addr = res->start + I2S_RXDR; | ||
| 447 | i2s->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
| 448 | i2s->capture_dma_data.maxburst = 16; | ||
| 449 | |||
| 450 | i2s->dev = &pdev->dev; | ||
| 451 | dev_set_drvdata(&pdev->dev, i2s); | ||
| 452 | |||
| 453 | pm_runtime_enable(&pdev->dev); | ||
| 454 | if (!pm_runtime_enabled(&pdev->dev)) { | ||
| 455 | ret = i2s_runtime_resume(&pdev->dev); | ||
| 456 | if (ret) | ||
| 457 | goto err_pm_disable; | ||
| 458 | } | ||
| 459 | |||
| 460 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
| 461 | &rockchip_i2s_component, | ||
| 462 | &rockchip_i2s_dai, 1); | ||
| 463 | if (ret) { | ||
| 464 | dev_err(&pdev->dev, "Could not register DAI\n"); | ||
| 465 | goto err_suspend; | ||
| 466 | } | ||
| 467 | |||
| 468 | ret = snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); | ||
| 469 | if (ret) { | ||
| 470 | dev_err(&pdev->dev, "Could not register PCM\n"); | ||
| 471 | goto err_pcm_register; | ||
| 472 | } | ||
| 473 | |||
| 474 | return 0; | ||
| 475 | |||
| 476 | err_pcm_register: | ||
| 477 | snd_dmaengine_pcm_unregister(&pdev->dev); | ||
| 478 | err_suspend: | ||
| 479 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
| 480 | i2s_runtime_suspend(&pdev->dev); | ||
| 481 | err_pm_disable: | ||
| 482 | pm_runtime_disable(&pdev->dev); | ||
| 483 | |||
| 484 | return ret; | ||
| 485 | } | ||
| 486 | |||
| 487 | static int rockchip_i2s_remove(struct platform_device *pdev) | ||
| 488 | { | ||
| 489 | struct rk_i2s_dev *i2s = dev_get_drvdata(&pdev->dev); | ||
| 490 | |||
| 491 | pm_runtime_disable(&pdev->dev); | ||
| 492 | if (!pm_runtime_status_suspended(&pdev->dev)) | ||
| 493 | i2s_runtime_suspend(&pdev->dev); | ||
| 494 | |||
| 495 | clk_disable_unprepare(i2s->mclk); | ||
| 496 | clk_disable_unprepare(i2s->hclk); | ||
| 497 | snd_dmaengine_pcm_unregister(&pdev->dev); | ||
| 498 | snd_soc_unregister_component(&pdev->dev); | ||
| 499 | |||
| 500 | return 0; | ||
| 501 | } | ||
| 502 | |||
| 503 | static const struct of_device_id rockchip_i2s_match[] = { | ||
| 504 | { .compatible = "rockchip,rk3066-i2s", }, | ||
| 505 | {}, | ||
| 506 | }; | ||
| 507 | |||
| 508 | static const struct dev_pm_ops rockchip_i2s_pm_ops = { | ||
| 509 | SET_RUNTIME_PM_OPS(i2s_runtime_suspend, i2s_runtime_resume, | ||
| 510 | NULL) | ||
| 511 | }; | ||
| 512 | |||
| 513 | static struct platform_driver rockchip_i2s_driver = { | ||
| 514 | .probe = rockchip_i2s_probe, | ||
| 515 | .remove = rockchip_i2s_remove, | ||
| 516 | .driver = { | ||
| 517 | .name = DRV_NAME, | ||
| 518 | .owner = THIS_MODULE, | ||
| 519 | .of_match_table = of_match_ptr(rockchip_i2s_match), | ||
| 520 | .pm = &rockchip_i2s_pm_ops, | ||
| 521 | }, | ||
| 522 | }; | ||
| 523 | module_platform_driver(rockchip_i2s_driver); | ||
| 524 | |||
| 525 | MODULE_DESCRIPTION("ROCKCHIP IIS ASoC Interface"); | ||
| 526 | MODULE_AUTHOR("jianqun <jay.xu@rock-chips.com>"); | ||
| 527 | MODULE_LICENSE("GPL v2"); | ||
| 528 | MODULE_ALIAS("platform:" DRV_NAME); | ||
| 529 | MODULE_DEVICE_TABLE(of, rockchip_i2s_match); | ||
diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h new file mode 100644 index 000000000000..89a5d8bc6ee7 --- /dev/null +++ b/sound/soc/rockchip/rockchip_i2s.h | |||
| @@ -0,0 +1,223 @@ | |||
| 1 | /* | ||
| 2 | * sound/soc/rockchip/rockchip_i2s.h | ||
| 3 | * | ||
| 4 | * ALSA SoC Audio Layer - Rockchip I2S Controller driver | ||
| 5 | * | ||
| 6 | * Copyright (c) 2014 Rockchip Electronics Co. Ltd. | ||
| 7 | * Author: Jianqun xu <jay.xu@rock-chips.com> | ||
| 8 | * | ||
| 9 | * This program is free software; you can redistribute it and/or modify | ||
| 10 | * it under the terms of the GNU General Public License version 2 as | ||
| 11 | * published by the Free Software Foundation. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef _ROCKCHIP_IIS_H | ||
| 15 | #define _ROCKCHIP_IIS_H | ||
| 16 | |||
| 17 | /* | ||
| 18 | * TXCR | ||
| 19 | * transmit operation control register | ||
| 20 | */ | ||
| 21 | #define I2S_TXCR_RCNT_SHIFT 17 | ||
| 22 | #define I2S_TXCR_RCNT_MASK (0x3f << I2S_TXCR_RCNT_SHIFT) | ||
| 23 | #define I2S_TXCR_CSR_SHIFT 15 | ||
| 24 | #define I2S_TXCR_CSR(x) (x << I2S_TXCR_CSR_SHIFT) | ||
| 25 | #define I2S_TXCR_CSR_MASK (3 << I2S_TXCR_CSR_SHIFT) | ||
| 26 | #define I2S_TXCR_HWT BIT(14) | ||
| 27 | #define I2S_TXCR_SJM_SHIFT 12 | ||
| 28 | #define I2S_TXCR_SJM_R (0 << I2S_TXCR_SJM_SHIFT) | ||
| 29 | #define I2S_TXCR_SJM_L (1 << I2S_TXCR_SJM_SHIFT) | ||
| 30 | #define I2S_TXCR_FBM_SHIFT 11 | ||
| 31 | #define I2S_TXCR_FBM_MSB (0 << I2S_TXCR_FBM_SHIFT) | ||
| 32 | #define I2S_TXCR_FBM_LSB (1 << I2S_TXCR_FBM_SHIFT) | ||
| 33 | #define I2S_TXCR_IBM_SHIFT 9 | ||
| 34 | #define I2S_TXCR_IBM_NORMAL (0 << I2S_TXCR_IBM_SHIFT) | ||
| 35 | #define I2S_TXCR_IBM_LSJM (1 << I2S_TXCR_IBM_SHIFT) | ||
| 36 | #define I2S_TXCR_IBM_RSJM (2 << I2S_TXCR_IBM_SHIFT) | ||
| 37 | #define I2S_TXCR_IBM_MASK (3 << I2S_TXCR_IBM_SHIFT) | ||
| 38 | #define I2S_TXCR_PBM_SHIFT 7 | ||
| 39 | #define I2S_TXCR_PBM_MODE(x) (x << I2S_TXCR_PBM_SHIFT) | ||
| 40 | #define I2S_TXCR_PBM_MASK (3 << I2S_TXCR_PBM_SHIFT) | ||
| 41 | #define I2S_TXCR_TFS_SHIFT 5 | ||
| 42 | #define I2S_TXCR_TFS_I2S (0 << I2S_TXCR_TFS_SHIFT) | ||
| 43 | #define I2S_TXCR_TFS_PCM (1 << I2S_TXCR_TFS_SHIFT) | ||
| 44 | #define I2S_TXCR_VDW_SHIFT 0 | ||
| 45 | #define I2S_TXCR_VDW(x) ((x - 1) << I2S_TXCR_VDW_SHIFT) | ||
| 46 | #define I2S_TXCR_VDW_MASK (0x1f << I2S_TXCR_VDW_SHIFT) | ||
| 47 | |||
| 48 | /* | ||
| 49 | * RXCR | ||
| 50 | * receive operation control register | ||
| 51 | */ | ||
| 52 | #define I2S_RXCR_HWT BIT(14) | ||
| 53 | #define I2S_RXCR_SJM_SHIFT 12 | ||
| 54 | #define I2S_RXCR_SJM_R (0 << I2S_RXCR_SJM_SHIFT) | ||
| 55 | #define I2S_RXCR_SJM_L (1 << I2S_RXCR_SJM_SHIFT) | ||
| 56 | #define I2S_RXCR_FBM_SHIFT 11 | ||
| 57 | #define I2S_RXCR_FBM_MSB (0 << I2S_RXCR_FBM_SHIFT) | ||
| 58 | #define I2S_RXCR_FBM_LSB (1 << I2S_RXCR_FBM_SHIFT) | ||
| 59 | #define I2S_RXCR_IBM_SHIFT 9 | ||
| 60 | #define I2S_RXCR_IBM_NORMAL (0 << I2S_RXCR_IBM_SHIFT) | ||
| 61 | #define I2S_RXCR_IBM_LSJM (1 << I2S_RXCR_IBM_SHIFT) | ||
| 62 | #define I2S_RXCR_IBM_RSJM (2 << I2S_RXCR_IBM_SHIFT) | ||
| 63 | #define I2S_RXCR_IBM_MASK (3 << I2S_RXCR_IBM_SHIFT) | ||
| 64 | #define I2S_RXCR_PBM_SHIFT 7 | ||
| 65 | #define I2S_RXCR_PBM_MODE(x) (x << I2S_RXCR_PBM_SHIFT) | ||
| 66 | #define I2S_RXCR_PBM_MASK (3 << I2S_RXCR_PBM_SHIFT) | ||
| 67 | #define I2S_RXCR_TFS_SHIFT 5 | ||
| 68 | #define I2S_RXCR_TFS_I2S (0 << I2S_RXCR_TFS_SHIFT) | ||
| 69 | #define I2S_RXCR_TFS_PCM (1 << I2S_RXCR_TFS_SHIFT) | ||
| 70 | #define I2S_RXCR_VDW_SHIFT 0 | ||
| 71 | #define I2S_RXCR_VDW(x) ((x - 1) << I2S_RXCR_VDW_SHIFT) | ||
| 72 | #define I2S_RXCR_VDW_MASK (0x1f << I2S_RXCR_VDW_SHIFT) | ||
| 73 | |||
| 74 | /* | ||
| 75 | * CKR | ||
| 76 | * clock generation register | ||
| 77 | */ | ||
| 78 | #define I2S_CKR_MSS_SHIFT 27 | ||
| 79 | #define I2S_CKR_MSS_MASTER (0 << I2S_CKR_MSS_SHIFT) | ||
| 80 | #define I2S_CKR_MSS_SLAVE (1 << I2S_CKR_MSS_SHIFT) | ||
| 81 | #define I2S_CKR_MSS_MASK (1 << I2S_CKR_MSS_SHIFT) | ||
| 82 | #define I2S_CKR_CKP_SHIFT 26 | ||
| 83 | #define I2S_CKR_CKP_NEG (0 << I2S_CKR_CKP_SHIFT) | ||
| 84 | #define I2S_CKR_CKP_POS (1 << I2S_CKR_CKP_SHIFT) | ||
| 85 | #define I2S_CKR_RLP_SHIFT 25 | ||
| 86 | #define I2S_CKR_RLP_NORMAL (0 << I2S_CKR_RLP_SHIFT) | ||
| 87 | #define I2S_CKR_RLP_OPPSITE (1 << I2S_CKR_RLP_SHIFT) | ||
| 88 | #define I2S_CKR_TLP_SHIFT 24 | ||
| 89 | #define I2S_CKR_TLP_NORMAL (0 << I2S_CKR_TLP_SHIFT) | ||
| 90 | #define I2S_CKR_TLP_OPPSITE (1 << I2S_CKR_TLP_SHIFT) | ||
| 91 | #define I2S_CKR_MDIV_SHIFT 16 | ||
| 92 | #define I2S_CKR_MDIV(x) ((x - 1) << I2S_CKR_MDIV_SHIFT) | ||
| 93 | #define I2S_CKR_MDIV_MASK (0xff << I2S_CKR_MDIV_SHIFT) | ||
| 94 | #define I2S_CKR_RSD_SHIFT 8 | ||
| 95 | #define I2S_CKR_RSD(x) ((x - 1) << I2S_CKR_RSD_SHIFT) | ||
| 96 | #define I2S_CKR_RSD_MASK (0xff << I2S_CKR_RSD_SHIFT) | ||
| 97 | #define I2S_CKR_TSD_SHIFT 0 | ||
| 98 | #define I2S_CKR_TSD(x) ((x - 1) << I2S_CKR_TSD_SHIFT) | ||
| 99 | #define I2S_CKR_TSD_MASK (0xff << I2S_CKR_TSD_SHIFT) | ||
| 100 | |||
| 101 | /* | ||
| 102 | * FIFOLR | ||
| 103 | * FIFO level register | ||
| 104 | */ | ||
| 105 | #define I2S_FIFOLR_RFL_SHIFT 24 | ||
| 106 | #define I2S_FIFOLR_RFL_MASK (0x3f << I2S_FIFOLR_RFL_SHIFT) | ||
| 107 | #define I2S_FIFOLR_TFL3_SHIFT 18 | ||
| 108 | #define I2S_FIFOLR_TFL3_MASK (0x3f << I2S_FIFOLR_TFL3_SHIFT) | ||
| 109 | #define I2S_FIFOLR_TFL2_SHIFT 12 | ||
| 110 | #define I2S_FIFOLR_TFL2_MASK (0x3f << I2S_FIFOLR_TFL2_SHIFT) | ||
| 111 | #define I2S_FIFOLR_TFL1_SHIFT 6 | ||
| 112 | #define I2S_FIFOLR_TFL1_MASK (0x3f << I2S_FIFOLR_TFL1_SHIFT) | ||
| 113 | #define I2S_FIFOLR_TFL0_SHIFT 0 | ||
| 114 | #define I2S_FIFOLR_TFL0_MASK (0x3f << I2S_FIFOLR_TFL0_SHIFT) | ||
| 115 | |||
| 116 | /* | ||
| 117 | * DMACR | ||
| 118 | * DMA control register | ||
| 119 | */ | ||
| 120 | #define I2S_DMACR_RDE_SHIFT 24 | ||
| 121 | #define I2S_DMACR_RDE_DISABLE (0 << I2S_DMACR_RDE_SHIFT) | ||
| 122 | #define I2S_DMACR_RDE_ENABLE (1 << I2S_DMACR_RDE_SHIFT) | ||
| 123 | #define I2S_DMACR_RDL_SHIFT 16 | ||
| 124 | #define I2S_DMACR_RDL(x) ((x - 1) << I2S_DMACR_RDL_SHIFT) | ||
| 125 | #define I2S_DMACR_RDL_MASK (0x1f << I2S_DMACR_RDL_SHIFT) | ||
| 126 | #define I2S_DMACR_TDE_SHIFT 8 | ||
| 127 | #define I2S_DMACR_TDE_DISABLE (0 << I2S_DMACR_TDE_SHIFT) | ||
| 128 | #define I2S_DMACR_TDE_ENABLE (1 << I2S_DMACR_TDE_SHIFT) | ||
| 129 | #define I2S_DMACR_TDL_SHIFT 0 | ||
| 130 | #define I2S_DMACR_TDL(x) ((x - 1) << I2S_DMACR_TDL_SHIFT) | ||
| 131 | #define I2S_DMACR_TDL_MASK (0x1f << I2S_DMACR_TDL_SHIFT) | ||
| 132 | |||
| 133 | /* | ||
| 134 | * INTCR | ||
| 135 | * interrupt control register | ||
| 136 | */ | ||
| 137 | #define I2S_INTCR_RFT_SHIFT 20 | ||
| 138 | #define I2S_INTCR_RFT(x) ((x - 1) << I2S_INTCR_RFT_SHIFT) | ||
| 139 | #define I2S_INTCR_RXOIC BIT(18) | ||
| 140 | #define I2S_INTCR_RXOIE_SHIFT 17 | ||
| 141 | #define I2S_INTCR_RXOIE_DISABLE (0 << I2S_INTCR_RXOIE_SHIFT) | ||
| 142 | #define I2S_INTCR_RXOIE_ENABLE (1 << I2S_INTCR_RXOIE_SHIFT) | ||
| 143 | #define I2S_INTCR_RXFIE_SHIFT 16 | ||
| 144 | #define I2S_INTCR_RXFIE_DISABLE (0 << I2S_INTCR_RXFIE_SHIFT) | ||
| 145 | #define I2S_INTCR_RXFIE_ENABLE (1 << I2S_INTCR_RXFIE_SHIFT) | ||
| 146 | #define I2S_INTCR_TFT_SHIFT 4 | ||
| 147 | #define I2S_INTCR_TFT(x) ((x - 1) << I2S_INTCR_TFT_SHIFT) | ||
| 148 | #define I2S_INTCR_TFT_MASK (0x1f << I2S_INTCR_TFT_SHIFT) | ||
| 149 | #define I2S_INTCR_TXUIC BIT(2) | ||
| 150 | #define I2S_INTCR_TXUIE_SHIFT 1 | ||
| 151 | #define I2S_INTCR_TXUIE_DISABLE (0 << I2S_INTCR_TXUIE_SHIFT) | ||
| 152 | #define I2S_INTCR_TXUIE_ENABLE (1 << I2S_INTCR_TXUIE_SHIFT) | ||
| 153 | |||
| 154 | /* | ||
| 155 | * INTSR | ||
| 156 | * interrupt status register | ||
| 157 | */ | ||
| 158 | #define I2S_INTSR_TXEIE_SHIFT 0 | ||
| 159 | #define I2S_INTSR_TXEIE_DISABLE (0 << I2S_INTSR_TXEIE_SHIFT) | ||
| 160 | #define I2S_INTSR_TXEIE_ENABLE (1 << I2S_INTSR_TXEIE_SHIFT) | ||
| 161 | #define I2S_INTSR_RXOI_SHIFT 17 | ||
| 162 | #define I2S_INTSR_RXOI_INA (0 << I2S_INTSR_RXOI_SHIFT) | ||
| 163 | #define I2S_INTSR_RXOI_ACT (1 << I2S_INTSR_RXOI_SHIFT) | ||
| 164 | #define I2S_INTSR_RXFI_SHIFT 16 | ||
| 165 | #define I2S_INTSR_RXFI_INA (0 << I2S_INTSR_RXFI_SHIFT) | ||
| 166 | #define I2S_INTSR_RXFI_ACT (1 << I2S_INTSR_RXFI_SHIFT) | ||
| 167 | #define I2S_INTSR_TXUI_SHIFT 1 | ||
| 168 | #define I2S_INTSR_TXUI_INA (0 << I2S_INTSR_TXUI_SHIFT) | ||
| 169 | #define I2S_INTSR_TXUI_ACT (1 << I2S_INTSR_TXUI_SHIFT) | ||
| 170 | #define I2S_INTSR_TXEI_SHIFT 0 | ||
| 171 | #define I2S_INTSR_TXEI_INA (0 << I2S_INTSR_TXEI_SHIFT) | ||
| 172 | #define I2S_INTSR_TXEI_ACT (1 << I2S_INTSR_TXEI_SHIFT) | ||
| 173 | |||
| 174 | /* | ||
| 175 | * XFER | ||
| 176 | * Transfer start register | ||
| 177 | */ | ||
| 178 | #define I2S_XFER_RXS_SHIFT 1 | ||
| 179 | #define I2S_XFER_RXS_STOP (0 << I2S_XFER_RXS_SHIFT) | ||
| 180 | #define I2S_XFER_RXS_START (1 << I2S_XFER_RXS_SHIFT) | ||
| 181 | #define I2S_XFER_TXS_SHIFT 0 | ||
| 182 | #define I2S_XFER_TXS_STOP (0 << I2S_XFER_TXS_SHIFT) | ||
| 183 | #define I2S_XFER_TXS_START (1 << I2S_XFER_TXS_SHIFT) | ||
| 184 | |||
| 185 | /* | ||
| 186 | * CLR | ||
| 187 | * clear SCLK domain logic register | ||
| 188 | */ | ||
| 189 | #define I2S_CLR_RXC BIT(1) | ||
| 190 | #define I2S_CLR_TXC BIT(0) | ||
| 191 | |||
| 192 | /* | ||
| 193 | * TXDR | ||
| 194 | * Transimt FIFO data register, write only. | ||
| 195 | */ | ||
| 196 | #define I2S_TXDR_MASK (0xff) | ||
| 197 | |||
| 198 | /* | ||
| 199 | * RXDR | ||
| 200 | * Receive FIFO data register, write only. | ||
| 201 | */ | ||
| 202 | #define I2S_RXDR_MASK (0xff) | ||
| 203 | |||
| 204 | /* Clock divider id */ | ||
| 205 | enum { | ||
| 206 | ROCKCHIP_DIV_MCLK = 0, | ||
| 207 | ROCKCHIP_DIV_BCLK, | ||
| 208 | }; | ||
| 209 | |||
| 210 | /* I2S REGS */ | ||
| 211 | #define I2S_TXCR (0x0000) | ||
| 212 | #define I2S_RXCR (0x0004) | ||
| 213 | #define I2S_CKR (0x0008) | ||
| 214 | #define I2S_FIFOLR (0x000c) | ||
| 215 | #define I2S_DMACR (0x0010) | ||
| 216 | #define I2S_INTCR (0x0014) | ||
| 217 | #define I2S_INTSR (0x0018) | ||
| 218 | #define I2S_XFER (0x001c) | ||
| 219 | #define I2S_CLR (0x0020) | ||
| 220 | #define I2S_TXDR (0x0024) | ||
| 221 | #define I2S_RXDR (0x0028) | ||
| 222 | |||
| 223 | #endif /* _ROCKCHIP_IIS_H */ | ||
