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 */ | ||