diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt | 155 | ||||
-rw-r--r-- | sound/soc/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/Makefile | 1 | ||||
-rw-r--r-- | sound/soc/codecs/Kconfig | 4 | ||||
-rw-r--r-- | sound/soc/codecs/Makefile | 2 | ||||
-rw-r--r-- | sound/soc/codecs/ssm2518.c | 9 | ||||
-rw-r--r-- | sound/soc/codecs/sta529.c | 3 | ||||
-rw-r--r-- | sound/soc/codecs/sti-sas.c | 628 | ||||
-rw-r--r-- | sound/soc/sti/Kconfig | 11 | ||||
-rw-r--r-- | sound/soc/sti/Makefile | 4 | ||||
-rw-r--r-- | sound/soc/sti/sti_uniperif.c | 254 | ||||
-rw-r--r-- | sound/soc/sti/uniperif.h | 1229 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_player.c | 1110 | ||||
-rw-r--r-- | sound/soc/sti/uniperif_reader.c | 362 |
14 files changed, 3770 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt new file mode 100644 index 000000000000..028fa1c82f50 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,sti-asoc-card.txt | |||
@@ -0,0 +1,155 @@ | |||
1 | STMicroelectronics sti ASoC cards | ||
2 | |||
3 | The sti ASoC Sound Card can be used, for all sti SoCs using internal sti-sas | ||
4 | codec or external codecs. | ||
5 | |||
6 | sti sound drivers allows to expose sti SoC audio interface through the | ||
7 | generic ASoC simple card. For details about sound card declaration please refer to | ||
8 | Documentation/devicetree/bindings/sound/simple-card.txt. | ||
9 | |||
10 | 1) sti-uniperiph-dai: audio dai device. | ||
11 | --------------------------------------- | ||
12 | |||
13 | Required properties: | ||
14 | - compatible: "st,sti-uni-player" or "st,sti-uni-reader" | ||
15 | |||
16 | - st,syscfg: phandle to boot-device system configuration registers | ||
17 | |||
18 | - clock-names: name of the clocks listed in clocks property in the same order | ||
19 | |||
20 | - reg: CPU DAI IP Base address and size entries, listed in same | ||
21 | order than the CPU_DAI properties. | ||
22 | |||
23 | - reg-names: names of the mapped memory regions listed in regs property in | ||
24 | the same order. | ||
25 | |||
26 | - interrupts: CPU_DAI interrupt line, listed in the same order than the | ||
27 | CPU_DAI properties. | ||
28 | |||
29 | - dma: CPU_DAI DMA controller phandle and DMA request line, listed in the same | ||
30 | order than the CPU_DAI properties. | ||
31 | |||
32 | - dma-names: identifier string for each DMA request line in the dmas property. | ||
33 | "tx" for "st,sti-uni-player" compatibility | ||
34 | "rx" for "st,sti-uni-reader" compatibility | ||
35 | |||
36 | - version: IP version integrated in SOC. | ||
37 | |||
38 | - dai-name: DAI name that describes the IP. | ||
39 | |||
40 | Required properties ("st,sti-uni-player" compatibility only): | ||
41 | - clocks: CPU_DAI IP clock source, listed in the same order than the | ||
42 | CPU_DAI properties. | ||
43 | |||
44 | - uniperiph-id: internal SOC IP instance ID. | ||
45 | |||
46 | - IP mode: IP working mode depending on associated codec. | ||
47 | "HDMI" connected to HDMI codec IP and IEC HDMI formats. | ||
48 | "SPDIF"connected to SPDIF codec and support SPDIF formats. | ||
49 | "PCM" PCM standard mode for I2S or TDM bus. | ||
50 | |||
51 | Optional properties: | ||
52 | - pinctrl-0: defined for CPU_DAI@1 and CPU_DAI@4 to describe I2S PIOs for | ||
53 | external codecs connection. | ||
54 | |||
55 | - pinctrl-names: should contain only one value - "default". | ||
56 | |||
57 | Example: | ||
58 | |||
59 | sti_uni_player2: sti-uni-player@2 { | ||
60 | compatible = "st,sti-uni-player"; | ||
61 | status = "okay"; | ||
62 | #sound-dai-cells = <0>; | ||
63 | st,syscfg = <&syscfg_core>; | ||
64 | clocks = <&clk_s_d0_flexgen CLK_PCM_2>; | ||
65 | reg = <0x8D82000 0x158>; | ||
66 | interrupts = <GIC_SPI 86 IRQ_TYPE_NONE>; | ||
67 | dmas = <&fdma0 4 0 1>; | ||
68 | dai-name = "Uni Player #1 (DAC)"; | ||
69 | dma-names = "tx"; | ||
70 | uniperiph-id = <2>; | ||
71 | version = <5>; | ||
72 | mode = "PCM"; | ||
73 | }; | ||
74 | |||
75 | sti_uni_player3: sti-uni-player@3 { | ||
76 | compatible = "st,sti-uni-player"; | ||
77 | status = "okay"; | ||
78 | #sound-dai-cells = <0>; | ||
79 | st,syscfg = <&syscfg_core>; | ||
80 | clocks = <&clk_s_d0_flexgen CLK_SPDIFF>; | ||
81 | reg = <0x8D85000 0x158>; | ||
82 | interrupts = <GIC_SPI 89 IRQ_TYPE_NONE>; | ||
83 | dmas = <&fdma0 7 0 1>; | ||
84 | dma-names = "tx"; | ||
85 | dai-name = "Uni Player #1 (PIO)"; | ||
86 | uniperiph-id = <3>; | ||
87 | version = <5>; | ||
88 | mode = "SPDIF"; | ||
89 | }; | ||
90 | |||
91 | sti_uni_reader1: sti-uni-reader@1 { | ||
92 | compatible = "st,sti-uni-reader"; | ||
93 | status = "disabled"; | ||
94 | #sound-dai-cells = <0>; | ||
95 | st,syscfg = <&syscfg_core>; | ||
96 | reg = <0x8D84000 0x158>; | ||
97 | interrupts = <GIC_SPI 88 IRQ_TYPE_NONE>; | ||
98 | dmas = <&fdma0 6 0 1>; | ||
99 | dma-names = "rx"; | ||
100 | dai-name = "Uni Reader #1 (HDMI RX)"; | ||
101 | version = <3>; | ||
102 | }; | ||
103 | |||
104 | 2) sti-sas-codec: internal audio codec IPs driver | ||
105 | ------------------------------------------------- | ||
106 | |||
107 | Required properties: | ||
108 | - compatible: "st,sti<chip>-sas-codec" . | ||
109 | Should be chip "st,stih416-sas-codec" or "st,stih407-sas-codec" | ||
110 | |||
111 | - st,syscfg: phandle to boot-device system configuration registers. | ||
112 | |||
113 | - pinctrl-0: SPDIF PIO description. | ||
114 | |||
115 | - pinctrl-names: should contain only one value - "default". | ||
116 | |||
117 | Example: | ||
118 | sti_sas_codec: sti-sas-codec { | ||
119 | compatible = "st,stih407-sas-codec"; | ||
120 | #sound-dai-cells = <1>; | ||
121 | st,reg_audio = <&syscfg_core>; | ||
122 | pinctrl-names = "default"; | ||
123 | pinctrl-0 = <&pinctrl_spdif_out >; | ||
124 | }; | ||
125 | |||
126 | Example of audio card declaration: | ||
127 | sound { | ||
128 | compatible = "simple-audio-card"; | ||
129 | simple-audio-card,name = "sti audio card"; | ||
130 | status = "okay"; | ||
131 | |||
132 | simple-audio-card,dai-link@0 { | ||
133 | /* DAC */ | ||
134 | format = "i2s"; | ||
135 | dai-tdm-slot-width = <32>; | ||
136 | cpu { | ||
137 | sound-dai = <&sti_uni_player2>; | ||
138 | }; | ||
139 | |||
140 | codec { | ||
141 | sound-dai = <&sti_sasg_codec 1>; | ||
142 | }; | ||
143 | }; | ||
144 | simple-audio-card,dai-link@1 { | ||
145 | /* SPDIF */ | ||
146 | format = "left_j"; | ||
147 | cpu { | ||
148 | sound-dai = <&sti_uni_player3>; | ||
149 | }; | ||
150 | |||
151 | codec { | ||
152 | sound-dai = <&sti_sasg_codec 0>; | ||
153 | }; | ||
154 | }; | ||
155 | }; | ||
diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig index 1d651b8a8957..225bfda414e9 100644 --- a/sound/soc/Kconfig +++ b/sound/soc/Kconfig | |||
@@ -57,6 +57,7 @@ source "sound/soc/samsung/Kconfig" | |||
57 | source "sound/soc/sh/Kconfig" | 57 | source "sound/soc/sh/Kconfig" |
58 | source "sound/soc/sirf/Kconfig" | 58 | source "sound/soc/sirf/Kconfig" |
59 | source "sound/soc/spear/Kconfig" | 59 | source "sound/soc/spear/Kconfig" |
60 | source "sound/soc/sti/Kconfig" | ||
60 | source "sound/soc/tegra/Kconfig" | 61 | source "sound/soc/tegra/Kconfig" |
61 | source "sound/soc/txx9/Kconfig" | 62 | source "sound/soc/txx9/Kconfig" |
62 | source "sound/soc/ux500/Kconfig" | 63 | source "sound/soc/ux500/Kconfig" |
diff --git a/sound/soc/Makefile b/sound/soc/Makefile index 669648b41d30..134aca150a50 100644 --- a/sound/soc/Makefile +++ b/sound/soc/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_SND_SOC) += samsung/ | |||
39 | obj-$(CONFIG_SND_SOC) += sh/ | 39 | obj-$(CONFIG_SND_SOC) += sh/ |
40 | obj-$(CONFIG_SND_SOC) += sirf/ | 40 | obj-$(CONFIG_SND_SOC) += sirf/ |
41 | obj-$(CONFIG_SND_SOC) += spear/ | 41 | obj-$(CONFIG_SND_SOC) += spear/ |
42 | obj-$(CONFIG_SND_SOC) += sti/ | ||
42 | obj-$(CONFIG_SND_SOC) += tegra/ | 43 | obj-$(CONFIG_SND_SOC) += tegra/ |
43 | obj-$(CONFIG_SND_SOC) += txx9/ | 44 | obj-$(CONFIG_SND_SOC) += txx9/ |
44 | obj-$(CONFIG_SND_SOC) += ux500/ | 45 | obj-$(CONFIG_SND_SOC) += ux500/ |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 6fd467cde101..0c9733ecd17f 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
@@ -106,6 +106,7 @@ config SND_SOC_ALL_CODECS | |||
106 | select SND_SOC_STA350 if I2C | 106 | select SND_SOC_STA350 if I2C |
107 | select SND_SOC_STA529 if I2C | 107 | select SND_SOC_STA529 if I2C |
108 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS | 108 | select SND_SOC_STAC9766 if SND_SOC_AC97_BUS |
109 | select SND_SOC_STI_SAS | ||
109 | select SND_SOC_TAS2552 if I2C | 110 | select SND_SOC_TAS2552 if I2C |
110 | select SND_SOC_TAS5086 if I2C | 111 | select SND_SOC_TAS5086 if I2C |
111 | select SND_SOC_TAS571X if I2C | 112 | select SND_SOC_TAS571X if I2C |
@@ -631,6 +632,9 @@ config SND_SOC_STA529 | |||
631 | config SND_SOC_STAC9766 | 632 | config SND_SOC_STAC9766 |
632 | tristate | 633 | tristate |
633 | 634 | ||
635 | config SND_SOC_STI_SAS | ||
636 | tristate "codec Audio support for STI SAS codec" | ||
637 | |||
634 | config SND_SOC_TAS2552 | 638 | config SND_SOC_TAS2552 |
635 | tristate "Texas Instruments TAS2552 Mono Audio amplifier" | 639 | tristate "Texas Instruments TAS2552 Mono Audio amplifier" |
636 | depends on I2C | 640 | depends on I2C |
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index f65bd7b0e97e..4a32077954ae 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
@@ -110,6 +110,7 @@ snd-soc-sta32x-objs := sta32x.o | |||
110 | snd-soc-sta350-objs := sta350.o | 110 | snd-soc-sta350-objs := sta350.o |
111 | snd-soc-sta529-objs := sta529.o | 111 | snd-soc-sta529-objs := sta529.o |
112 | snd-soc-stac9766-objs := stac9766.o | 112 | snd-soc-stac9766-objs := stac9766.o |
113 | snd-soc-sti-sas-objs := sti-sas.o | ||
113 | snd-soc-tas5086-objs := tas5086.o | 114 | snd-soc-tas5086-objs := tas5086.o |
114 | snd-soc-tas571x-objs := tas571x.o | 115 | snd-soc-tas571x-objs := tas571x.o |
115 | snd-soc-tfa9879-objs := tfa9879.o | 116 | snd-soc-tfa9879-objs := tfa9879.o |
@@ -297,6 +298,7 @@ obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o | |||
297 | obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o | 298 | obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o |
298 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o | 299 | obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o |
299 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o | 300 | obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o |
301 | obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o | ||
300 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o | 302 | obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o |
301 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o | 303 | obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o |
302 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o | 304 | obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o |
diff --git a/sound/soc/codecs/ssm2518.c b/sound/soc/codecs/ssm2518.c index 5d94d6c7ad33..ddb0203fc649 100644 --- a/sound/soc/codecs/ssm2518.c +++ b/sound/soc/codecs/ssm2518.c | |||
@@ -806,6 +806,14 @@ static int ssm2518_i2c_remove(struct i2c_client *client) | |||
806 | return 0; | 806 | return 0; |
807 | } | 807 | } |
808 | 808 | ||
809 | #ifdef CONFIG_OF | ||
810 | static const struct of_device_id ssm2518_dt_ids[] = { | ||
811 | { .compatible = "adi,ssm2518", }, | ||
812 | { } | ||
813 | }; | ||
814 | MODULE_DEVICE_TABLE(of, ssm2518_dt_ids); | ||
815 | #endif | ||
816 | |||
809 | static const struct i2c_device_id ssm2518_i2c_ids[] = { | 817 | static const struct i2c_device_id ssm2518_i2c_ids[] = { |
810 | { "ssm2518", 0 }, | 818 | { "ssm2518", 0 }, |
811 | { } | 819 | { } |
@@ -815,6 +823,7 @@ MODULE_DEVICE_TABLE(i2c, ssm2518_i2c_ids); | |||
815 | static struct i2c_driver ssm2518_driver = { | 823 | static struct i2c_driver ssm2518_driver = { |
816 | .driver = { | 824 | .driver = { |
817 | .name = "ssm2518", | 825 | .name = "ssm2518", |
826 | .of_match_table = of_match_ptr(ssm2518_dt_ids), | ||
818 | }, | 827 | }, |
819 | .probe = ssm2518_i2c_probe, | 828 | .probe = ssm2518_i2c_probe, |
820 | .remove = ssm2518_i2c_remove, | 829 | .remove = ssm2518_i2c_remove, |
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c index 3430f444c1ae..2cdaca943a8c 100644 --- a/sound/soc/codecs/sta529.c +++ b/sound/soc/codecs/sta529.c | |||
@@ -339,9 +339,6 @@ static int sta529_i2c_probe(struct i2c_client *i2c, | |||
339 | struct sta529 *sta529; | 339 | struct sta529 *sta529; |
340 | int ret; | 340 | int ret; |
341 | 341 | ||
342 | if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) | ||
343 | return -EINVAL; | ||
344 | |||
345 | sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL); | 342 | sta529 = devm_kzalloc(&i2c->dev, sizeof(struct sta529), GFP_KERNEL); |
346 | if (!sta529) | 343 | if (!sta529) |
347 | return -ENOMEM; | 344 | return -ENOMEM; |
diff --git a/sound/soc/codecs/sti-sas.c b/sound/soc/codecs/sti-sas.c new file mode 100644 index 000000000000..160d61a66204 --- /dev/null +++ b/sound/soc/codecs/sti-sas.c | |||
@@ -0,0 +1,628 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> | ||
4 | * for STMicroelectronics. | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/io.h> | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/regmap.h> | ||
11 | #include <linux/reset.h> | ||
12 | #include <linux/mfd/syscon.h> | ||
13 | |||
14 | #include <sound/soc.h> | ||
15 | #include <sound/soc-dapm.h> | ||
16 | |||
17 | /* chipID supported */ | ||
18 | #define CHIPID_STIH416 0 | ||
19 | #define CHIPID_STIH407 1 | ||
20 | |||
21 | /* DAC definitions */ | ||
22 | |||
23 | /* stih416 DAC registers */ | ||
24 | /* sysconf 2517: Audio-DAC-Control */ | ||
25 | #define STIH416_AUDIO_DAC_CTRL 0x00000814 | ||
26 | /* sysconf 2519: Audio-Gue-Control */ | ||
27 | #define STIH416_AUDIO_GLUE_CTRL 0x0000081C | ||
28 | |||
29 | #define STIH416_DAC_NOT_STANDBY 0x3 | ||
30 | #define STIH416_DAC_SOFTMUTE 0x4 | ||
31 | #define STIH416_DAC_ANA_NOT_PWR 0x5 | ||
32 | #define STIH416_DAC_NOT_PNDBG 0x6 | ||
33 | |||
34 | #define STIH416_DAC_NOT_STANDBY_MASK BIT(STIH416_DAC_NOT_STANDBY) | ||
35 | #define STIH416_DAC_SOFTMUTE_MASK BIT(STIH416_DAC_SOFTMUTE) | ||
36 | #define STIH416_DAC_ANA_NOT_PWR_MASK BIT(STIH416_DAC_ANA_NOT_PWR) | ||
37 | #define STIH416_DAC_NOT_PNDBG_MASK BIT(STIH416_DAC_NOT_PNDBG) | ||
38 | |||
39 | /* stih407 DAC registers */ | ||
40 | /* sysconf 5041: Audio-Gue-Control */ | ||
41 | #define STIH407_AUDIO_GLUE_CTRL 0x000000A4 | ||
42 | /* sysconf 5042: Audio-DAC-Control */ | ||
43 | #define STIH407_AUDIO_DAC_CTRL 0x000000A8 | ||
44 | |||
45 | /* DAC definitions */ | ||
46 | #define STIH407_DAC_SOFTMUTE 0x0 | ||
47 | #define STIH407_DAC_STANDBY_ANA 0x1 | ||
48 | #define STIH407_DAC_STANDBY 0x2 | ||
49 | |||
50 | #define STIH407_DAC_SOFTMUTE_MASK BIT(STIH407_DAC_SOFTMUTE) | ||
51 | #define STIH407_DAC_STANDBY_ANA_MASK BIT(STIH407_DAC_STANDBY_ANA) | ||
52 | #define STIH407_DAC_STANDBY_MASK BIT(STIH407_DAC_STANDBY) | ||
53 | |||
54 | /* SPDIF definitions */ | ||
55 | #define SPDIF_BIPHASE_ENABLE 0x6 | ||
56 | #define SPDIF_BIPHASE_IDLE 0x7 | ||
57 | |||
58 | #define SPDIF_BIPHASE_ENABLE_MASK BIT(SPDIF_BIPHASE_ENABLE) | ||
59 | #define SPDIF_BIPHASE_IDLE_MASK BIT(SPDIF_BIPHASE_IDLE) | ||
60 | |||
61 | enum { | ||
62 | STI_SAS_DAI_SPDIF_OUT, | ||
63 | STI_SAS_DAI_ANALOG_OUT, | ||
64 | }; | ||
65 | |||
66 | static const struct reg_default stih416_sas_reg_defaults[] = { | ||
67 | { STIH407_AUDIO_GLUE_CTRL, 0x00000040 }, | ||
68 | { STIH407_AUDIO_DAC_CTRL, 0x000000000 }, | ||
69 | }; | ||
70 | |||
71 | static const struct reg_default stih407_sas_reg_defaults[] = { | ||
72 | { STIH416_AUDIO_DAC_CTRL, 0x000000000 }, | ||
73 | { STIH416_AUDIO_GLUE_CTRL, 0x00000040 }, | ||
74 | }; | ||
75 | |||
76 | struct sti_dac_audio { | ||
77 | struct regmap *regmap; | ||
78 | struct regmap *virt_regmap; | ||
79 | struct regmap_field **field; | ||
80 | struct reset_control *rst; | ||
81 | int mclk; | ||
82 | }; | ||
83 | |||
84 | struct sti_spdif_audio { | ||
85 | struct regmap *regmap; | ||
86 | struct regmap_field **field; | ||
87 | int mclk; | ||
88 | }; | ||
89 | |||
90 | /* device data structure */ | ||
91 | struct sti_sas_dev_data { | ||
92 | const int chipid; /* IC version */ | ||
93 | const struct regmap_config *regmap; | ||
94 | const struct snd_soc_dai_ops *dac_ops; /* DAC function callbacks */ | ||
95 | const struct snd_soc_dapm_widget *dapm_widgets; /* dapms declaration */ | ||
96 | const int num_dapm_widgets; /* dapms declaration */ | ||
97 | const struct snd_soc_dapm_route *dapm_routes; /* route declaration */ | ||
98 | const int num_dapm_routes; /* route declaration */ | ||
99 | }; | ||
100 | |||
101 | /* driver data structure */ | ||
102 | struct sti_sas_data { | ||
103 | struct device *dev; | ||
104 | const struct sti_sas_dev_data *dev_data; | ||
105 | struct sti_dac_audio dac; | ||
106 | struct sti_spdif_audio spdif; | ||
107 | }; | ||
108 | |||
109 | /* Read a register from the sysconf reg bank */ | ||
110 | static int sti_sas_read_reg(void *context, unsigned int reg, | ||
111 | unsigned int *value) | ||
112 | { | ||
113 | struct sti_sas_data *drvdata = context; | ||
114 | int status; | ||
115 | u32 val; | ||
116 | |||
117 | status = regmap_read(drvdata->dac.regmap, reg, &val); | ||
118 | *value = (unsigned int)val; | ||
119 | |||
120 | return status; | ||
121 | } | ||
122 | |||
123 | /* Read a register from the sysconf reg bank */ | ||
124 | static int sti_sas_write_reg(void *context, unsigned int reg, | ||
125 | unsigned int value) | ||
126 | { | ||
127 | struct sti_sas_data *drvdata = context; | ||
128 | int status; | ||
129 | |||
130 | status = regmap_write(drvdata->dac.regmap, reg, value); | ||
131 | |||
132 | return status; | ||
133 | } | ||
134 | |||
135 | static int sti_sas_init_sas_registers(struct snd_soc_codec *codec, | ||
136 | struct sti_sas_data *data) | ||
137 | { | ||
138 | int ret; | ||
139 | /* | ||
140 | * DAC and SPDIF are activated by default | ||
141 | * put them in IDLE to save power | ||
142 | */ | ||
143 | |||
144 | /* Initialise bi-phase formatter to disabled */ | ||
145 | ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, | ||
146 | SPDIF_BIPHASE_ENABLE_MASK, 0); | ||
147 | |||
148 | if (!ret) | ||
149 | /* Initialise bi-phase formatter idle value to 0 */ | ||
150 | ret = snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, | ||
151 | SPDIF_BIPHASE_IDLE_MASK, 0); | ||
152 | if (ret < 0) { | ||
153 | dev_err(codec->dev, "Failed to update SPDIF registers"); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | /* Init DAC configuration */ | ||
158 | switch (data->dev_data->chipid) { | ||
159 | case CHIPID_STIH407: | ||
160 | /* init configuration */ | ||
161 | ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, | ||
162 | STIH407_DAC_STANDBY_MASK, | ||
163 | STIH407_DAC_STANDBY_MASK); | ||
164 | |||
165 | if (!ret) | ||
166 | ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, | ||
167 | STIH407_DAC_STANDBY_ANA_MASK, | ||
168 | STIH407_DAC_STANDBY_ANA_MASK); | ||
169 | if (!ret) | ||
170 | ret = snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, | ||
171 | STIH407_DAC_SOFTMUTE_MASK, | ||
172 | STIH407_DAC_SOFTMUTE_MASK); | ||
173 | break; | ||
174 | case CHIPID_STIH416: | ||
175 | ret = snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, | ||
176 | STIH416_DAC_NOT_STANDBY_MASK, 0); | ||
177 | if (!ret) | ||
178 | ret = snd_soc_update_bits(codec, | ||
179 | STIH416_AUDIO_DAC_CTRL, | ||
180 | STIH416_DAC_ANA_NOT_PWR, 0); | ||
181 | if (!ret) | ||
182 | ret = snd_soc_update_bits(codec, | ||
183 | STIH416_AUDIO_DAC_CTRL, | ||
184 | STIH416_DAC_NOT_PNDBG_MASK, | ||
185 | 0); | ||
186 | if (!ret) | ||
187 | ret = snd_soc_update_bits(codec, | ||
188 | STIH416_AUDIO_DAC_CTRL, | ||
189 | STIH416_DAC_SOFTMUTE_MASK, | ||
190 | STIH416_DAC_SOFTMUTE_MASK); | ||
191 | break; | ||
192 | default: | ||
193 | return -EINVAL; | ||
194 | } | ||
195 | |||
196 | if (ret < 0) { | ||
197 | dev_err(codec->dev, "Failed to update DAC registers"); | ||
198 | return ret; | ||
199 | } | ||
200 | |||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * DAC | ||
206 | */ | ||
207 | static int sti_sas_dac_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
208 | { | ||
209 | /* Sanity check only */ | ||
210 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { | ||
211 | dev_err(dai->codec->dev, | ||
212 | "%s: ERROR: Unsupporter master mask 0x%x\n", | ||
213 | __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int stih416_dac_probe(struct snd_soc_dai *dai) | ||
221 | { | ||
222 | struct snd_soc_codec *codec = dai->codec; | ||
223 | struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); | ||
224 | struct sti_dac_audio *dac = &drvdata->dac; | ||
225 | |||
226 | /* Get reset control */ | ||
227 | dac->rst = devm_reset_control_get(codec->dev, "dac_rst"); | ||
228 | if (IS_ERR(dac->rst)) { | ||
229 | dev_err(dai->codec->dev, | ||
230 | "%s: ERROR: DAC reset control not defined !\n", | ||
231 | __func__); | ||
232 | dac->rst = NULL; | ||
233 | return -EFAULT; | ||
234 | } | ||
235 | /* Put the DAC into reset */ | ||
236 | reset_control_assert(dac->rst); | ||
237 | |||
238 | return 0; | ||
239 | } | ||
240 | |||
241 | static const struct snd_soc_dapm_widget stih416_sas_dapm_widgets[] = { | ||
242 | SND_SOC_DAPM_PGA("DAC bandgap", STIH416_AUDIO_DAC_CTRL, | ||
243 | STIH416_DAC_NOT_PNDBG_MASK, 0, NULL, 0), | ||
244 | SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH416_AUDIO_DAC_CTRL, | ||
245 | STIH416_DAC_ANA_NOT_PWR, 0, NULL, 0), | ||
246 | SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH416_AUDIO_DAC_CTRL, | ||
247 | STIH416_DAC_NOT_STANDBY, 0), | ||
248 | SND_SOC_DAPM_OUTPUT("DAC Output"), | ||
249 | }; | ||
250 | |||
251 | static const struct snd_soc_dapm_widget stih407_sas_dapm_widgets[] = { | ||
252 | SND_SOC_DAPM_OUT_DRV("DAC standby ana", STIH407_AUDIO_DAC_CTRL, | ||
253 | STIH407_DAC_STANDBY_ANA, 1, NULL, 0), | ||
254 | SND_SOC_DAPM_DAC("DAC standby", "dac_p", STIH407_AUDIO_DAC_CTRL, | ||
255 | STIH407_DAC_STANDBY, 1), | ||
256 | SND_SOC_DAPM_OUTPUT("DAC Output"), | ||
257 | }; | ||
258 | |||
259 | static const struct snd_soc_dapm_route stih416_sas_route[] = { | ||
260 | {"DAC Output", NULL, "DAC bandgap"}, | ||
261 | {"DAC Output", NULL, "DAC standby ana"}, | ||
262 | {"DAC standby ana", NULL, "DAC standby"}, | ||
263 | }; | ||
264 | |||
265 | static const struct snd_soc_dapm_route stih407_sas_route[] = { | ||
266 | {"DAC Output", NULL, "DAC standby ana"}, | ||
267 | {"DAC standby ana", NULL, "DAC standby"}, | ||
268 | }; | ||
269 | |||
270 | static int stih416_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) | ||
271 | { | ||
272 | struct snd_soc_codec *codec = dai->codec; | ||
273 | |||
274 | if (mute) { | ||
275 | return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, | ||
276 | STIH416_DAC_SOFTMUTE_MASK, | ||
277 | STIH416_DAC_SOFTMUTE_MASK); | ||
278 | } else { | ||
279 | return snd_soc_update_bits(codec, STIH416_AUDIO_DAC_CTRL, | ||
280 | STIH416_DAC_SOFTMUTE_MASK, 0); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static int stih407_sas_dac_mute(struct snd_soc_dai *dai, int mute, int stream) | ||
285 | { | ||
286 | struct snd_soc_codec *codec = dai->codec; | ||
287 | |||
288 | if (mute) { | ||
289 | return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, | ||
290 | STIH407_DAC_SOFTMUTE_MASK, | ||
291 | STIH407_DAC_SOFTMUTE_MASK); | ||
292 | } else { | ||
293 | return snd_soc_update_bits(codec, STIH407_AUDIO_DAC_CTRL, | ||
294 | STIH407_DAC_SOFTMUTE_MASK, | ||
295 | 0); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * SPDIF | ||
301 | */ | ||
302 | static int sti_sas_spdif_set_fmt(struct snd_soc_dai *dai, | ||
303 | unsigned int fmt) | ||
304 | { | ||
305 | if ((fmt & SND_SOC_DAIFMT_MASTER_MASK) != SND_SOC_DAIFMT_CBS_CFS) { | ||
306 | dev_err(dai->codec->dev, | ||
307 | "%s: ERROR: Unsupporter master mask 0x%x\n", | ||
308 | __func__, fmt & SND_SOC_DAIFMT_MASTER_MASK); | ||
309 | return -EINVAL; | ||
310 | } | ||
311 | |||
312 | return 0; | ||
313 | } | ||
314 | |||
315 | /* | ||
316 | * sti_sas_spdif_trigger: | ||
317 | * Trigger function is used to ensure that BiPhase Formater is disabled | ||
318 | * before CPU dai is stopped. | ||
319 | * This is mandatory to avoid that BPF is stalled | ||
320 | */ | ||
321 | static int sti_sas_spdif_trigger(struct snd_pcm_substream *substream, int cmd, | ||
322 | struct snd_soc_dai *dai) | ||
323 | { | ||
324 | struct snd_soc_codec *codec = dai->codec; | ||
325 | |||
326 | switch (cmd) { | ||
327 | case SNDRV_PCM_TRIGGER_START: | ||
328 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
329 | return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, | ||
330 | SPDIF_BIPHASE_ENABLE_MASK, | ||
331 | SPDIF_BIPHASE_ENABLE_MASK); | ||
332 | case SNDRV_PCM_TRIGGER_RESUME: | ||
333 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
334 | case SNDRV_PCM_TRIGGER_STOP: | ||
335 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
336 | return snd_soc_update_bits(codec, STIH407_AUDIO_GLUE_CTRL, | ||
337 | SPDIF_BIPHASE_ENABLE_MASK, | ||
338 | 0); | ||
339 | default: | ||
340 | return -EINVAL; | ||
341 | } | ||
342 | } | ||
343 | |||
344 | static bool sti_sas_volatile_register(struct device *dev, unsigned int reg) | ||
345 | { | ||
346 | if (reg == STIH407_AUDIO_GLUE_CTRL) | ||
347 | return true; | ||
348 | |||
349 | return false; | ||
350 | } | ||
351 | |||
352 | /* | ||
353 | * CODEC DAIS | ||
354 | */ | ||
355 | |||
356 | /* | ||
357 | * sti_sas_set_sysclk: | ||
358 | * get MCLK input frequency to check that MCLK-FS ratio is coherent | ||
359 | */ | ||
360 | static int sti_sas_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
361 | unsigned int freq, int dir) | ||
362 | { | ||
363 | struct snd_soc_codec *codec = dai->codec; | ||
364 | struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); | ||
365 | |||
366 | if (dir == SND_SOC_CLOCK_OUT) | ||
367 | return 0; | ||
368 | |||
369 | if (clk_id != 0) | ||
370 | return -EINVAL; | ||
371 | |||
372 | switch (dai->id) { | ||
373 | case STI_SAS_DAI_SPDIF_OUT: | ||
374 | drvdata->spdif.mclk = freq; | ||
375 | break; | ||
376 | |||
377 | case STI_SAS_DAI_ANALOG_OUT: | ||
378 | drvdata->dac.mclk = freq; | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | return 0; | ||
383 | } | ||
384 | |||
385 | static int sti_sas_prepare(struct snd_pcm_substream *substream, | ||
386 | struct snd_soc_dai *dai) | ||
387 | { | ||
388 | struct snd_soc_codec *codec = dai->codec; | ||
389 | struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); | ||
390 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
391 | |||
392 | switch (dai->id) { | ||
393 | case STI_SAS_DAI_SPDIF_OUT: | ||
394 | if ((drvdata->spdif.mclk / runtime->rate) != 128) { | ||
395 | dev_err(codec->dev, "unexpected mclk-fs ratio"); | ||
396 | return -EINVAL; | ||
397 | } | ||
398 | break; | ||
399 | case STI_SAS_DAI_ANALOG_OUT: | ||
400 | if ((drvdata->dac.mclk / runtime->rate) != 256) { | ||
401 | dev_err(codec->dev, "unexpected mclk-fs ratio"); | ||
402 | return -EINVAL; | ||
403 | } | ||
404 | break; | ||
405 | } | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | static const struct snd_soc_dai_ops stih416_dac_ops = { | ||
411 | .set_fmt = sti_sas_dac_set_fmt, | ||
412 | .mute_stream = stih416_sas_dac_mute, | ||
413 | .prepare = sti_sas_prepare, | ||
414 | .set_sysclk = sti_sas_set_sysclk, | ||
415 | }; | ||
416 | |||
417 | static const struct snd_soc_dai_ops stih407_dac_ops = { | ||
418 | .set_fmt = sti_sas_dac_set_fmt, | ||
419 | .mute_stream = stih407_sas_dac_mute, | ||
420 | .prepare = sti_sas_prepare, | ||
421 | .set_sysclk = sti_sas_set_sysclk, | ||
422 | }; | ||
423 | |||
424 | static const struct regmap_config stih407_sas_regmap = { | ||
425 | .reg_bits = 32, | ||
426 | .val_bits = 32, | ||
427 | |||
428 | .max_register = STIH407_AUDIO_DAC_CTRL, | ||
429 | .reg_defaults = stih407_sas_reg_defaults, | ||
430 | .num_reg_defaults = ARRAY_SIZE(stih407_sas_reg_defaults), | ||
431 | .volatile_reg = sti_sas_volatile_register, | ||
432 | .cache_type = REGCACHE_RBTREE, | ||
433 | .reg_read = sti_sas_read_reg, | ||
434 | .reg_write = sti_sas_write_reg, | ||
435 | }; | ||
436 | |||
437 | static const struct regmap_config stih416_sas_regmap = { | ||
438 | .reg_bits = 32, | ||
439 | .val_bits = 32, | ||
440 | |||
441 | .max_register = STIH416_AUDIO_DAC_CTRL, | ||
442 | .reg_defaults = stih416_sas_reg_defaults, | ||
443 | .num_reg_defaults = ARRAY_SIZE(stih416_sas_reg_defaults), | ||
444 | .volatile_reg = sti_sas_volatile_register, | ||
445 | .cache_type = REGCACHE_RBTREE, | ||
446 | .reg_read = sti_sas_read_reg, | ||
447 | .reg_write = sti_sas_write_reg, | ||
448 | }; | ||
449 | |||
450 | static const struct sti_sas_dev_data stih416_data = { | ||
451 | .chipid = CHIPID_STIH416, | ||
452 | .regmap = &stih416_sas_regmap, | ||
453 | .dac_ops = &stih416_dac_ops, | ||
454 | .dapm_widgets = stih416_sas_dapm_widgets, | ||
455 | .num_dapm_widgets = ARRAY_SIZE(stih416_sas_dapm_widgets), | ||
456 | .dapm_routes = stih416_sas_route, | ||
457 | .num_dapm_routes = ARRAY_SIZE(stih416_sas_route), | ||
458 | }; | ||
459 | |||
460 | static const struct sti_sas_dev_data stih407_data = { | ||
461 | .chipid = CHIPID_STIH407, | ||
462 | .regmap = &stih407_sas_regmap, | ||
463 | .dac_ops = &stih407_dac_ops, | ||
464 | .dapm_widgets = stih407_sas_dapm_widgets, | ||
465 | .num_dapm_widgets = ARRAY_SIZE(stih407_sas_dapm_widgets), | ||
466 | .dapm_routes = stih407_sas_route, | ||
467 | .num_dapm_routes = ARRAY_SIZE(stih407_sas_route), | ||
468 | }; | ||
469 | |||
470 | static struct snd_soc_dai_driver sti_sas_dai[] = { | ||
471 | { | ||
472 | .name = "sas-dai-spdif-out", | ||
473 | .id = STI_SAS_DAI_SPDIF_OUT, | ||
474 | .playback = { | ||
475 | .stream_name = "spdif_p", | ||
476 | .channels_min = 2, | ||
477 | .channels_max = 2, | ||
478 | .rates = SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 | | ||
479 | SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_64000 | | ||
480 | SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | | ||
481 | SNDRV_PCM_RATE_192000, | ||
482 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
483 | SNDRV_PCM_FMTBIT_S32_LE, | ||
484 | }, | ||
485 | .ops = (struct snd_soc_dai_ops[]) { | ||
486 | { | ||
487 | .set_fmt = sti_sas_spdif_set_fmt, | ||
488 | .trigger = sti_sas_spdif_trigger, | ||
489 | .set_sysclk = sti_sas_set_sysclk, | ||
490 | .prepare = sti_sas_prepare, | ||
491 | } | ||
492 | }, | ||
493 | }, | ||
494 | { | ||
495 | .name = "sas-dai-dac", | ||
496 | .id = STI_SAS_DAI_ANALOG_OUT, | ||
497 | .playback = { | ||
498 | .stream_name = "dac_p", | ||
499 | .channels_min = 2, | ||
500 | .channels_max = 2, | ||
501 | .rates = SNDRV_PCM_RATE_8000_48000, | ||
502 | .formats = SNDRV_PCM_FMTBIT_S16_LE | | ||
503 | SNDRV_PCM_FMTBIT_S32_LE, | ||
504 | }, | ||
505 | }, | ||
506 | }; | ||
507 | |||
508 | #ifdef CONFIG_PM_SLEEP | ||
509 | static int sti_sas_resume(struct snd_soc_codec *codec) | ||
510 | { | ||
511 | struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); | ||
512 | |||
513 | return sti_sas_init_sas_registers(codec, drvdata); | ||
514 | } | ||
515 | #else | ||
516 | #define sti_sas_resume NULL | ||
517 | #endif | ||
518 | |||
519 | static int sti_sas_codec_probe(struct snd_soc_codec *codec) | ||
520 | { | ||
521 | struct sti_sas_data *drvdata = dev_get_drvdata(codec->dev); | ||
522 | int ret; | ||
523 | |||
524 | ret = sti_sas_init_sas_registers(codec, drvdata); | ||
525 | |||
526 | return ret; | ||
527 | } | ||
528 | |||
529 | static struct snd_soc_codec_driver sti_sas_driver = { | ||
530 | .probe = sti_sas_codec_probe, | ||
531 | .resume = sti_sas_resume, | ||
532 | }; | ||
533 | |||
534 | static const struct of_device_id sti_sas_dev_match[] = { | ||
535 | { | ||
536 | .compatible = "st,stih416-sas-codec", | ||
537 | .data = &stih416_data, | ||
538 | }, | ||
539 | { | ||
540 | .compatible = "st,stih407-sas-codec", | ||
541 | .data = &stih407_data, | ||
542 | }, | ||
543 | {}, | ||
544 | }; | ||
545 | |||
546 | static int sti_sas_driver_probe(struct platform_device *pdev) | ||
547 | { | ||
548 | struct device_node *pnode = pdev->dev.of_node; | ||
549 | struct sti_sas_data *drvdata; | ||
550 | const struct of_device_id *of_id; | ||
551 | |||
552 | /* Allocate device structure */ | ||
553 | drvdata = devm_kzalloc(&pdev->dev, sizeof(struct sti_sas_data), | ||
554 | GFP_KERNEL); | ||
555 | if (!drvdata) | ||
556 | return -ENOMEM; | ||
557 | |||
558 | /* Populate data structure depending on compatibility */ | ||
559 | of_id = of_match_node(sti_sas_dev_match, pnode); | ||
560 | if (!of_id->data) { | ||
561 | dev_err(&pdev->dev, "data associated to device is missing"); | ||
562 | return -EINVAL; | ||
563 | } | ||
564 | |||
565 | drvdata->dev_data = (struct sti_sas_dev_data *)of_id->data; | ||
566 | |||
567 | /* Initialise device structure */ | ||
568 | drvdata->dev = &pdev->dev; | ||
569 | |||
570 | /* Request the DAC & SPDIF registers memory region */ | ||
571 | drvdata->dac.virt_regmap = devm_regmap_init(&pdev->dev, NULL, drvdata, | ||
572 | drvdata->dev_data->regmap); | ||
573 | if (IS_ERR(drvdata->dac.virt_regmap)) { | ||
574 | dev_err(&pdev->dev, "audio registers not enabled\n"); | ||
575 | return PTR_ERR(drvdata->dac.virt_regmap); | ||
576 | } | ||
577 | |||
578 | /* Request the syscon region */ | ||
579 | drvdata->dac.regmap = | ||
580 | syscon_regmap_lookup_by_phandle(pnode, "st,syscfg"); | ||
581 | if (IS_ERR(drvdata->dac.regmap)) { | ||
582 | dev_err(&pdev->dev, "syscon registers not available\n"); | ||
583 | return PTR_ERR(drvdata->dac.regmap); | ||
584 | } | ||
585 | drvdata->spdif.regmap = drvdata->dac.regmap; | ||
586 | |||
587 | /* Set DAC dai probe */ | ||
588 | if (drvdata->dev_data->chipid == CHIPID_STIH416) | ||
589 | sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].probe = stih416_dac_probe; | ||
590 | |||
591 | sti_sas_dai[STI_SAS_DAI_ANALOG_OUT].ops = drvdata->dev_data->dac_ops; | ||
592 | |||
593 | /* Set dapms*/ | ||
594 | sti_sas_driver.dapm_widgets = drvdata->dev_data->dapm_widgets; | ||
595 | sti_sas_driver.num_dapm_widgets = drvdata->dev_data->num_dapm_widgets; | ||
596 | |||
597 | sti_sas_driver.dapm_routes = drvdata->dev_data->dapm_routes; | ||
598 | sti_sas_driver.num_dapm_routes = drvdata->dev_data->num_dapm_routes; | ||
599 | |||
600 | /* Store context */ | ||
601 | dev_set_drvdata(&pdev->dev, drvdata); | ||
602 | |||
603 | return snd_soc_register_codec(&pdev->dev, &sti_sas_driver, | ||
604 | sti_sas_dai, | ||
605 | ARRAY_SIZE(sti_sas_dai)); | ||
606 | } | ||
607 | |||
608 | static int sti_sas_driver_remove(struct platform_device *pdev) | ||
609 | { | ||
610 | snd_soc_unregister_codec(&pdev->dev); | ||
611 | |||
612 | return 0; | ||
613 | } | ||
614 | |||
615 | static struct platform_driver sti_sas_platform_driver = { | ||
616 | .driver = { | ||
617 | .name = "sti-sas-codec", | ||
618 | .of_match_table = sti_sas_dev_match, | ||
619 | }, | ||
620 | .probe = sti_sas_driver_probe, | ||
621 | .remove = sti_sas_driver_remove, | ||
622 | }; | ||
623 | |||
624 | module_platform_driver(sti_sas_platform_driver); | ||
625 | |||
626 | MODULE_DESCRIPTION("audio codec for STMicroelectronics sti platforms"); | ||
627 | MODULE_AUTHOR("Arnaud.pouliquen@st.com"); | ||
628 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/sti/Kconfig b/sound/soc/sti/Kconfig new file mode 100644 index 000000000000..64a690077023 --- /dev/null +++ b/sound/soc/sti/Kconfig | |||
@@ -0,0 +1,11 @@ | |||
1 | # | ||
2 | # STM SoC audio configuration | ||
3 | # | ||
4 | menuconfig SND_SOC_STI | ||
5 | tristate "SoC Audio support for STI System-On-Chip" | ||
6 | depends on SND_SOC | ||
7 | depends on ARCH_STI || COMPILE_TEST | ||
8 | select SND_SOC_GENERIC_DMAENGINE_PCM | ||
9 | help | ||
10 | Say Y if you want to enable ASoC-support for | ||
11 | any of the STI platforms (e.g. STIH416). | ||
diff --git a/sound/soc/sti/Makefile b/sound/soc/sti/Makefile new file mode 100644 index 000000000000..4b188d2d76b8 --- /dev/null +++ b/sound/soc/sti/Makefile | |||
@@ -0,0 +1,4 @@ | |||
1 | # STI platform support | ||
2 | snd-soc-sti-objs := sti_uniperif.o uniperif_player.o uniperif_reader.o | ||
3 | |||
4 | obj-$(CONFIG_SND_SOC_STI) += snd-soc-sti.o | ||
diff --git a/sound/soc/sti/sti_uniperif.c b/sound/soc/sti/sti_uniperif.c new file mode 100644 index 000000000000..39bcefe5eea0 --- /dev/null +++ b/sound/soc/sti/sti_uniperif.c | |||
@@ -0,0 +1,254 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> | ||
4 | * for STMicroelectronics. | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/module.h> | ||
9 | #include <linux/pinctrl/consumer.h> | ||
10 | |||
11 | #include "uniperif.h" | ||
12 | |||
13 | /* | ||
14 | * sti_uniperiph_dai_create_ctrl | ||
15 | * This function is used to create Ctrl associated to DAI but also pcm device. | ||
16 | * Request is done by front end to associate ctrl with pcm device id | ||
17 | */ | ||
18 | static int sti_uniperiph_dai_create_ctrl(struct snd_soc_dai *dai) | ||
19 | { | ||
20 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
21 | struct uniperif *uni = priv->dai_data.uni; | ||
22 | struct snd_kcontrol_new *ctrl; | ||
23 | int i; | ||
24 | |||
25 | if (!uni->num_ctrls) | ||
26 | return 0; | ||
27 | |||
28 | for (i = 0; i < uni->num_ctrls; i++) { | ||
29 | /* | ||
30 | * Several Control can have same name. Controls are indexed on | ||
31 | * Uniperipheral instance ID | ||
32 | */ | ||
33 | ctrl = &uni->snd_ctrls[i]; | ||
34 | ctrl->index = uni->info->id; | ||
35 | ctrl->device = uni->info->id; | ||
36 | } | ||
37 | |||
38 | return snd_soc_add_dai_controls(dai, uni->snd_ctrls, uni->num_ctrls); | ||
39 | } | ||
40 | |||
41 | /* | ||
42 | * DAI | ||
43 | */ | ||
44 | int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | ||
45 | struct snd_pcm_hw_params *params, | ||
46 | struct snd_soc_dai *dai) | ||
47 | { | ||
48 | struct snd_dmaengine_dai_dma_data *dma_data; | ||
49 | int transfer_size; | ||
50 | |||
51 | transfer_size = params_channels(params) * UNIPERIF_FIFO_FRAMES; | ||
52 | |||
53 | dma_data = snd_soc_dai_get_dma_data(dai, substream); | ||
54 | dma_data->maxburst = transfer_size; | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
60 | { | ||
61 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
62 | |||
63 | priv->dai_data.uni->daifmt = fmt; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int sti_uniperiph_dai_suspend(struct snd_soc_dai *dai) | ||
69 | { | ||
70 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
71 | struct uniperif *uni = priv->dai_data.uni; | ||
72 | int ret; | ||
73 | |||
74 | /* The uniperipheral should be in stopped state */ | ||
75 | if (uni->state != UNIPERIF_STATE_STOPPED) { | ||
76 | dev_err(uni->dev, "%s: invalid uni state( %d)", | ||
77 | __func__, (int)uni->state); | ||
78 | return -EBUSY; | ||
79 | } | ||
80 | |||
81 | /* Pinctrl: switch pinstate to sleep */ | ||
82 | ret = pinctrl_pm_select_sleep_state(uni->dev); | ||
83 | if (ret) | ||
84 | dev_err(uni->dev, "%s: failed to select pinctrl state", | ||
85 | __func__); | ||
86 | |||
87 | return ret; | ||
88 | } | ||
89 | |||
90 | static int sti_uniperiph_dai_resume(struct snd_soc_dai *dai) | ||
91 | { | ||
92 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
93 | struct uniperif *uni = priv->dai_data.uni; | ||
94 | int ret; | ||
95 | |||
96 | if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) { | ||
97 | ret = uni_player_resume(uni); | ||
98 | if (ret) | ||
99 | return ret; | ||
100 | } | ||
101 | |||
102 | /* pinctrl: switch pinstate to default */ | ||
103 | ret = pinctrl_pm_select_default_state(uni->dev); | ||
104 | if (ret) | ||
105 | dev_err(uni->dev, "%s: failed to select pinctrl state", | ||
106 | __func__); | ||
107 | |||
108 | return ret; | ||
109 | } | ||
110 | |||
111 | static int sti_uniperiph_dai_probe(struct snd_soc_dai *dai) | ||
112 | { | ||
113 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
114 | struct sti_uniperiph_dai *dai_data = &priv->dai_data; | ||
115 | |||
116 | /* DMA settings*/ | ||
117 | if (of_device_is_compatible(dai->dev->of_node, "st,sti-uni-player")) | ||
118 | snd_soc_dai_init_dma_data(dai, &dai_data->dma_data, NULL); | ||
119 | else | ||
120 | snd_soc_dai_init_dma_data(dai, NULL, &dai_data->dma_data); | ||
121 | |||
122 | dai_data->dma_data.addr = dai_data->uni->fifo_phys_address; | ||
123 | dai_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | ||
124 | |||
125 | return sti_uniperiph_dai_create_ctrl(dai); | ||
126 | } | ||
127 | |||
128 | static const struct snd_soc_dai_driver sti_uniperiph_dai_template = { | ||
129 | .probe = sti_uniperiph_dai_probe, | ||
130 | .suspend = sti_uniperiph_dai_suspend, | ||
131 | .resume = sti_uniperiph_dai_resume | ||
132 | }; | ||
133 | |||
134 | static const struct snd_soc_component_driver sti_uniperiph_dai_component = { | ||
135 | .name = "sti_cpu_dai", | ||
136 | }; | ||
137 | |||
138 | static int sti_uniperiph_cpu_dai_of(struct device_node *node, | ||
139 | struct sti_uniperiph_data *priv) | ||
140 | { | ||
141 | const char *str; | ||
142 | int ret; | ||
143 | struct device *dev = &priv->pdev->dev; | ||
144 | struct sti_uniperiph_dai *dai_data = &priv->dai_data; | ||
145 | struct snd_soc_dai_driver *dai = priv->dai; | ||
146 | struct snd_soc_pcm_stream *stream; | ||
147 | struct uniperif *uni; | ||
148 | |||
149 | uni = devm_kzalloc(dev, sizeof(*uni), GFP_KERNEL); | ||
150 | if (!uni) | ||
151 | return -ENOMEM; | ||
152 | |||
153 | *dai = sti_uniperiph_dai_template; | ||
154 | ret = of_property_read_string(node, "dai-name", &str); | ||
155 | if (ret < 0) { | ||
156 | dev_err(dev, "%s: dai name missing.\n", __func__); | ||
157 | return -EINVAL; | ||
158 | } | ||
159 | dai->name = str; | ||
160 | |||
161 | /* Get resources */ | ||
162 | uni->mem_region = platform_get_resource(priv->pdev, IORESOURCE_MEM, 0); | ||
163 | |||
164 | if (!uni->mem_region) { | ||
165 | dev_err(dev, "Failed to get memory resource"); | ||
166 | return -ENODEV; | ||
167 | } | ||
168 | |||
169 | uni->base = devm_ioremap_resource(dev, uni->mem_region); | ||
170 | |||
171 | if (IS_ERR(uni->base)) | ||
172 | return PTR_ERR(uni->base); | ||
173 | |||
174 | uni->fifo_phys_address = uni->mem_region->start + | ||
175 | UNIPERIF_FIFO_DATA_OFFSET(uni); | ||
176 | |||
177 | uni->irq = platform_get_irq(priv->pdev, 0); | ||
178 | if (uni->irq < 0) { | ||
179 | dev_err(dev, "Failed to get IRQ resource"); | ||
180 | return -ENXIO; | ||
181 | } | ||
182 | |||
183 | dai_data->uni = uni; | ||
184 | |||
185 | if (of_device_is_compatible(node, "st,sti-uni-player")) { | ||
186 | uni_player_init(priv->pdev, uni); | ||
187 | stream = &dai->playback; | ||
188 | } else { | ||
189 | uni_reader_init(priv->pdev, uni); | ||
190 | stream = &dai->capture; | ||
191 | } | ||
192 | dai->ops = uni->dai_ops; | ||
193 | |||
194 | stream->stream_name = dai->name; | ||
195 | stream->channels_min = uni->hw->channels_min; | ||
196 | stream->channels_max = uni->hw->channels_max; | ||
197 | stream->rates = uni->hw->rates; | ||
198 | stream->formats = uni->hw->formats; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
203 | static const struct snd_dmaengine_pcm_config dmaengine_pcm_config = { | ||
204 | .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, | ||
205 | }; | ||
206 | |||
207 | static int sti_uniperiph_probe(struct platform_device *pdev) | ||
208 | { | ||
209 | struct sti_uniperiph_data *priv; | ||
210 | struct device_node *node = pdev->dev.of_node; | ||
211 | int ret; | ||
212 | |||
213 | /* Allocate the private data and the CPU_DAI array */ | ||
214 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
215 | if (!priv) | ||
216 | return -ENOMEM; | ||
217 | priv->dai = devm_kzalloc(&pdev->dev, sizeof(*priv->dai), GFP_KERNEL); | ||
218 | if (!priv->dai) | ||
219 | return -ENOMEM; | ||
220 | |||
221 | priv->pdev = pdev; | ||
222 | |||
223 | ret = sti_uniperiph_cpu_dai_of(node, priv); | ||
224 | |||
225 | dev_set_drvdata(&pdev->dev, priv); | ||
226 | |||
227 | ret = devm_snd_soc_register_component(&pdev->dev, | ||
228 | &sti_uniperiph_dai_component, | ||
229 | priv->dai, 1); | ||
230 | if (ret < 0) | ||
231 | return ret; | ||
232 | |||
233 | return devm_snd_dmaengine_pcm_register(&pdev->dev, | ||
234 | &dmaengine_pcm_config, 0); | ||
235 | } | ||
236 | |||
237 | static const struct of_device_id snd_soc_sti_match[] = { | ||
238 | { .compatible = "st,sti-uni-player", }, | ||
239 | { .compatible = "st,sti-uni-reader", }, | ||
240 | {}, | ||
241 | }; | ||
242 | |||
243 | static struct platform_driver sti_uniperiph_driver = { | ||
244 | .driver = { | ||
245 | .name = "sti-uniperiph-dai", | ||
246 | .of_match_table = snd_soc_sti_match, | ||
247 | }, | ||
248 | .probe = sti_uniperiph_probe, | ||
249 | }; | ||
250 | module_platform_driver(sti_uniperiph_driver); | ||
251 | |||
252 | MODULE_DESCRIPTION("uniperipheral DAI driver"); | ||
253 | MODULE_AUTHOR("Arnaud Pouliquen <arnaud.pouliquen@st.com>"); | ||
254 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/sound/soc/sti/uniperif.h b/sound/soc/sti/uniperif.h new file mode 100644 index 000000000000..f0fd5a9944e9 --- /dev/null +++ b/sound/soc/sti/uniperif.h | |||
@@ -0,0 +1,1229 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> | ||
4 | * for STMicroelectronics. | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #ifndef __SND_ST_AUD_UNIPERIF_H | ||
9 | #define __SND_ST_AUD_UNIPERIF_H | ||
10 | |||
11 | #include <linux/regmap.h> | ||
12 | |||
13 | #include <sound/dmaengine_pcm.h> | ||
14 | |||
15 | /* | ||
16 | * Register access macros | ||
17 | */ | ||
18 | |||
19 | #define GET_UNIPERIF_REG(ip, offset, shift, mask) \ | ||
20 | ((readl_relaxed(ip->base + offset) >> shift) & mask) | ||
21 | #define SET_UNIPERIF_REG(ip, offset, shift, mask, value) \ | ||
22 | writel_relaxed(((readl_relaxed(ip->base + offset) & \ | ||
23 | ~(mask << shift)) | (((value) & mask) << shift)), ip->base + offset) | ||
24 | #define SET_UNIPERIF_BIT_REG(ip, offset, shift, mask, value) \ | ||
25 | writel_relaxed((((value) & mask) << shift), ip->base + offset) | ||
26 | |||
27 | /* | ||
28 | * AUD_UNIPERIF_SOFT_RST reg | ||
29 | */ | ||
30 | |||
31 | #define UNIPERIF_SOFT_RST_OFFSET(ip) 0x0000 | ||
32 | #define GET_UNIPERIF_SOFT_RST(ip) \ | ||
33 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
34 | readl_relaxed(ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) : 0) | ||
35 | #define SET_UNIPERIF_SOFT_RST(ip, value) \ | ||
36 | writel_relaxed(value, ip->base + UNIPERIF_SOFT_RST_OFFSET(ip)) | ||
37 | |||
38 | /* SOFT_RST */ | ||
39 | #define UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip) 0x0 | ||
40 | #define UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip) 0x1 | ||
41 | #define SET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ | ||
42 | SET_UNIPERIF_BIT_REG(ip, \ | ||
43 | UNIPERIF_SOFT_RST_OFFSET(ip), \ | ||
44 | UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ | ||
45 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip), 1) | ||
46 | #define GET_UNIPERIF_SOFT_RST_SOFT_RST(ip) \ | ||
47 | GET_UNIPERIF_REG(ip, \ | ||
48 | UNIPERIF_SOFT_RST_OFFSET(ip), \ | ||
49 | UNIPERIF_SOFT_RST_SOFT_RST_SHIFT(ip), \ | ||
50 | UNIPERIF_SOFT_RST_SOFT_RST_MASK(ip)) | ||
51 | |||
52 | /* | ||
53 | * AUD_UNIPERIF_FIFO_DATA reg | ||
54 | */ | ||
55 | |||
56 | #define UNIPERIF_FIFO_DATA_OFFSET(ip) 0x0004 | ||
57 | #define SET_UNIPERIF_DATA(ip, value) \ | ||
58 | writel_relaxed(value, ip->base + UNIPERIF_FIFO_DATA_OFFSET(ip)) | ||
59 | |||
60 | /* | ||
61 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | ||
62 | */ | ||
63 | |||
64 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | ||
65 | #define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ | ||
66 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) | ||
67 | #define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ | ||
68 | writel_relaxed(value, ip->base + \ | ||
69 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) | ||
70 | |||
71 | #define UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip) 0x0060 | ||
72 | #define GET_UNIPERIF_CHANNEL_STA_REG0(ip) \ | ||
73 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) | ||
74 | #define SET_UNIPERIF_CHANNEL_STA_REG0(ip, value) \ | ||
75 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG0_OFFSET(ip)) | ||
76 | |||
77 | #define UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip) 0x0064 | ||
78 | #define GET_UNIPERIF_CHANNEL_STA_REG1(ip) \ | ||
79 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) | ||
80 | #define SET_UNIPERIF_CHANNEL_STA_REG1(ip, value) \ | ||
81 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG1_OFFSET(ip)) | ||
82 | |||
83 | #define UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip) 0x0068 | ||
84 | #define GET_UNIPERIF_CHANNEL_STA_REG2(ip) \ | ||
85 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) | ||
86 | #define SET_UNIPERIF_CHANNEL_STA_REG2(ip, value) \ | ||
87 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG2_OFFSET(ip)) | ||
88 | |||
89 | #define UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip) 0x006C | ||
90 | #define GET_UNIPERIF_CHANNEL_STA_REG3(ip) \ | ||
91 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) | ||
92 | #define SET_UNIPERIF_CHANNEL_STA_REG3(ip, value) \ | ||
93 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG3_OFFSET(ip)) | ||
94 | |||
95 | #define UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip) 0x0070 | ||
96 | #define GET_UNIPERIF_CHANNEL_STA_REG4(ip) \ | ||
97 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) | ||
98 | #define SET_UNIPERIF_CHANNEL_STA_REG4(ip, value) \ | ||
99 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG4_OFFSET(ip)) | ||
100 | |||
101 | #define UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip) 0x0074 | ||
102 | #define GET_UNIPERIF_CHANNEL_STA_REG5(ip) \ | ||
103 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) | ||
104 | #define SET_UNIPERIF_CHANNEL_STA_REG5(ip, value) \ | ||
105 | writel_relaxed(value, ip->base + UNIPERIF_CHANNEL_STA_REG5_OFFSET(ip)) | ||
106 | |||
107 | /* | ||
108 | * AUD_UNIPERIF_ITS reg | ||
109 | */ | ||
110 | |||
111 | #define UNIPERIF_ITS_OFFSET(ip) 0x000C | ||
112 | #define GET_UNIPERIF_ITS(ip) \ | ||
113 | readl_relaxed(ip->base + UNIPERIF_ITS_OFFSET(ip)) | ||
114 | |||
115 | /* MEM_BLK_READ */ | ||
116 | #define UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip) 5 | ||
117 | #define UNIPERIF_ITS_MEM_BLK_READ_MASK(ip) \ | ||
118 | (BIT(UNIPERIF_ITS_MEM_BLK_READ_SHIFT(ip))) | ||
119 | |||
120 | /* FIFO_ERROR */ | ||
121 | #define UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip) \ | ||
122 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) | ||
123 | #define UNIPERIF_ITS_FIFO_ERROR_MASK(ip) \ | ||
124 | (BIT(UNIPERIF_ITS_FIFO_ERROR_SHIFT(ip))) | ||
125 | |||
126 | /* DMA_ERROR */ | ||
127 | #define UNIPERIF_ITS_DMA_ERROR_SHIFT(ip) 9 | ||
128 | #define UNIPERIF_ITS_DMA_ERROR_MASK(ip) \ | ||
129 | (BIT(UNIPERIF_ITS_DMA_ERROR_SHIFT(ip))) | ||
130 | |||
131 | /* UNDERFLOW_REC_DONE */ | ||
132 | #define UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip) \ | ||
133 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) | ||
134 | #define UNIPERIF_ITS_UNDERFLOW_REC_DONE_MASK(ip) \ | ||
135 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
136 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_DONE_SHIFT(ip)))) | ||
137 | |||
138 | /* UNDERFLOW_REC_FAILED */ | ||
139 | #define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip) \ | ||
140 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) | ||
141 | #define UNIPERIF_ITS_UNDERFLOW_REC_FAILED_MASK(ip) \ | ||
142 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
143 | 0 : (BIT(UNIPERIF_ITS_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | ||
144 | |||
145 | /* | ||
146 | * AUD_UNIPERIF_ITS_BCLR reg | ||
147 | */ | ||
148 | |||
149 | /* FIFO_ERROR */ | ||
150 | #define UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip) \ | ||
151 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) | ||
152 | #define UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip) \ | ||
153 | (BIT(UNIPERIF_ITS_BCLR_FIFO_ERROR_SHIFT(ip))) | ||
154 | #define SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(ip) \ | ||
155 | SET_UNIPERIF_ITS_BCLR(ip, \ | ||
156 | UNIPERIF_ITS_BCLR_FIFO_ERROR_MASK(ip)) | ||
157 | |||
158 | #define UNIPERIF_ITS_BCLR_OFFSET(ip) 0x0010 | ||
159 | #define SET_UNIPERIF_ITS_BCLR(ip, value) \ | ||
160 | writel_relaxed(value, ip->base + UNIPERIF_ITS_BCLR_OFFSET(ip)) | ||
161 | |||
162 | /* | ||
163 | * AUD_UNIPERIF_ITM reg | ||
164 | */ | ||
165 | |||
166 | #define UNIPERIF_ITM_OFFSET(ip) 0x0018 | ||
167 | #define GET_UNIPERIF_ITM(ip) \ | ||
168 | readl_relaxed(ip->base + UNIPERIF_ITM_OFFSET(ip)) | ||
169 | |||
170 | /* FIFO_ERROR */ | ||
171 | #define UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip) \ | ||
172 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) | ||
173 | #define UNIPERIF_ITM_FIFO_ERROR_MASK(ip) \ | ||
174 | (BIT(UNIPERIF_ITM_FIFO_ERROR_SHIFT(ip))) | ||
175 | |||
176 | /* UNDERFLOW_REC_DONE */ | ||
177 | #define UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip) \ | ||
178 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) | ||
179 | #define UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(ip) \ | ||
180 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
181 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_DONE_SHIFT(ip)))) | ||
182 | |||
183 | /* UNDERFLOW_REC_FAILED */ | ||
184 | #define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip) \ | ||
185 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) | ||
186 | #define UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(ip) \ | ||
187 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
188 | 0 : (BIT(UNIPERIF_ITM_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | ||
189 | |||
190 | /* | ||
191 | * AUD_UNIPERIF_ITM_BCLR reg | ||
192 | */ | ||
193 | |||
194 | #define UNIPERIF_ITM_BCLR_OFFSET(ip) 0x001c | ||
195 | #define SET_UNIPERIF_ITM_BCLR(ip, value) \ | ||
196 | writel_relaxed(value, ip->base + UNIPERIF_ITM_BCLR_OFFSET(ip)) | ||
197 | |||
198 | /* FIFO_ERROR */ | ||
199 | #define UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip) \ | ||
200 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) | ||
201 | #define UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip) \ | ||
202 | (BIT(UNIPERIF_ITM_BCLR_FIFO_ERROR_SHIFT(ip))) | ||
203 | #define SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(ip) \ | ||
204 | SET_UNIPERIF_ITM_BCLR(ip, \ | ||
205 | UNIPERIF_ITM_BCLR_FIFO_ERROR_MASK(ip)) | ||
206 | |||
207 | /* DMA_ERROR */ | ||
208 | #define UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip) 9 | ||
209 | #define UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip) \ | ||
210 | (BIT(UNIPERIF_ITM_BCLR_DMA_ERROR_SHIFT(ip))) | ||
211 | #define SET_UNIPERIF_ITM_BCLR_DMA_ERROR(ip) \ | ||
212 | SET_UNIPERIF_ITM_BCLR(ip, \ | ||
213 | UNIPERIF_ITM_BCLR_DMA_ERROR_MASK(ip)) | ||
214 | |||
215 | /* | ||
216 | * AUD_UNIPERIF_ITM_BSET reg | ||
217 | */ | ||
218 | |||
219 | #define UNIPERIF_ITM_BSET_OFFSET(ip) 0x0020 | ||
220 | #define SET_UNIPERIF_ITM_BSET(ip, value) \ | ||
221 | writel_relaxed(value, ip->base + UNIPERIF_ITM_BSET_OFFSET(ip)) | ||
222 | |||
223 | /* FIFO_ERROR */ | ||
224 | #define UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip) \ | ||
225 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 8) | ||
226 | #define UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip) \ | ||
227 | (BIT(UNIPERIF_ITM_BSET_FIFO_ERROR_SHIFT(ip))) | ||
228 | #define SET_UNIPERIF_ITM_BSET_FIFO_ERROR(ip) \ | ||
229 | SET_UNIPERIF_ITM_BSET(ip, \ | ||
230 | UNIPERIF_ITM_BSET_FIFO_ERROR_MASK(ip)) | ||
231 | |||
232 | /* MEM_BLK_READ */ | ||
233 | #define UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip) 5 | ||
234 | #define UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip) \ | ||
235 | (BIT(UNIPERIF_ITM_BSET_MEM_BLK_READ_SHIFT(ip))) | ||
236 | #define SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(ip) \ | ||
237 | SET_UNIPERIF_ITM_BSET(ip, \ | ||
238 | UNIPERIF_ITM_BSET_MEM_BLK_READ_MASK(ip)) | ||
239 | |||
240 | /* DMA_ERROR */ | ||
241 | #define UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip) 9 | ||
242 | #define UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip) \ | ||
243 | (BIT(UNIPERIF_ITM_BSET_DMA_ERROR_SHIFT(ip))) | ||
244 | #define SET_UNIPERIF_ITM_BSET_DMA_ERROR(ip) \ | ||
245 | SET_UNIPERIF_ITM_BSET(ip, \ | ||
246 | UNIPERIF_ITM_BSET_DMA_ERROR_MASK(ip)) | ||
247 | |||
248 | /* UNDERFLOW_REC_DONE */ | ||
249 | #define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip) \ | ||
250 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 12) | ||
251 | #define UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip) \ | ||
252 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
253 | 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_SHIFT(ip)))) | ||
254 | #define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(ip) \ | ||
255 | SET_UNIPERIF_ITM_BSET(ip, \ | ||
256 | UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE_MASK(ip)) | ||
257 | |||
258 | /* UNDERFLOW_REC_FAILED */ | ||
259 | #define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip) \ | ||
260 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 13) | ||
261 | #define UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip) \ | ||
262 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? \ | ||
263 | 0 : (BIT(UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_SHIFT(ip)))) | ||
264 | #define SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(ip) \ | ||
265 | SET_UNIPERIF_ITM_BSET(ip, \ | ||
266 | UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED_MASK(ip)) | ||
267 | |||
268 | /* | ||
269 | * UNIPERIF_CONFIG reg | ||
270 | */ | ||
271 | |||
272 | #define UNIPERIF_CONFIG_OFFSET(ip) 0x0040 | ||
273 | #define GET_UNIPERIF_CONFIG(ip) \ | ||
274 | readl_relaxed(ip->base + UNIPERIF_CONFIG_OFFSET(ip)) | ||
275 | #define SET_UNIPERIF_CONFIG(ip, value) \ | ||
276 | writel_relaxed(value, ip->base + UNIPERIF_CONFIG_OFFSET(ip)) | ||
277 | |||
278 | /* PARITY_CNTR */ | ||
279 | #define UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip) 0 | ||
280 | #define UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip) 0x1 | ||
281 | #define GET_UNIPERIF_CONFIG_PARITY_CNTR(ip) \ | ||
282 | GET_UNIPERIF_REG(ip, \ | ||
283 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
284 | UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ | ||
285 | UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip)) | ||
286 | #define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(ip) \ | ||
287 | SET_UNIPERIF_REG(ip, \ | ||
288 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
289 | UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ | ||
290 | UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 0) | ||
291 | #define SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_SW(ip) \ | ||
292 | SET_UNIPERIF_REG(ip, \ | ||
293 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
294 | UNIPERIF_CONFIG_PARITY_CNTR_SHIFT(ip), \ | ||
295 | UNIPERIF_CONFIG_PARITY_CNTR_MASK(ip), 1) | ||
296 | |||
297 | /* CHANNEL_STA_CNTR */ | ||
298 | #define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip) 1 | ||
299 | #define UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip) 0x1 | ||
300 | #define GET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR(ip) \ | ||
301 | GET_UNIPERIF_REG(ip, \ | ||
302 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
303 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ | ||
304 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip)) | ||
305 | #define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_SW(ip) \ | ||
306 | SET_UNIPERIF_REG(ip, \ | ||
307 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
308 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ | ||
309 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 0) | ||
310 | #define SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(ip) \ | ||
311 | SET_UNIPERIF_REG(ip, \ | ||
312 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
313 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_SHIFT(ip), \ | ||
314 | UNIPERIF_CONFIG_CHANNEL_STA_CNTR_MASK(ip), 1) | ||
315 | |||
316 | /* USER_DAT_CNTR */ | ||
317 | #define UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip) 2 | ||
318 | #define UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip) 0x1 | ||
319 | #define GET_UNIPERIF_CONFIG_USER_DAT_CNTR(ip) \ | ||
320 | GET_UNIPERIF_REG(ip, \ | ||
321 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
322 | UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ | ||
323 | UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip)) | ||
324 | #define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(ip) \ | ||
325 | SET_UNIPERIF_REG(ip, \ | ||
326 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
327 | UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ | ||
328 | UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 1) | ||
329 | #define SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_SW(ip) \ | ||
330 | SET_UNIPERIF_REG(ip, \ | ||
331 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
332 | UNIPERIF_CONFIG_USER_DAT_CNTR_SHIFT(ip), \ | ||
333 | UNIPERIF_CONFIG_USER_DAT_CNTR_MASK(ip), 0) | ||
334 | |||
335 | /* VALIDITY_DAT_CNTR */ | ||
336 | #define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip) 3 | ||
337 | #define UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip) 0x1 | ||
338 | #define GET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR(ip) \ | ||
339 | GET_UNIPERIF_REG(ip, \ | ||
340 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
341 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ | ||
342 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip)) | ||
343 | #define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_SW(ip) \ | ||
344 | SET_UNIPERIF_REG(ip, \ | ||
345 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
346 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ | ||
347 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 0) | ||
348 | #define SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(ip) \ | ||
349 | SET_UNIPERIF_REG(ip, \ | ||
350 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
351 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_SHIFT(ip), \ | ||
352 | UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_MASK(ip), 1) | ||
353 | |||
354 | /* ONE_BIT_AUD_SUPPORT */ | ||
355 | #define UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip) 4 | ||
356 | #define UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip) 0x1 | ||
357 | #define GET_UNIPERIF_CONFIG_ONE_BIT_AUD(ip) \ | ||
358 | GET_UNIPERIF_REG(ip, \ | ||
359 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
360 | UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ | ||
361 | UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip)) | ||
362 | #define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(ip) \ | ||
363 | SET_UNIPERIF_REG(ip, \ | ||
364 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
365 | UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ | ||
366 | UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 0) | ||
367 | #define SET_UNIPERIF_CONFIG_ONE_BIT_AUD_ENABLE(ip) \ | ||
368 | SET_UNIPERIF_REG(ip, \ | ||
369 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
370 | UNIPERIF_CONFIG_ONE_BIT_AUD_SHIFT(ip), \ | ||
371 | UNIPERIF_CONFIG_ONE_BIT_AUD_MASK(ip), 1) | ||
372 | |||
373 | /* MEMORY_FMT */ | ||
374 | #define UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip) 5 | ||
375 | #define UNIPERIF_CONFIG_MEM_FMT_MASK(ip) 0x1 | ||
376 | #define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) 0 | ||
377 | #define VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) 1 | ||
378 | #define GET_UNIPERIF_CONFIG_MEM_FMT(ip) \ | ||
379 | GET_UNIPERIF_REG(ip, \ | ||
380 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
381 | UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ | ||
382 | UNIPERIF_CONFIG_MEM_FMT_MASK(ip)) | ||
383 | #define SET_UNIPERIF_CONFIG_MEM_FMT(ip, value) \ | ||
384 | SET_UNIPERIF_REG(ip, \ | ||
385 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
386 | UNIPERIF_CONFIG_MEM_FMT_SHIFT(ip), \ | ||
387 | UNIPERIF_CONFIG_MEM_FMT_MASK(ip), value) | ||
388 | #define SET_UNIPERIF_CONFIG_MEM_FMT_16_0(ip) \ | ||
389 | SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ | ||
390 | VALUE_UNIPERIF_CONFIG_MEM_FMT_16_0(ip)) | ||
391 | #define SET_UNIPERIF_CONFIG_MEM_FMT_16_16(ip) \ | ||
392 | SET_UNIPERIF_CONFIG_MEM_FMT(ip, \ | ||
393 | VALUE_UNIPERIF_CONFIG_MEM_FMT_16_16(ip)) | ||
394 | |||
395 | /* REPEAT_CHL_STS */ | ||
396 | #define UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip) 6 | ||
397 | #define UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip) 0x1 | ||
398 | #define GET_UNIPERIF_CONFIG_REPEAT_CHL_STS(ip) \ | ||
399 | GET_UNIPERIF_REG(ip, \ | ||
400 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
401 | UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ | ||
402 | UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip)) | ||
403 | #define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(ip) \ | ||
404 | SET_UNIPERIF_REG(ip, \ | ||
405 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
406 | UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ | ||
407 | UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 0) | ||
408 | #define SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_DISABLE(ip) \ | ||
409 | SET_UNIPERIF_REG(ip, \ | ||
410 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
411 | UNIPERIF_CONFIG_REPEAT_CHL_STS_SHIFT(ip), \ | ||
412 | UNIPERIF_CONFIG_REPEAT_CHL_STS_MASK(ip), 1) | ||
413 | |||
414 | /* BACK_STALL_REQ */ | ||
415 | #define UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip) \ | ||
416 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 7 : -1) | ||
417 | #define UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip) 0x1 | ||
418 | #define GET_UNIPERIF_CONFIG_BACK_STALL_REQ(ip) \ | ||
419 | GET_UNIPERIF_REG(ip, \ | ||
420 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
421 | UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ | ||
422 | UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip)) | ||
423 | #define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(ip) \ | ||
424 | SET_UNIPERIF_REG(ip, \ | ||
425 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
426 | UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ | ||
427 | UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 0) | ||
428 | #define SET_UNIPERIF_CONFIG_BACK_STALL_REQ_ENABLE(ip) \ | ||
429 | SET_UNIPERIF_REG(ip, \ | ||
430 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
431 | UNIPERIF_CONFIG_BACK_STALL_REQ_SHIFT(ip), \ | ||
432 | UNIPERIF_CONFIG_BACK_STALL_REQ_MASK(ip), 1) | ||
433 | |||
434 | /* FDMA_TRIGGER_LIMIT */ | ||
435 | #define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip) 8 | ||
436 | #define UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip) 0x7F | ||
437 | #define GET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip) \ | ||
438 | GET_UNIPERIF_REG(ip, \ | ||
439 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
440 | UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ | ||
441 | UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip)) | ||
442 | #define SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(ip, value) \ | ||
443 | SET_UNIPERIF_REG(ip, \ | ||
444 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
445 | UNIPERIF_CONFIG_DMA_TRIG_LIMIT_SHIFT(ip), \ | ||
446 | UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(ip), value) | ||
447 | |||
448 | /* CHL_STS_UPDATE */ | ||
449 | #define UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip) \ | ||
450 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) | ||
451 | #define UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip) 0x1 | ||
452 | #define GET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ | ||
453 | GET_UNIPERIF_REG(ip, \ | ||
454 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
455 | UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ | ||
456 | UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip)) | ||
457 | #define SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(ip) \ | ||
458 | SET_UNIPERIF_REG(ip, \ | ||
459 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
460 | UNIPERIF_CONFIG_CHL_STS_UPDATE_SHIFT(ip), \ | ||
461 | UNIPERIF_CONFIG_CHL_STS_UPDATE_MASK(ip), 1) | ||
462 | |||
463 | /* IDLE_MOD */ | ||
464 | #define UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip) 18 | ||
465 | #define UNIPERIF_CONFIG_IDLE_MOD_MASK(ip) 0x1 | ||
466 | #define GET_UNIPERIF_CONFIG_IDLE_MOD(ip) \ | ||
467 | GET_UNIPERIF_REG(ip, \ | ||
468 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
469 | UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ | ||
470 | UNIPERIF_CONFIG_IDLE_MOD_MASK(ip)) | ||
471 | #define SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(ip) \ | ||
472 | SET_UNIPERIF_REG(ip, \ | ||
473 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
474 | UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ | ||
475 | UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 0) | ||
476 | #define SET_UNIPERIF_CONFIG_IDLE_MOD_ENABLE(ip) \ | ||
477 | SET_UNIPERIF_REG(ip, \ | ||
478 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
479 | UNIPERIF_CONFIG_IDLE_MOD_SHIFT(ip), \ | ||
480 | UNIPERIF_CONFIG_IDLE_MOD_MASK(ip), 1) | ||
481 | |||
482 | /* SUBFRAME_SELECTION */ | ||
483 | #define UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip) 19 | ||
484 | #define UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip) 0x1 | ||
485 | #define GET_UNIPERIF_CONFIG_SUBFRAME_SEL(ip) \ | ||
486 | GET_UNIPERIF_REG(ip, \ | ||
487 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
488 | UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ | ||
489 | UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip)) | ||
490 | #define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(ip) \ | ||
491 | SET_UNIPERIF_REG(ip, \ | ||
492 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
493 | UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ | ||
494 | UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 1) | ||
495 | #define SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF0_SUBF1(ip) \ | ||
496 | SET_UNIPERIF_REG(ip, \ | ||
497 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
498 | UNIPERIF_CONFIG_SUBFRAME_SEL_SHIFT(ip), \ | ||
499 | UNIPERIF_CONFIG_SUBFRAME_SEL_MASK(ip), 0) | ||
500 | |||
501 | /* FULL_SW_CONTROL */ | ||
502 | #define UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip) 20 | ||
503 | #define UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip) 0x1 | ||
504 | #define GET_UNIPERIF_CONFIG_SPDIF_SW_CTRL(ip) \ | ||
505 | GET_UNIPERIF_REG(ip, \ | ||
506 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
507 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ | ||
508 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip)) | ||
509 | #define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_ENABLE(ip) \ | ||
510 | SET_UNIPERIF_REG(ip, \ | ||
511 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
512 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ | ||
513 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 1) | ||
514 | #define SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(ip) \ | ||
515 | SET_UNIPERIF_REG(ip, \ | ||
516 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
517 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_SHIFT(ip), \ | ||
518 | UNIPERIF_CONFIG_SPDIF_SW_CTRL_MASK(ip), 0) | ||
519 | |||
520 | /* MASTER_CLKEDGE */ | ||
521 | #define UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip) \ | ||
522 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 24 : -1) | ||
523 | #define UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip) 0x1 | ||
524 | #define GET_UNIPERIF_CONFIG_MSTR_CLKEDGE(ip) \ | ||
525 | GET_UNIPERIF_REG(ip, \ | ||
526 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
527 | UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ | ||
528 | UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip)) | ||
529 | #define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_FALLING(ip) \ | ||
530 | SET_UNIPERIF_REG(ip, \ | ||
531 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
532 | UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ | ||
533 | UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 1) | ||
534 | #define SET_UNIPERIF_CONFIG_MSTR_CLKEDGE_RISING(ip) \ | ||
535 | SET_UNIPERIF_REG(ip, \ | ||
536 | UNIPERIF_CONFIG_OFFSET(ip), \ | ||
537 | UNIPERIF_CONFIG_MSTR_CLKEDGE_SHIFT(ip), \ | ||
538 | UNIPERIF_CONFIG_MSTR_CLKEDGE_MASK(ip), 0) | ||
539 | |||
540 | /* | ||
541 | * UNIPERIF_CTRL reg | ||
542 | */ | ||
543 | |||
544 | #define UNIPERIF_CTRL_OFFSET(ip) 0x0044 | ||
545 | #define GET_UNIPERIF_CTRL(ip) \ | ||
546 | readl_relaxed(ip->base + UNIPERIF_CTRL_OFFSET(ip)) | ||
547 | #define SET_UNIPERIF_CTRL(ip, value) \ | ||
548 | writel_relaxed(value, ip->base + UNIPERIF_CTRL_OFFSET(ip)) | ||
549 | |||
550 | /* OPERATION */ | ||
551 | #define UNIPERIF_CTRL_OPERATION_SHIFT(ip) 0 | ||
552 | #define UNIPERIF_CTRL_OPERATION_MASK(ip) 0x7 | ||
553 | #define GET_UNIPERIF_CTRL_OPERATION(ip) \ | ||
554 | GET_UNIPERIF_REG(ip, \ | ||
555 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
556 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
557 | UNIPERIF_CTRL_OPERATION_MASK(ip)) | ||
558 | #define VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip) 0 | ||
559 | #define SET_UNIPERIF_CTRL_OPERATION_OFF(ip) \ | ||
560 | SET_UNIPERIF_REG(ip, \ | ||
561 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
562 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
563 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
564 | VALUE_UNIPERIF_CTRL_OPERATION_OFF(ip)) | ||
565 | #define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ | ||
566 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 1 : -1) | ||
567 | #define SET_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip) \ | ||
568 | SET_UNIPERIF_REG(ip, \ | ||
569 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
570 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
571 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
572 | VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PCM_NULL(ip)) | ||
573 | #define VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ | ||
574 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 2 : -1) | ||
575 | #define SET_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip) \ | ||
576 | SET_UNIPERIF_REG(ip, \ | ||
577 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
578 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
579 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
580 | VALUE_UNIPERIF_CTRL_OPERATION_MUTE_PAUSE_BURST(ip)) | ||
581 | #define VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) 3 | ||
582 | #define SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip) \ | ||
583 | SET_UNIPERIF_REG(ip, \ | ||
584 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
585 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
586 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
587 | VALUE_UNIPERIF_CTRL_OPERATION_PCM_DATA(ip)) | ||
588 | /* This is the same as above! */ | ||
589 | #define VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) 3 | ||
590 | #define SET_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip) \ | ||
591 | SET_UNIPERIF_REG(ip, \ | ||
592 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
593 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
594 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
595 | VALUE_UNIPERIF_CTRL_OPERATION_AUDIO_DATA(ip)) | ||
596 | #define VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) 4 | ||
597 | #define SET_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip) \ | ||
598 | SET_UNIPERIF_REG(ip, \ | ||
599 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
600 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
601 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
602 | VALUE_UNIPERIF_CTRL_OPERATION_ENC_DATA(ip)) | ||
603 | #define VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ | ||
604 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 5 : -1) | ||
605 | #define SET_UNIPERIF_CTRL_OPERATION_CD_DATA(ip) \ | ||
606 | SET_UNIPERIF_REG(ip, \ | ||
607 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
608 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
609 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
610 | VALUE_UNIPERIF_CTRL_OPERATION_CD_DATA(ip)) | ||
611 | #define VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ | ||
612 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 7) | ||
613 | #define SET_UNIPERIF_CTRL_OPERATION_STANDBY(ip) \ | ||
614 | SET_UNIPERIF_REG(ip, \ | ||
615 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
616 | UNIPERIF_CTRL_OPERATION_SHIFT(ip), \ | ||
617 | UNIPERIF_CTRL_OPERATION_MASK(ip), \ | ||
618 | VALUE_UNIPERIF_CTRL_OPERATION_STANDBY(ip)) | ||
619 | |||
620 | /* EXIT_STBY_ON_EOBLOCK */ | ||
621 | #define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip) \ | ||
622 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 3) | ||
623 | #define UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip) 0x1 | ||
624 | #define GET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK(ip) \ | ||
625 | GET_UNIPERIF_REG(ip, \ | ||
626 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
627 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ | ||
628 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip)) | ||
629 | #define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(ip) \ | ||
630 | SET_UNIPERIF_REG(ip, \ | ||
631 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
632 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ | ||
633 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 0) | ||
634 | #define SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(ip) \ | ||
635 | SET_UNIPERIF_REG(ip, \ | ||
636 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
637 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_SHIFT(ip), \ | ||
638 | UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_MASK(ip), 1) | ||
639 | |||
640 | /* ROUNDING */ | ||
641 | #define UNIPERIF_CTRL_ROUNDING_SHIFT(ip) 4 | ||
642 | #define UNIPERIF_CTRL_ROUNDING_MASK(ip) 0x1 | ||
643 | #define GET_UNIPERIF_CTRL_ROUNDING(ip) \ | ||
644 | GET_UNIPERIF_REG(ip, \ | ||
645 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
646 | UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ | ||
647 | UNIPERIF_CTRL_ROUNDING_MASK(ip)) | ||
648 | #define SET_UNIPERIF_CTRL_ROUNDING_OFF(ip) \ | ||
649 | SET_UNIPERIF_REG(ip, \ | ||
650 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
651 | UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ | ||
652 | UNIPERIF_CTRL_ROUNDING_MASK(ip), 0) | ||
653 | #define SET_UNIPERIF_CTRL_ROUNDING_ON(ip) \ | ||
654 | SET_UNIPERIF_REG(ip, \ | ||
655 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
656 | UNIPERIF_CTRL_ROUNDING_SHIFT(ip), \ | ||
657 | UNIPERIF_CTRL_ROUNDING_MASK(ip), 1) | ||
658 | |||
659 | /* DIVIDER */ | ||
660 | #define UNIPERIF_CTRL_DIVIDER_SHIFT(ip) 5 | ||
661 | #define UNIPERIF_CTRL_DIVIDER_MASK(ip) 0xff | ||
662 | #define GET_UNIPERIF_CTRL_DIVIDER(ip) \ | ||
663 | GET_UNIPERIF_REG(ip, \ | ||
664 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
665 | UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ | ||
666 | UNIPERIF_CTRL_DIVIDER_MASK(ip)) | ||
667 | #define SET_UNIPERIF_CTRL_DIVIDER(ip, value) \ | ||
668 | SET_UNIPERIF_REG(ip, \ | ||
669 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
670 | UNIPERIF_CTRL_DIVIDER_SHIFT(ip), \ | ||
671 | UNIPERIF_CTRL_DIVIDER_MASK(ip), value) | ||
672 | |||
673 | /* BYTE_SWAP */ | ||
674 | #define UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip) \ | ||
675 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 13 : -1) | ||
676 | #define UNIPERIF_CTRL_BYTE_SWP_MASK(ip) 0x1 | ||
677 | #define GET_UNIPERIF_CTRL_BYTE_SWP(ip) \ | ||
678 | GET_UNIPERIF_REG(ip, \ | ||
679 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
680 | UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ | ||
681 | UNIPERIF_CTRL_BYTE_SWP_MASK(ip)) | ||
682 | #define SET_UNIPERIF_CTRL_BYTE_SWP_OFF(ip) \ | ||
683 | SET_UNIPERIF_REG(ip, \ | ||
684 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
685 | UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ | ||
686 | UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 0) | ||
687 | #define SET_UNIPERIF_CTRL_BYTE_SWP_ON(ip) \ | ||
688 | SET_UNIPERIF_REG(ip, \ | ||
689 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
690 | UNIPERIF_CTRL_BYTE_SWP_SHIFT(ip), \ | ||
691 | UNIPERIF_CTRL_BYTE_SWP_MASK(ip), 1) | ||
692 | |||
693 | /* ZERO_STUFFING_HW_SW */ | ||
694 | #define UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip) \ | ||
695 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 14 : -1) | ||
696 | #define UNIPERIF_CTRL_ZERO_STUFF_MASK(ip) 0x1 | ||
697 | #define GET_UNIPERIF_CTRL_ZERO_STUFF(ip) \ | ||
698 | GET_UNIPERIF_REG(ip, \ | ||
699 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
700 | UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ | ||
701 | UNIPERIF_CTRL_ZERO_STUFF_MASK(ip)) | ||
702 | #define SET_UNIPERIF_CTRL_ZERO_STUFF_HW(ip) \ | ||
703 | SET_UNIPERIF_REG(ip, \ | ||
704 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
705 | UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ | ||
706 | UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 1) | ||
707 | #define SET_UNIPERIF_CTRL_ZERO_STUFF_SW(ip) \ | ||
708 | SET_UNIPERIF_REG(ip, \ | ||
709 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
710 | UNIPERIF_CTRL_ZERO_STUFF_SHIFT(ip), \ | ||
711 | UNIPERIF_CTRL_ZERO_STUFF_MASK(ip), 0) | ||
712 | |||
713 | /* SPDIF_LAT */ | ||
714 | #define UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip) \ | ||
715 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 16 : -1) | ||
716 | #define UNIPERIF_CTRL_SPDIF_LAT_MASK(ip) 0x1 | ||
717 | #define GET_UNIPERIF_CTRL_SPDIF_LAT(ip) \ | ||
718 | GET_UNIPERIF_REG(ip, \ | ||
719 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
720 | UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ | ||
721 | UNIPERIF_CTRL_SPDIF_LAT_MASK(ip)) | ||
722 | #define SET_UNIPERIF_CTRL_SPDIF_LAT_ON(ip) \ | ||
723 | SET_UNIPERIF_REG(ip, \ | ||
724 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
725 | UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ | ||
726 | UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 1) | ||
727 | #define SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(ip) \ | ||
728 | SET_UNIPERIF_REG(ip, \ | ||
729 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
730 | UNIPERIF_CTRL_SPDIF_LAT_SHIFT(ip), \ | ||
731 | UNIPERIF_CTRL_SPDIF_LAT_MASK(ip), 0) | ||
732 | |||
733 | /* EN_SPDIF_FORMATTING */ | ||
734 | #define UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip) 17 | ||
735 | #define UNIPERIF_CTRL_SPDIF_FMT_MASK(ip) 0x1 | ||
736 | #define GET_UNIPERIF_CTRL_SPDIF_FMT(ip) \ | ||
737 | GET_UNIPERIF_REG(ip, \ | ||
738 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
739 | UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ | ||
740 | UNIPERIF_CTRL_SPDIF_FMT_MASK(ip)) | ||
741 | #define SET_UNIPERIF_CTRL_SPDIF_FMT_ON(ip) \ | ||
742 | SET_UNIPERIF_REG(ip, \ | ||
743 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
744 | UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ | ||
745 | UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 1) | ||
746 | #define SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(ip) \ | ||
747 | SET_UNIPERIF_REG(ip, \ | ||
748 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
749 | UNIPERIF_CTRL_SPDIF_FMT_SHIFT(ip), \ | ||
750 | UNIPERIF_CTRL_SPDIF_FMT_MASK(ip), 0) | ||
751 | |||
752 | /* READER_OUT_SELECT */ | ||
753 | #define UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip) \ | ||
754 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 18 : -1) | ||
755 | #define UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip) 0x1 | ||
756 | #define GET_UNIPERIF_CTRL_READER_OUT_SEL(ip) \ | ||
757 | GET_UNIPERIF_REG(ip, \ | ||
758 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
759 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | ||
760 | UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip)) | ||
761 | #define SET_UNIPERIF_CTRL_READER_OUT_SEL_IN_MEM(ip) \ | ||
762 | SET_UNIPERIF_REG(ip, \ | ||
763 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
764 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | ||
765 | UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 0) | ||
766 | #define SET_UNIPERIF_CTRL_READER_OUT_SEL_ON_I2S_LINE(ip) \ | ||
767 | SET_UNIPERIF_REG(ip, \ | ||
768 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
769 | UNIPERIF_CTRL_READER_OUT_SEL_SHIFT(ip), \ | ||
770 | CORAUD_UNIPERIF_CTRL_READER_OUT_SEL_MASK(ip), 1) | ||
771 | |||
772 | /* UNDERFLOW_REC_WINDOW */ | ||
773 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip) 20 | ||
774 | #define UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip) 0xff | ||
775 | #define GET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip) \ | ||
776 | GET_UNIPERIF_REG(ip, \ | ||
777 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
778 | UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ | ||
779 | UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip)) | ||
780 | #define SET_UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW(ip, value) \ | ||
781 | SET_UNIPERIF_REG(ip, \ | ||
782 | UNIPERIF_CTRL_OFFSET(ip), \ | ||
783 | UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_SHIFT(ip), \ | ||
784 | UNIPERIF_CTRL_UNDERFLOW_REC_WINDOW_MASK(ip), value) | ||
785 | |||
786 | /* | ||
787 | * UNIPERIF_I2S_FMT a.k.a UNIPERIF_FORMAT reg | ||
788 | */ | ||
789 | |||
790 | #define UNIPERIF_I2S_FMT_OFFSET(ip) 0x0048 | ||
791 | #define GET_UNIPERIF_I2S_FMT(ip) \ | ||
792 | readl_relaxed(ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) | ||
793 | #define SET_UNIPERIF_I2S_FMT(ip, value) \ | ||
794 | writel_relaxed(value, ip->base + UNIPERIF_I2S_FMT_OFFSET(ip)) | ||
795 | |||
796 | /* NBIT */ | ||
797 | #define UNIPERIF_I2S_FMT_NBIT_SHIFT(ip) 0 | ||
798 | #define UNIPERIF_I2S_FMT_NBIT_MASK(ip) 0x1 | ||
799 | #define GET_UNIPERIF_I2S_FMT_NBIT(ip) \ | ||
800 | GET_UNIPERIF_REG(ip, \ | ||
801 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
802 | UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ | ||
803 | UNIPERIF_I2S_FMT_NBIT_MASK(ip)) | ||
804 | #define SET_UNIPERIF_I2S_FMT_NBIT_32(ip) \ | ||
805 | SET_UNIPERIF_REG(ip, \ | ||
806 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
807 | UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ | ||
808 | UNIPERIF_I2S_FMT_NBIT_MASK(ip), 0) | ||
809 | #define SET_UNIPERIF_I2S_FMT_NBIT_16(ip) \ | ||
810 | SET_UNIPERIF_REG(ip, \ | ||
811 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
812 | UNIPERIF_I2S_FMT_NBIT_SHIFT(ip), \ | ||
813 | UNIPERIF_I2S_FMT_NBIT_MASK(ip), 1) | ||
814 | |||
815 | /* DATA_SIZE */ | ||
816 | #define UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip) 1 | ||
817 | #define UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip) 0x7 | ||
818 | #define GET_UNIPERIF_I2S_FMT_DATA_SIZE(ip) \ | ||
819 | GET_UNIPERIF_REG(ip, \ | ||
820 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
821 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
822 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip)) | ||
823 | #define SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(ip) \ | ||
824 | SET_UNIPERIF_REG(ip, \ | ||
825 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
826 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
827 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 0) | ||
828 | #define SET_UNIPERIF_I2S_FMT_DATA_SIZE_18(ip) \ | ||
829 | SET_UNIPERIF_REG(ip, \ | ||
830 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
831 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
832 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 1) | ||
833 | #define SET_UNIPERIF_I2S_FMT_DATA_SIZE_20(ip) \ | ||
834 | SET_UNIPERIF_REG(ip, \ | ||
835 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
836 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
837 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 2) | ||
838 | #define SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(ip) \ | ||
839 | SET_UNIPERIF_REG(ip, \ | ||
840 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
841 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
842 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 3) | ||
843 | #define SET_UNIPERIF_I2S_FMTL_DATA_SIZE_28(ip) \ | ||
844 | SET_UNIPERIF_REG(ip, \ | ||
845 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
846 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
847 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 4) | ||
848 | #define SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(ip) \ | ||
849 | SET_UNIPERIF_REG(ip, \ | ||
850 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
851 | UNIPERIF_I2S_FMT_DATA_SIZE_SHIFT(ip), \ | ||
852 | UNIPERIF_I2S_FMT_DATA_SIZE_MASK(ip), 5) | ||
853 | |||
854 | /* LR_POL */ | ||
855 | #define UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip) 4 | ||
856 | #define UNIPERIF_I2S_FMT_LR_POL_MASK(ip) 0x1 | ||
857 | #define VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) 0x0 | ||
858 | #define VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) 0x1 | ||
859 | #define GET_UNIPERIF_I2S_FMT_LR_POL(ip) \ | ||
860 | GET_UNIPERIF_REG(ip, \ | ||
861 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
862 | UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ | ||
863 | UNIPERIF_I2S_FMT_LR_POL_MASK(ip)) | ||
864 | #define SET_UNIPERIF_I2S_FMT_LR_POL(ip, value) \ | ||
865 | SET_UNIPERIF_REG(ip, \ | ||
866 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
867 | UNIPERIF_I2S_FMT_LR_POL_SHIFT(ip), \ | ||
868 | UNIPERIF_I2S_FMT_LR_POL_MASK(ip), value) | ||
869 | #define SET_UNIPERIF_I2S_FMT_LR_POL_LOW(ip) \ | ||
870 | SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ | ||
871 | VALUE_UNIPERIF_I2S_FMT_LR_POL_LOW(ip)) | ||
872 | #define SET_UNIPERIF_I2S_FMT_LR_POL_HIG(ip) \ | ||
873 | SET_UNIPERIF_I2S_FMT_LR_POL(ip, \ | ||
874 | VALUE_UNIPERIF_I2S_FMT_LR_POL_HIG(ip)) | ||
875 | |||
876 | /* SCLK_EDGE */ | ||
877 | #define UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip) 5 | ||
878 | #define UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip) 0x1 | ||
879 | #define GET_UNIPERIF_I2S_FMT_SCLK_EDGE(ip) \ | ||
880 | GET_UNIPERIF_REG(ip, \ | ||
881 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
882 | UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ | ||
883 | UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip)) | ||
884 | #define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(ip) \ | ||
885 | SET_UNIPERIF_REG(ip, \ | ||
886 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
887 | UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ | ||
888 | UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 0) | ||
889 | #define SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(ip) \ | ||
890 | SET_UNIPERIF_REG(ip, \ | ||
891 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
892 | UNIPERIF_I2S_FMT_SCLK_EDGE_SHIFT(ip), \ | ||
893 | UNIPERIF_I2S_FMT_SCLK_EDGE_MASK(ip), 1) | ||
894 | |||
895 | /* PADDING */ | ||
896 | #define UNIPERIF_I2S_FMT_PADDING_SHIFT(ip) 6 | ||
897 | #define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 | ||
898 | #define UNIPERIF_I2S_FMT_PADDING_MASK(ip) 0x1 | ||
899 | #define VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) 0x0 | ||
900 | #define VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) 0x1 | ||
901 | #define GET_UNIPERIF_I2S_FMT_PADDING(ip) \ | ||
902 | GET_UNIPERIF_REG(ip, \ | ||
903 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
904 | UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ | ||
905 | UNIPERIF_I2S_FMT_PADDING_MASK(ip)) | ||
906 | #define SET_UNIPERIF_I2S_FMT_PADDING(ip, value) \ | ||
907 | SET_UNIPERIF_REG(ip, \ | ||
908 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
909 | UNIPERIF_I2S_FMT_PADDING_SHIFT(ip), \ | ||
910 | UNIPERIF_I2S_FMT_PADDING_MASK(ip), value) | ||
911 | #define SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip) \ | ||
912 | SET_UNIPERIF_I2S_FMT_PADDING(ip, \ | ||
913 | VALUE_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(ip)) | ||
914 | #define SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip) \ | ||
915 | SET_UNIPERIF_I2S_FMT_PADDING(ip, \ | ||
916 | VALUE_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(ip)) | ||
917 | |||
918 | /* ALIGN */ | ||
919 | #define UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip) 7 | ||
920 | #define UNIPERIF_I2S_FMT_ALIGN_MASK(ip) 0x1 | ||
921 | #define GET_UNIPERIF_I2S_FMT_ALIGN(ip) \ | ||
922 | GET_UNIPERIF_REG(ip, \ | ||
923 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
924 | UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ | ||
925 | UNIPERIF_I2S_FMT_ALIGN_MASK(ip)) | ||
926 | #define SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(ip) \ | ||
927 | SET_UNIPERIF_REG(ip, \ | ||
928 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
929 | UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ | ||
930 | UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 0) | ||
931 | #define SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(ip) \ | ||
932 | SET_UNIPERIF_REG(ip, \ | ||
933 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
934 | UNIPERIF_I2S_FMT_ALIGN_SHIFT(ip), \ | ||
935 | UNIPERIF_I2S_FMT_ALIGN_MASK(ip), 1) | ||
936 | |||
937 | /* ORDER */ | ||
938 | #define UNIPERIF_I2S_FMT_ORDER_SHIFT(ip) 8 | ||
939 | #define UNIPERIF_I2S_FMT_ORDER_MASK(ip) 0x1 | ||
940 | #define GET_UNIPERIF_I2S_FMT_ORDER(ip) \ | ||
941 | GET_UNIPERIF_REG(ip, \ | ||
942 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
943 | UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ | ||
944 | UNIPERIF_I2S_FMT_ORDER_MASK(ip)) | ||
945 | #define SET_UNIPERIF_I2S_FMT_ORDER_LSB(ip) \ | ||
946 | SET_UNIPERIF_REG(ip, \ | ||
947 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
948 | UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ | ||
949 | UNIPERIF_I2S_FMT_ORDER_MASK(ip), 0) | ||
950 | #define SET_UNIPERIF_I2S_FMT_ORDER_MSB(ip) \ | ||
951 | SET_UNIPERIF_REG(ip, \ | ||
952 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
953 | UNIPERIF_I2S_FMT_ORDER_SHIFT(ip), \ | ||
954 | UNIPERIF_I2S_FMT_ORDER_MASK(ip), 1) | ||
955 | |||
956 | /* NUM_CH */ | ||
957 | #define UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip) 9 | ||
958 | #define UNIPERIF_I2S_FMT_NUM_CH_MASK(ip) 0x7 | ||
959 | #define GET_UNIPERIF_I2S_FMT_NUM_CH(ip) \ | ||
960 | GET_UNIPERIF_REG(ip, \ | ||
961 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
962 | UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ | ||
963 | UNIPERIF_I2S_FMT_NUM_CH_MASK(ip)) | ||
964 | #define SET_UNIPERIF_I2S_FMT_NUM_CH(ip, value) \ | ||
965 | SET_UNIPERIF_REG(ip, \ | ||
966 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
967 | UNIPERIF_I2S_FMT_NUM_CH_SHIFT(ip), \ | ||
968 | UNIPERIF_I2S_FMT_NUM_CH_MASK(ip), value) | ||
969 | |||
970 | /* NO_OF_SAMPLES_TO_READ */ | ||
971 | #define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip) 12 | ||
972 | #define UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip) 0xfffff | ||
973 | #define GET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip) \ | ||
974 | GET_UNIPERIF_REG(ip, \ | ||
975 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
976 | UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ | ||
977 | UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip)) | ||
978 | #define SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(ip, value) \ | ||
979 | SET_UNIPERIF_REG(ip, \ | ||
980 | UNIPERIF_I2S_FMT_OFFSET(ip), \ | ||
981 | UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_SHIFT(ip), \ | ||
982 | UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ_MASK(ip), value) | ||
983 | |||
984 | /* | ||
985 | * UNIPERIF_BIT_CONTROL reg | ||
986 | */ | ||
987 | |||
988 | #define UNIPERIF_BIT_CONTROL_OFFSET(ip) \ | ||
989 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0x004c) | ||
990 | #define GET_UNIPERIF_BIT_CONTROL(ip) \ | ||
991 | readl_relaxed(ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) | ||
992 | #define SET_UNIPERIF_BIT_CONTROL(ip, value) \ | ||
993 | writel_relaxed(value, ip->base + UNIPERIF_BIT_CONTROL_OFFSET(ip)) | ||
994 | |||
995 | /* CLR_UNDERFLOW_DURATION */ | ||
996 | #define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip) 0 | ||
997 | #define UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip) 0x1 | ||
998 | #define GET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ | ||
999 | GET_UNIPERIF_REG(ip, \ | ||
1000 | UNIPERIF_BIT_CONTROL_OFFSET(ip), \ | ||
1001 | UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ | ||
1002 | UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip)) | ||
1003 | #define SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(ip) \ | ||
1004 | SET_UNIPERIF_REG(ip, \ | ||
1005 | UNIPERIF_BIT_CONTROL_OFFSET(ip), \ | ||
1006 | UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_SHIFT(ip), \ | ||
1007 | UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION_MASK(ip), 1) | ||
1008 | |||
1009 | /* CHL_STS_UPDATE */ | ||
1010 | #define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip) 1 | ||
1011 | #define UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip) 0x1 | ||
1012 | #define GET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ | ||
1013 | GET_UNIPERIF_REG(ip, \ | ||
1014 | UNIPERIF_BIT_CONTROL_OFFSET(ip), \ | ||
1015 | UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ | ||
1016 | UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip)) | ||
1017 | #define SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(ip) \ | ||
1018 | SET_UNIPERIF_BIT_REG(ip, \ | ||
1019 | UNIPERIF_BIT_CONTROL_OFFSET(ip), \ | ||
1020 | UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_SHIFT(ip), \ | ||
1021 | UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE_MASK(ip), 1) | ||
1022 | |||
1023 | /* | ||
1024 | * UNIPERIF_STATUS_1 reg | ||
1025 | */ | ||
1026 | |||
1027 | #define UNIPERIF_STATUS_1_OFFSET(ip) 0x0050 | ||
1028 | #define GET_UNIPERIF_STATUS_1(ip) \ | ||
1029 | readl_relaxed(ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) | ||
1030 | #define SET_UNIPERIF_STATUS_1(ip, value) \ | ||
1031 | writel_relaxed(value, ip->base + UNIPERIF_STATUS_1_OFFSET(ip)) | ||
1032 | |||
1033 | /* UNDERFLOW_DURATION */ | ||
1034 | #define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip) \ | ||
1035 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) | ||
1036 | #define UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip) 0xff | ||
1037 | #define GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip) \ | ||
1038 | GET_UNIPERIF_REG(ip, \ | ||
1039 | UNIPERIF_STATUS_1_OFFSET(ip), \ | ||
1040 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ | ||
1041 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip)) | ||
1042 | #define SET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(ip, value) \ | ||
1043 | SET_UNIPERIF_REG(ip, \ | ||
1044 | UNIPERIF_STATUS_1_OFFSET(ip), \ | ||
1045 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_SHIFT(ip), \ | ||
1046 | UNIPERIF_STATUS_1_UNDERFLOW_DURATION_MASK(ip), value) | ||
1047 | |||
1048 | /* | ||
1049 | * AUD_UNIPERIF_CHANNEL_STA_REGN reg | ||
1050 | */ | ||
1051 | |||
1052 | #define UNIPERIF_CHANNEL_STA_REGN(ip, n) (0x0060 + (4 * n)) | ||
1053 | #define GET_UNIPERIF_CHANNEL_STA_REGN(ip) \ | ||
1054 | readl_relaxed(ip->base + UNIPERIF_CHANNEL_STA_REGN(ip, n)) | ||
1055 | #define SET_UNIPERIF_CHANNEL_STA_REGN(ip, n, value) \ | ||
1056 | writel_relaxed(value, ip->base + \ | ||
1057 | UNIPERIF_CHANNEL_STA_REGN(ip, n)) | ||
1058 | |||
1059 | /* | ||
1060 | * AUD_UNIPERIF_USER_VALIDITY reg | ||
1061 | */ | ||
1062 | |||
1063 | #define UNIPERIF_USER_VALIDITY_OFFSET(ip) 0x0090 | ||
1064 | #define GET_UNIPERIF_USER_VALIDITY(ip) \ | ||
1065 | readl_relaxed(ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) | ||
1066 | #define SET_UNIPERIF_USER_VALIDITY(ip, value) \ | ||
1067 | writel_relaxed(value, ip->base + UNIPERIF_USER_VALIDITY_OFFSET(ip)) | ||
1068 | |||
1069 | /* VALIDITY_LEFT_AND_RIGHT */ | ||
1070 | #define UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip) 0 | ||
1071 | #define UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip) 0x3 | ||
1072 | #define GET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip) \ | ||
1073 | GET_UNIPERIF_REG(ip, \ | ||
1074 | UNIPERIF_USER_VALIDITY_OFFSET(ip), \ | ||
1075 | UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ | ||
1076 | UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip)) | ||
1077 | #define SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(ip, value) \ | ||
1078 | SET_UNIPERIF_REG(ip, \ | ||
1079 | UNIPERIF_USER_VALIDITY_OFFSET(ip), \ | ||
1080 | UNIPERIF_USER_VALIDITY_VALIDITY_LR_SHIFT(ip), \ | ||
1081 | UNIPERIF_USER_VALIDITY_VALIDITY_LR_MASK(ip), \ | ||
1082 | value ? 0x3 : 0) | ||
1083 | |||
1084 | /* | ||
1085 | * UNIPERIF_DBG_STANDBY_LEFT_SP reg | ||
1086 | */ | ||
1087 | #define UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip) 0x0150 | ||
1088 | #define UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip) \ | ||
1089 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? -1 : 0) | ||
1090 | #define UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip) \ | ||
1091 | ((ip)->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 ? 0 : 0xFFFFFF) | ||
1092 | #define GET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip) \ | ||
1093 | GET_UNIPERIF_REG(ip, \ | ||
1094 | UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ | ||
1095 | UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ | ||
1096 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip)) | ||
1097 | #define SET_UNIPERIF_DBG_STANDBY_LEFT_SP(ip, value) \ | ||
1098 | SET_UNIPERIF_REG(ip, \ | ||
1099 | UNIPERIF_DBG_STANDBY_LEFT_SP_OFFSET(ip), \ | ||
1100 | UNIPERIF_DBG_STANDBY_LEFT_SP_SHIFT(ip), \ | ||
1101 | UNIPERIF_DBG_STANDBY_LEFT_SP_MASK(ip), value) | ||
1102 | |||
1103 | /* | ||
1104 | * uniperipheral IP capabilities | ||
1105 | */ | ||
1106 | |||
1107 | #define UNIPERIF_FIFO_SIZE 70 /* FIFO is 70 cells deep */ | ||
1108 | #define UNIPERIF_FIFO_FRAMES 4 /* FDMA trigger limit in frames */ | ||
1109 | |||
1110 | /* | ||
1111 | * Uniperipheral IP revisions | ||
1112 | */ | ||
1113 | enum uniperif_version { | ||
1114 | SND_ST_UNIPERIF_VERSION_UNKNOWN, | ||
1115 | /* SASG1 (Orly), Newman */ | ||
1116 | SND_ST_UNIPERIF_VERSION_C6AUD0_UNI_1_0, | ||
1117 | /* SASC1, SASG2 (Orly2) */ | ||
1118 | SND_ST_UNIPERIF_VERSION_UNI_PLR_1_0, | ||
1119 | /* SASC1, SASG2 (Orly2), TELSS, Cannes */ | ||
1120 | SND_ST_UNIPERIF_VERSION_UNI_RDR_1_0, | ||
1121 | /* TELSS (SASC1) */ | ||
1122 | SND_ST_UNIPERIF_VERSION_TDM_PLR_1_0, | ||
1123 | /* Cannes/Monaco */ | ||
1124 | SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
1125 | }; | ||
1126 | |||
1127 | enum uniperif_type { | ||
1128 | SND_ST_UNIPERIF_PLAYER_TYPE_NONE, | ||
1129 | SND_ST_UNIPERIF_PLAYER_TYPE_HDMI, | ||
1130 | SND_ST_UNIPERIF_PLAYER_TYPE_PCM, | ||
1131 | SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF | ||
1132 | }; | ||
1133 | |||
1134 | enum uniperif_state { | ||
1135 | UNIPERIF_STATE_STOPPED, | ||
1136 | UNIPERIF_STATE_STARTED, | ||
1137 | UNIPERIF_STATE_STANDBY, | ||
1138 | UNIPERIF_STATE_UNDERFLOW, | ||
1139 | UNIPERIF_STATE_OVERFLOW = UNIPERIF_STATE_UNDERFLOW, | ||
1140 | UNIPERIF_STATE_XRUN | ||
1141 | }; | ||
1142 | |||
1143 | enum uniperif_iec958_encoding_mode { | ||
1144 | UNIPERIF_IEC958_ENCODING_MODE_PCM, | ||
1145 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED | ||
1146 | }; | ||
1147 | |||
1148 | struct uniperif_info { | ||
1149 | int id; /* instance value of the uniperipheral IP */ | ||
1150 | enum uniperif_type player_type; | ||
1151 | int underflow_enabled; /* Underflow recovery mode */ | ||
1152 | }; | ||
1153 | |||
1154 | struct uniperif_iec958_settings { | ||
1155 | enum uniperif_iec958_encoding_mode encoding_mode; | ||
1156 | struct snd_aes_iec958 iec958; | ||
1157 | }; | ||
1158 | |||
1159 | struct uniperif { | ||
1160 | /* System information */ | ||
1161 | struct uniperif_info *info; | ||
1162 | struct device *dev; | ||
1163 | int ver; /* IP version, used by register access macros */ | ||
1164 | struct regmap_field *clk_sel; | ||
1165 | |||
1166 | /* capabilities */ | ||
1167 | const struct snd_pcm_hardware *hw; | ||
1168 | |||
1169 | /* Resources */ | ||
1170 | struct resource *mem_region; | ||
1171 | void __iomem *base; | ||
1172 | unsigned long fifo_phys_address; | ||
1173 | int irq; | ||
1174 | |||
1175 | /* Clocks */ | ||
1176 | struct clk *clk; | ||
1177 | int mclk; | ||
1178 | int clk_adj; | ||
1179 | |||
1180 | /* Runtime data */ | ||
1181 | enum uniperif_state state; | ||
1182 | |||
1183 | struct snd_pcm_substream *substream; | ||
1184 | |||
1185 | /* Specific to IEC958 player */ | ||
1186 | struct uniperif_iec958_settings stream_settings; | ||
1187 | struct mutex ctrl_lock; /* For resource updated by stream and controls*/ | ||
1188 | |||
1189 | /*alsa ctrl*/ | ||
1190 | struct snd_kcontrol_new *snd_ctrls; | ||
1191 | int num_ctrls; | ||
1192 | |||
1193 | /* dai properties */ | ||
1194 | unsigned int daifmt; | ||
1195 | |||
1196 | /* DAI callbacks */ | ||
1197 | const struct snd_soc_dai_ops *dai_ops; | ||
1198 | }; | ||
1199 | |||
1200 | struct sti_uniperiph_dai { | ||
1201 | int stream; | ||
1202 | struct uniperif *uni; | ||
1203 | struct snd_dmaengine_dai_dma_data dma_data; | ||
1204 | }; | ||
1205 | |||
1206 | struct sti_uniperiph_data { | ||
1207 | struct platform_device *pdev; | ||
1208 | struct snd_soc_dai_driver *dai; | ||
1209 | struct sti_uniperiph_dai dai_data; | ||
1210 | }; | ||
1211 | |||
1212 | /* uniperiph player*/ | ||
1213 | int uni_player_init(struct platform_device *pdev, | ||
1214 | struct uniperif *uni_player); | ||
1215 | int uni_player_resume(struct uniperif *player); | ||
1216 | |||
1217 | /* uniperiph reader */ | ||
1218 | int uni_reader_init(struct platform_device *pdev, | ||
1219 | struct uniperif *uni_reader); | ||
1220 | |||
1221 | /* common */ | ||
1222 | int sti_uniperiph_dai_set_fmt(struct snd_soc_dai *dai, | ||
1223 | unsigned int fmt); | ||
1224 | |||
1225 | int sti_uniperiph_dai_hw_params(struct snd_pcm_substream *substream, | ||
1226 | struct snd_pcm_hw_params *params, | ||
1227 | struct snd_soc_dai *dai); | ||
1228 | |||
1229 | #endif | ||
diff --git a/sound/soc/sti/uniperif_player.c b/sound/soc/sti/uniperif_player.c new file mode 100644 index 000000000000..f6eefe1b8f8f --- /dev/null +++ b/sound/soc/sti/uniperif_player.c | |||
@@ -0,0 +1,1110 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> | ||
4 | * for STMicroelectronics. | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/clk.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/io.h> | ||
11 | #include <linux/mfd/syscon.h> | ||
12 | |||
13 | #include <sound/asoundef.h> | ||
14 | #include <sound/soc.h> | ||
15 | |||
16 | #include "uniperif.h" | ||
17 | |||
18 | /* | ||
19 | * Some hardware-related definitions | ||
20 | */ | ||
21 | |||
22 | /* sys config registers definitions */ | ||
23 | #define SYS_CFG_AUDIO_GLUE 0xA4 | ||
24 | #define SYS_CFG_AUDI0_GLUE_PCM_CLKX 8 | ||
25 | |||
26 | /* | ||
27 | * Driver specific types. | ||
28 | */ | ||
29 | #define UNIPERIF_PLAYER_TYPE_IS_HDMI(p) \ | ||
30 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_HDMI) | ||
31 | #define UNIPERIF_PLAYER_TYPE_IS_PCM(p) \ | ||
32 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_PCM) | ||
33 | #define UNIPERIF_PLAYER_TYPE_IS_SPDIF(p) \ | ||
34 | ((p)->info->player_type == SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF) | ||
35 | #define UNIPERIF_PLAYER_TYPE_IS_IEC958(p) \ | ||
36 | (UNIPERIF_PLAYER_TYPE_IS_HDMI(p) || \ | ||
37 | UNIPERIF_PLAYER_TYPE_IS_SPDIF(p)) | ||
38 | |||
39 | #define UNIPERIF_PLAYER_CLK_ADJ_MIN -999999 | ||
40 | #define UNIPERIF_PLAYER_CLK_ADJ_MAX 1000000 | ||
41 | |||
42 | /* | ||
43 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to | ||
44 | * integrate DAI_CPU capability in term of rate and supported channels | ||
45 | */ | ||
46 | static const struct snd_pcm_hardware uni_player_pcm_hw = { | ||
47 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
48 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | | ||
49 | SNDRV_PCM_INFO_MMAP_VALID, | ||
50 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
51 | |||
52 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
53 | .rate_min = 8000, | ||
54 | .rate_max = 192000, | ||
55 | |||
56 | .channels_min = 2, | ||
57 | .channels_max = 8, | ||
58 | |||
59 | .periods_min = 2, | ||
60 | .periods_max = 48, | ||
61 | |||
62 | .period_bytes_min = 128, | ||
63 | .period_bytes_max = 64 * PAGE_SIZE, | ||
64 | .buffer_bytes_max = 256 * PAGE_SIZE | ||
65 | }; | ||
66 | |||
67 | static inline int reset_player(struct uniperif *player) | ||
68 | { | ||
69 | int count = 10; | ||
70 | |||
71 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { | ||
72 | while (GET_UNIPERIF_SOFT_RST_SOFT_RST(player) && count) { | ||
73 | udelay(5); | ||
74 | count--; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | if (!count) { | ||
79 | dev_err(player->dev, "Failed to reset uniperif"); | ||
80 | return -EIO; | ||
81 | } | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | /* | ||
87 | * uni_player_irq_handler | ||
88 | * In case of error audio stream is stopped; stop action is protected via PCM | ||
89 | * stream lock to avoid race condition with trigger callback. | ||
90 | */ | ||
91 | static irqreturn_t uni_player_irq_handler(int irq, void *dev_id) | ||
92 | { | ||
93 | irqreturn_t ret = IRQ_NONE; | ||
94 | struct uniperif *player = dev_id; | ||
95 | unsigned int status; | ||
96 | unsigned int tmp; | ||
97 | |||
98 | if (player->state == UNIPERIF_STATE_STOPPED) { | ||
99 | /* Unexpected IRQ: do nothing */ | ||
100 | return IRQ_NONE; | ||
101 | } | ||
102 | |||
103 | /* Get interrupt status & clear them immediately */ | ||
104 | status = GET_UNIPERIF_ITS(player); | ||
105 | SET_UNIPERIF_ITS_BCLR(player, status); | ||
106 | |||
107 | /* Check for fifo error (underrun) */ | ||
108 | if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(player))) { | ||
109 | dev_err(player->dev, "FIFO underflow error detected"); | ||
110 | |||
111 | /* Interrupt is just for information when underflow recovery */ | ||
112 | if (player->info->underflow_enabled) { | ||
113 | /* Update state to underflow */ | ||
114 | player->state = UNIPERIF_STATE_UNDERFLOW; | ||
115 | |||
116 | } else { | ||
117 | /* Disable interrupt so doesn't continually fire */ | ||
118 | SET_UNIPERIF_ITM_BCLR_FIFO_ERROR(player); | ||
119 | |||
120 | /* Stop the player */ | ||
121 | snd_pcm_stream_lock(player->substream); | ||
122 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | ||
123 | snd_pcm_stream_unlock(player->substream); | ||
124 | } | ||
125 | |||
126 | ret = IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | /* Check for dma error (overrun) */ | ||
130 | if (unlikely(status & UNIPERIF_ITS_DMA_ERROR_MASK(player))) { | ||
131 | dev_err(player->dev, "DMA error detected"); | ||
132 | |||
133 | /* Disable interrupt so doesn't continually fire */ | ||
134 | SET_UNIPERIF_ITM_BCLR_DMA_ERROR(player); | ||
135 | |||
136 | /* Stop the player */ | ||
137 | snd_pcm_stream_lock(player->substream); | ||
138 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | ||
139 | snd_pcm_stream_unlock(player->substream); | ||
140 | |||
141 | ret = IRQ_HANDLED; | ||
142 | } | ||
143 | |||
144 | /* Check for underflow recovery done */ | ||
145 | if (unlikely(status & UNIPERIF_ITM_UNDERFLOW_REC_DONE_MASK(player))) { | ||
146 | if (!player->info->underflow_enabled) { | ||
147 | dev_err(player->dev, "unexpected Underflow recovering"); | ||
148 | return -EPERM; | ||
149 | } | ||
150 | /* Read the underflow recovery duration */ | ||
151 | tmp = GET_UNIPERIF_STATUS_1_UNDERFLOW_DURATION(player); | ||
152 | |||
153 | /* Clear the underflow recovery duration */ | ||
154 | SET_UNIPERIF_BIT_CONTROL_CLR_UNDERFLOW_DURATION(player); | ||
155 | |||
156 | /* Update state to started */ | ||
157 | player->state = UNIPERIF_STATE_STARTED; | ||
158 | |||
159 | ret = IRQ_HANDLED; | ||
160 | } | ||
161 | |||
162 | /* Check if underflow recovery failed */ | ||
163 | if (unlikely(status & | ||
164 | UNIPERIF_ITM_UNDERFLOW_REC_FAILED_MASK(player))) { | ||
165 | dev_err(player->dev, "Underflow recovery failed"); | ||
166 | |||
167 | /* Stop the player */ | ||
168 | snd_pcm_stream_lock(player->substream); | ||
169 | snd_pcm_stop(player->substream, SNDRV_PCM_STATE_XRUN); | ||
170 | snd_pcm_stream_unlock(player->substream); | ||
171 | |||
172 | ret = IRQ_HANDLED; | ||
173 | } | ||
174 | |||
175 | return ret; | ||
176 | } | ||
177 | |||
178 | static int uni_player_clk_set_rate(struct uniperif *player, unsigned long rate) | ||
179 | { | ||
180 | int rate_adjusted, rate_achieved, delta, ret; | ||
181 | int adjustment = player->clk_adj; | ||
182 | |||
183 | /* | ||
184 | * a | ||
185 | * F = f + --------- * f = f + d | ||
186 | * 1000000 | ||
187 | * | ||
188 | * a | ||
189 | * d = --------- * f | ||
190 | * 1000000 | ||
191 | * | ||
192 | * where: | ||
193 | * f - nominal rate | ||
194 | * a - adjustment in ppm (parts per milion) | ||
195 | * F - rate to be set in synthesizer | ||
196 | * d - delta (difference) between f and F | ||
197 | */ | ||
198 | if (adjustment < 0) { | ||
199 | /* div64_64 operates on unsigned values... */ | ||
200 | delta = -1; | ||
201 | adjustment = -adjustment; | ||
202 | } else { | ||
203 | delta = 1; | ||
204 | } | ||
205 | /* 500000 ppm is 0.5, which is used to round up values */ | ||
206 | delta *= (int)div64_u64((uint64_t)rate * | ||
207 | (uint64_t)adjustment + 500000, 1000000); | ||
208 | rate_adjusted = rate + delta; | ||
209 | |||
210 | /* Adjusted rate should never be == 0 */ | ||
211 | if (!rate_adjusted) | ||
212 | return -EINVAL; | ||
213 | |||
214 | ret = clk_set_rate(player->clk, rate_adjusted); | ||
215 | if (ret < 0) | ||
216 | return ret; | ||
217 | |||
218 | rate_achieved = clk_get_rate(player->clk); | ||
219 | if (!rate_achieved) | ||
220 | /* If value is 0 means that clock or parent not valid */ | ||
221 | return -EINVAL; | ||
222 | |||
223 | /* | ||
224 | * Using ALSA's adjustment control, we can modify the rate to be up | ||
225 | * to twice as much as requested, but no more | ||
226 | */ | ||
227 | delta = rate_achieved - rate; | ||
228 | if (delta < 0) { | ||
229 | /* div64_64 operates on unsigned values... */ | ||
230 | delta = -delta; | ||
231 | adjustment = -1; | ||
232 | } else { | ||
233 | adjustment = 1; | ||
234 | } | ||
235 | /* Frequency/2 is added to round up result */ | ||
236 | adjustment *= (int)div64_u64((uint64_t)delta * 1000000 + rate / 2, | ||
237 | rate); | ||
238 | player->clk_adj = adjustment; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | static void uni_player_set_channel_status(struct uniperif *player, | ||
243 | struct snd_pcm_runtime *runtime) | ||
244 | { | ||
245 | int n; | ||
246 | unsigned int status; | ||
247 | |||
248 | /* | ||
249 | * Some AVRs and TVs require the channel status to contain a correct | ||
250 | * sampling frequency. If no sample rate is already specified, then | ||
251 | * set one. | ||
252 | */ | ||
253 | mutex_lock(&player->ctrl_lock); | ||
254 | if (runtime && (player->stream_settings.iec958.status[3] | ||
255 | == IEC958_AES3_CON_FS_NOTID)) { | ||
256 | switch (runtime->rate) { | ||
257 | case 22050: | ||
258 | player->stream_settings.iec958.status[3] = | ||
259 | IEC958_AES3_CON_FS_22050; | ||
260 | break; | ||
261 | case 44100: | ||
262 | player->stream_settings.iec958.status[3] = | ||
263 | IEC958_AES3_CON_FS_44100; | ||
264 | break; | ||
265 | case 88200: | ||
266 | player->stream_settings.iec958.status[3] = | ||
267 | IEC958_AES3_CON_FS_88200; | ||
268 | break; | ||
269 | case 176400: | ||
270 | player->stream_settings.iec958.status[3] = | ||
271 | IEC958_AES3_CON_FS_176400; | ||
272 | break; | ||
273 | case 24000: | ||
274 | player->stream_settings.iec958.status[3] = | ||
275 | IEC958_AES3_CON_FS_24000; | ||
276 | break; | ||
277 | case 48000: | ||
278 | player->stream_settings.iec958.status[3] = | ||
279 | IEC958_AES3_CON_FS_48000; | ||
280 | break; | ||
281 | case 96000: | ||
282 | player->stream_settings.iec958.status[3] = | ||
283 | IEC958_AES3_CON_FS_96000; | ||
284 | break; | ||
285 | case 192000: | ||
286 | player->stream_settings.iec958.status[3] = | ||
287 | IEC958_AES3_CON_FS_192000; | ||
288 | break; | ||
289 | case 32000: | ||
290 | player->stream_settings.iec958.status[3] = | ||
291 | IEC958_AES3_CON_FS_32000; | ||
292 | break; | ||
293 | default: | ||
294 | /* Mark as sampling frequency not indicated */ | ||
295 | player->stream_settings.iec958.status[3] = | ||
296 | IEC958_AES3_CON_FS_NOTID; | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | /* Audio mode: | ||
302 | * Use audio mode status to select PCM or encoded mode | ||
303 | */ | ||
304 | if (player->stream_settings.iec958.status[0] & IEC958_AES0_NONAUDIO) | ||
305 | player->stream_settings.encoding_mode = | ||
306 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED; | ||
307 | else | ||
308 | player->stream_settings.encoding_mode = | ||
309 | UNIPERIF_IEC958_ENCODING_MODE_PCM; | ||
310 | |||
311 | if (player->stream_settings.encoding_mode == | ||
312 | UNIPERIF_IEC958_ENCODING_MODE_PCM) | ||
313 | /* Clear user validity bits */ | ||
314 | SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); | ||
315 | else | ||
316 | /* Set user validity bits */ | ||
317 | SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 1); | ||
318 | |||
319 | /* Program the new channel status */ | ||
320 | for (n = 0; n < 6; ++n) { | ||
321 | status = | ||
322 | player->stream_settings.iec958.status[0 + (n * 4)] & 0xf; | ||
323 | status |= | ||
324 | player->stream_settings.iec958.status[1 + (n * 4)] << 8; | ||
325 | status |= | ||
326 | player->stream_settings.iec958.status[2 + (n * 4)] << 16; | ||
327 | status |= | ||
328 | player->stream_settings.iec958.status[3 + (n * 4)] << 24; | ||
329 | SET_UNIPERIF_CHANNEL_STA_REGN(player, n, status); | ||
330 | } | ||
331 | mutex_unlock(&player->ctrl_lock); | ||
332 | |||
333 | /* Update the channel status */ | ||
334 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
335 | SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); | ||
336 | else | ||
337 | SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); | ||
338 | } | ||
339 | |||
340 | static int uni_player_prepare_iec958(struct uniperif *player, | ||
341 | struct snd_pcm_runtime *runtime) | ||
342 | { | ||
343 | int clk_div; | ||
344 | |||
345 | clk_div = player->mclk / runtime->rate; | ||
346 | |||
347 | /* Oversampling must be multiple of 128 as iec958 frame is 32-bits */ | ||
348 | if ((clk_div % 128) || (clk_div <= 0)) { | ||
349 | dev_err(player->dev, "%s: invalid clk_div %d", | ||
350 | __func__, clk_div); | ||
351 | return -EINVAL; | ||
352 | } | ||
353 | |||
354 | switch (runtime->format) { | ||
355 | case SNDRV_PCM_FORMAT_S16_LE: | ||
356 | /* 16/16 memory format */ | ||
357 | SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); | ||
358 | /* 16-bits per sub-frame */ | ||
359 | SET_UNIPERIF_I2S_FMT_NBIT_32(player); | ||
360 | /* Set 16-bit sample precision */ | ||
361 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); | ||
362 | break; | ||
363 | case SNDRV_PCM_FORMAT_S32_LE: | ||
364 | /* 16/0 memory format */ | ||
365 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); | ||
366 | /* 32-bits per sub-frame */ | ||
367 | SET_UNIPERIF_I2S_FMT_NBIT_32(player); | ||
368 | /* Set 24-bit sample precision */ | ||
369 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_24(player); | ||
370 | break; | ||
371 | default: | ||
372 | dev_err(player->dev, "format not supported"); | ||
373 | return -EINVAL; | ||
374 | } | ||
375 | |||
376 | /* Set parity to be calculated by the hardware */ | ||
377 | SET_UNIPERIF_CONFIG_PARITY_CNTR_BY_HW(player); | ||
378 | |||
379 | /* Set channel status bits to be inserted by the hardware */ | ||
380 | SET_UNIPERIF_CONFIG_CHANNEL_STA_CNTR_BY_HW(player); | ||
381 | |||
382 | /* Set user data bits to be inserted by the hardware */ | ||
383 | SET_UNIPERIF_CONFIG_USER_DAT_CNTR_BY_HW(player); | ||
384 | |||
385 | /* Set validity bits to be inserted by the hardware */ | ||
386 | SET_UNIPERIF_CONFIG_VALIDITY_DAT_CNTR_BY_HW(player); | ||
387 | |||
388 | /* Set full software control to disabled */ | ||
389 | SET_UNIPERIF_CONFIG_SPDIF_SW_CTRL_DISABLE(player); | ||
390 | |||
391 | SET_UNIPERIF_CTRL_ZERO_STUFF_HW(player); | ||
392 | |||
393 | /* Update the channel status */ | ||
394 | uni_player_set_channel_status(player, runtime); | ||
395 | |||
396 | /* Clear the user validity user bits */ | ||
397 | SET_UNIPERIF_USER_VALIDITY_VALIDITY_LR(player, 0); | ||
398 | |||
399 | /* Disable one-bit audio mode */ | ||
400 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); | ||
401 | |||
402 | /* Enable consecutive frames repetition of Z preamble (not for HBRA) */ | ||
403 | SET_UNIPERIF_CONFIG_REPEAT_CHL_STS_ENABLE(player); | ||
404 | |||
405 | /* Change to SUF0_SUBF1 and left/right channels swap! */ | ||
406 | SET_UNIPERIF_CONFIG_SUBFRAME_SEL_SUBF1_SUBF0(player); | ||
407 | |||
408 | /* Set data output as MSB first */ | ||
409 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | ||
410 | |||
411 | if (player->stream_settings.encoding_mode == | ||
412 | UNIPERIF_IEC958_ENCODING_MODE_ENCODED) | ||
413 | SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_ON(player); | ||
414 | else | ||
415 | SET_UNIPERIF_CTRL_EXIT_STBY_ON_EOBLOCK_OFF(player); | ||
416 | |||
417 | SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); | ||
418 | |||
419 | /* Set rounding to off */ | ||
420 | SET_UNIPERIF_CTRL_ROUNDING_OFF(player); | ||
421 | |||
422 | /* Set clock divisor */ | ||
423 | SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / 128); | ||
424 | |||
425 | /* Set the spdif latency to not wait before starting player */ | ||
426 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | ||
427 | |||
428 | /* | ||
429 | * Ensure iec958 formatting is off. It will be enabled in function | ||
430 | * uni_player_start() at the same time as the operation | ||
431 | * mode is set to work around a silicon issue. | ||
432 | */ | ||
433 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
434 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); | ||
435 | else | ||
436 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int uni_player_prepare_pcm(struct uniperif *player, | ||
442 | struct snd_pcm_runtime *runtime) | ||
443 | { | ||
444 | int output_frame_size, slot_width, clk_div; | ||
445 | |||
446 | /* Force slot width to 32 in I2S mode (HW constraint) */ | ||
447 | if ((player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) == | ||
448 | SND_SOC_DAIFMT_I2S) { | ||
449 | slot_width = 32; | ||
450 | } else { | ||
451 | switch (runtime->format) { | ||
452 | case SNDRV_PCM_FORMAT_S16_LE: | ||
453 | slot_width = 16; | ||
454 | break; | ||
455 | default: | ||
456 | slot_width = 32; | ||
457 | break; | ||
458 | } | ||
459 | } | ||
460 | output_frame_size = slot_width * runtime->channels; | ||
461 | |||
462 | clk_div = player->mclk / runtime->rate; | ||
463 | /* | ||
464 | * For 32 bits subframe clk_div must be a multiple of 128, | ||
465 | * for 16 bits must be a multiple of 64 | ||
466 | */ | ||
467 | if ((slot_width == 32) && (clk_div % 128)) { | ||
468 | dev_err(player->dev, "%s: invalid clk_div", __func__); | ||
469 | return -EINVAL; | ||
470 | } | ||
471 | |||
472 | if ((slot_width == 16) && (clk_div % 64)) { | ||
473 | dev_err(player->dev, "%s: invalid clk_div", __func__); | ||
474 | return -EINVAL; | ||
475 | } | ||
476 | |||
477 | /* | ||
478 | * Number of bits per subframe (which is one channel sample) | ||
479 | * on output - Transfer 16 or 32 bits from FIFO | ||
480 | */ | ||
481 | switch (slot_width) { | ||
482 | case 32: | ||
483 | SET_UNIPERIF_I2S_FMT_NBIT_32(player); | ||
484 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(player); | ||
485 | break; | ||
486 | case 16: | ||
487 | SET_UNIPERIF_I2S_FMT_NBIT_16(player); | ||
488 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(player); | ||
489 | break; | ||
490 | default: | ||
491 | dev_err(player->dev, "subframe format not supported"); | ||
492 | return -EINVAL; | ||
493 | } | ||
494 | |||
495 | /* Configure data memory format */ | ||
496 | switch (runtime->format) { | ||
497 | case SNDRV_PCM_FORMAT_S16_LE: | ||
498 | /* One data word contains two samples */ | ||
499 | SET_UNIPERIF_CONFIG_MEM_FMT_16_16(player); | ||
500 | break; | ||
501 | |||
502 | case SNDRV_PCM_FORMAT_S32_LE: | ||
503 | /* | ||
504 | * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits | ||
505 | * on the left than zeros (if less than 32 bytes)"... ;-) | ||
506 | */ | ||
507 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(player); | ||
508 | break; | ||
509 | |||
510 | default: | ||
511 | dev_err(player->dev, "format not supported"); | ||
512 | return -EINVAL; | ||
513 | } | ||
514 | |||
515 | /* Set rounding to off */ | ||
516 | SET_UNIPERIF_CTRL_ROUNDING_OFF(player); | ||
517 | |||
518 | /* Set clock divisor */ | ||
519 | SET_UNIPERIF_CTRL_DIVIDER(player, clk_div / (2 * output_frame_size)); | ||
520 | |||
521 | /* Number of channelsmust be even*/ | ||
522 | if ((runtime->channels % 2) || (runtime->channels < 2) || | ||
523 | (runtime->channels > 10)) { | ||
524 | dev_err(player->dev, "%s: invalid nb of channels", __func__); | ||
525 | return -EINVAL; | ||
526 | } | ||
527 | |||
528 | SET_UNIPERIF_I2S_FMT_NUM_CH(player, runtime->channels / 2); | ||
529 | |||
530 | /* Set 1-bit audio format to disabled */ | ||
531 | SET_UNIPERIF_CONFIG_ONE_BIT_AUD_DISABLE(player); | ||
532 | |||
533 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(player); | ||
534 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
535 | |||
536 | /* No iec958 formatting as outputting to DAC */ | ||
537 | SET_UNIPERIF_CTRL_SPDIF_FMT_OFF(player); | ||
538 | |||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | /* | ||
543 | * ALSA uniperipheral iec958 controls | ||
544 | */ | ||
545 | static int uni_player_ctl_iec958_info(struct snd_kcontrol *kcontrol, | ||
546 | struct snd_ctl_elem_info *uinfo) | ||
547 | { | ||
548 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
549 | uinfo->count = 1; | ||
550 | |||
551 | return 0; | ||
552 | } | ||
553 | |||
554 | static int uni_player_ctl_iec958_get(struct snd_kcontrol *kcontrol, | ||
555 | struct snd_ctl_elem_value *ucontrol) | ||
556 | { | ||
557 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); | ||
558 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
559 | struct uniperif *player = priv->dai_data.uni; | ||
560 | struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; | ||
561 | |||
562 | mutex_lock(&player->ctrl_lock); | ||
563 | ucontrol->value.iec958.status[0] = iec958->status[0]; | ||
564 | ucontrol->value.iec958.status[1] = iec958->status[1]; | ||
565 | ucontrol->value.iec958.status[2] = iec958->status[2]; | ||
566 | ucontrol->value.iec958.status[3] = iec958->status[3]; | ||
567 | mutex_unlock(&player->ctrl_lock); | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | static int uni_player_ctl_iec958_put(struct snd_kcontrol *kcontrol, | ||
572 | struct snd_ctl_elem_value *ucontrol) | ||
573 | { | ||
574 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); | ||
575 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
576 | struct uniperif *player = priv->dai_data.uni; | ||
577 | struct snd_aes_iec958 *iec958 = &player->stream_settings.iec958; | ||
578 | |||
579 | mutex_lock(&player->ctrl_lock); | ||
580 | iec958->status[0] = ucontrol->value.iec958.status[0]; | ||
581 | iec958->status[1] = ucontrol->value.iec958.status[1]; | ||
582 | iec958->status[2] = ucontrol->value.iec958.status[2]; | ||
583 | iec958->status[3] = ucontrol->value.iec958.status[3]; | ||
584 | mutex_unlock(&player->ctrl_lock); | ||
585 | |||
586 | uni_player_set_channel_status(player, NULL); | ||
587 | |||
588 | return 0; | ||
589 | } | ||
590 | |||
591 | static struct snd_kcontrol_new uni_player_iec958_ctl = { | ||
592 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
593 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
594 | .info = uni_player_ctl_iec958_info, | ||
595 | .get = uni_player_ctl_iec958_get, | ||
596 | .put = uni_player_ctl_iec958_put, | ||
597 | }; | ||
598 | |||
599 | /* | ||
600 | * uniperif rate adjustement control | ||
601 | */ | ||
602 | static int snd_sti_clk_adjustment_info(struct snd_kcontrol *kcontrol, | ||
603 | struct snd_ctl_elem_info *uinfo) | ||
604 | { | ||
605 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
606 | uinfo->count = 1; | ||
607 | uinfo->value.integer.min = UNIPERIF_PLAYER_CLK_ADJ_MIN; | ||
608 | uinfo->value.integer.max = UNIPERIF_PLAYER_CLK_ADJ_MAX; | ||
609 | uinfo->value.integer.step = 1; | ||
610 | |||
611 | return 0; | ||
612 | } | ||
613 | |||
614 | static int snd_sti_clk_adjustment_get(struct snd_kcontrol *kcontrol, | ||
615 | struct snd_ctl_elem_value *ucontrol) | ||
616 | { | ||
617 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); | ||
618 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
619 | struct uniperif *player = priv->dai_data.uni; | ||
620 | |||
621 | mutex_lock(&player->ctrl_lock); | ||
622 | ucontrol->value.integer.value[0] = player->clk_adj; | ||
623 | mutex_unlock(&player->ctrl_lock); | ||
624 | |||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static int snd_sti_clk_adjustment_put(struct snd_kcontrol *kcontrol, | ||
629 | struct snd_ctl_elem_value *ucontrol) | ||
630 | { | ||
631 | struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); | ||
632 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
633 | struct uniperif *player = priv->dai_data.uni; | ||
634 | int ret = 0; | ||
635 | |||
636 | if ((ucontrol->value.integer.value[0] < UNIPERIF_PLAYER_CLK_ADJ_MIN) || | ||
637 | (ucontrol->value.integer.value[0] > UNIPERIF_PLAYER_CLK_ADJ_MAX)) | ||
638 | return -EINVAL; | ||
639 | |||
640 | mutex_lock(&player->ctrl_lock); | ||
641 | player->clk_adj = ucontrol->value.integer.value[0]; | ||
642 | |||
643 | if (player->mclk) | ||
644 | ret = uni_player_clk_set_rate(player, player->mclk); | ||
645 | mutex_unlock(&player->ctrl_lock); | ||
646 | |||
647 | return ret; | ||
648 | } | ||
649 | |||
650 | static struct snd_kcontrol_new uni_player_clk_adj_ctl = { | ||
651 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
652 | .name = "PCM Playback Oversampling Freq. Adjustment", | ||
653 | .info = snd_sti_clk_adjustment_info, | ||
654 | .get = snd_sti_clk_adjustment_get, | ||
655 | .put = snd_sti_clk_adjustment_put, | ||
656 | }; | ||
657 | |||
658 | static struct snd_kcontrol_new *snd_sti_pcm_ctl[] = { | ||
659 | &uni_player_clk_adj_ctl, | ||
660 | }; | ||
661 | |||
662 | static struct snd_kcontrol_new *snd_sti_iec_ctl[] = { | ||
663 | &uni_player_iec958_ctl, | ||
664 | &uni_player_clk_adj_ctl, | ||
665 | }; | ||
666 | |||
667 | static int uni_player_startup(struct snd_pcm_substream *substream, | ||
668 | struct snd_soc_dai *dai) | ||
669 | { | ||
670 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
671 | struct uniperif *player = priv->dai_data.uni; | ||
672 | |||
673 | player->clk_adj = 0; | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int uni_player_set_sysclk(struct snd_soc_dai *dai, int clk_id, | ||
679 | unsigned int freq, int dir) | ||
680 | { | ||
681 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
682 | struct uniperif *player = priv->dai_data.uni; | ||
683 | int ret; | ||
684 | |||
685 | if (dir == SND_SOC_CLOCK_IN) | ||
686 | return 0; | ||
687 | |||
688 | if (clk_id != 0) | ||
689 | return -EINVAL; | ||
690 | |||
691 | mutex_lock(&player->ctrl_lock); | ||
692 | ret = uni_player_clk_set_rate(player, freq); | ||
693 | if (!ret) | ||
694 | player->mclk = freq; | ||
695 | mutex_unlock(&player->ctrl_lock); | ||
696 | |||
697 | return ret; | ||
698 | } | ||
699 | |||
700 | static int uni_player_prepare(struct snd_pcm_substream *substream, | ||
701 | struct snd_soc_dai *dai) | ||
702 | { | ||
703 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
704 | struct uniperif *player = priv->dai_data.uni; | ||
705 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
706 | int transfer_size, trigger_limit; | ||
707 | int ret; | ||
708 | |||
709 | /* The player should be stopped */ | ||
710 | if (player->state != UNIPERIF_STATE_STOPPED) { | ||
711 | dev_err(player->dev, "%s: invalid player state %d", __func__, | ||
712 | player->state); | ||
713 | return -EINVAL; | ||
714 | } | ||
715 | |||
716 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
717 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
718 | |||
719 | /* Calculate number of empty cells available before asserting DREQ */ | ||
720 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) { | ||
721 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
722 | } else { | ||
723 | /* | ||
724 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
725 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
726 | * from OFF or STANDBY to AUDIO DATA. | ||
727 | */ | ||
728 | trigger_limit = transfer_size; | ||
729 | } | ||
730 | |||
731 | /* Trigger limit must be an even number */ | ||
732 | if ((!trigger_limit % 2) || (trigger_limit != 1 && transfer_size % 2) || | ||
733 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(player))) { | ||
734 | dev_err(player->dev, "invalid trigger limit %d", trigger_limit); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(player, trigger_limit); | ||
739 | |||
740 | /* Uniperipheral setup depends on player type */ | ||
741 | switch (player->info->player_type) { | ||
742 | case SND_ST_UNIPERIF_PLAYER_TYPE_HDMI: | ||
743 | ret = uni_player_prepare_iec958(player, runtime); | ||
744 | break; | ||
745 | case SND_ST_UNIPERIF_PLAYER_TYPE_PCM: | ||
746 | ret = uni_player_prepare_pcm(player, runtime); | ||
747 | break; | ||
748 | case SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF: | ||
749 | ret = uni_player_prepare_iec958(player, runtime); | ||
750 | break; | ||
751 | default: | ||
752 | dev_err(player->dev, "invalid player type"); | ||
753 | return -EINVAL; | ||
754 | } | ||
755 | |||
756 | if (ret) | ||
757 | return ret; | ||
758 | |||
759 | switch (player->daifmt & SND_SOC_DAIFMT_INV_MASK) { | ||
760 | case SND_SOC_DAIFMT_NB_NF: | ||
761 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); | ||
762 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); | ||
763 | break; | ||
764 | case SND_SOC_DAIFMT_NB_IF: | ||
765 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); | ||
766 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(player); | ||
767 | break; | ||
768 | case SND_SOC_DAIFMT_IB_NF: | ||
769 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(player); | ||
770 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
771 | break; | ||
772 | case SND_SOC_DAIFMT_IB_IF: | ||
773 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(player); | ||
774 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_FALLING(player); | ||
775 | break; | ||
776 | } | ||
777 | |||
778 | switch (player->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
779 | case SND_SOC_DAIFMT_I2S: | ||
780 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); | ||
781 | SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(player); | ||
782 | break; | ||
783 | case SND_SOC_DAIFMT_LEFT_J: | ||
784 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(player); | ||
785 | SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); | ||
786 | break; | ||
787 | case SND_SOC_DAIFMT_RIGHT_J: | ||
788 | SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(player); | ||
789 | SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(player); | ||
790 | break; | ||
791 | default: | ||
792 | dev_err(player->dev, "format not supported"); | ||
793 | return -EINVAL; | ||
794 | } | ||
795 | |||
796 | SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(player, 0); | ||
797 | |||
798 | /* Reset uniperipheral player */ | ||
799 | SET_UNIPERIF_SOFT_RST_SOFT_RST(player); | ||
800 | |||
801 | return reset_player(player); | ||
802 | } | ||
803 | |||
804 | static int uni_player_start(struct uniperif *player) | ||
805 | { | ||
806 | int ret; | ||
807 | |||
808 | /* The player should be stopped */ | ||
809 | if (player->state != UNIPERIF_STATE_STOPPED) { | ||
810 | dev_err(player->dev, "%s: invalid player state", __func__); | ||
811 | return -EINVAL; | ||
812 | } | ||
813 | |||
814 | ret = clk_prepare_enable(player->clk); | ||
815 | if (ret) { | ||
816 | dev_err(player->dev, "%s: Failed to enable clock", __func__); | ||
817 | return ret; | ||
818 | } | ||
819 | |||
820 | /* Clear any pending interrupts */ | ||
821 | SET_UNIPERIF_ITS_BCLR(player, GET_UNIPERIF_ITS(player)); | ||
822 | |||
823 | /* Set the interrupt mask */ | ||
824 | SET_UNIPERIF_ITM_BSET_DMA_ERROR(player); | ||
825 | SET_UNIPERIF_ITM_BSET_FIFO_ERROR(player); | ||
826 | |||
827 | /* Enable underflow recovery interrupts */ | ||
828 | if (player->info->underflow_enabled) { | ||
829 | SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(player); | ||
830 | SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(player); | ||
831 | } | ||
832 | |||
833 | /* Reset uniperipheral player */ | ||
834 | SET_UNIPERIF_SOFT_RST_SOFT_RST(player); | ||
835 | |||
836 | ret = reset_player(player); | ||
837 | if (ret < 0) | ||
838 | return ret; | ||
839 | |||
840 | /* | ||
841 | * Does not use IEC61937 features of the uniperipheral hardware. | ||
842 | * Instead it performs IEC61937 in software and inserts it directly | ||
843 | * into the audio data stream. As such, when encoded mode is selected, | ||
844 | * linear pcm mode is still used, but with the differences of the | ||
845 | * channel status bits set for encoded mode and the validity bits set. | ||
846 | */ | ||
847 | SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(player); | ||
848 | |||
849 | /* | ||
850 | * If iec958 formatting is required for hdmi or spdif, then it must be | ||
851 | * enabled after the operation mode is set. If set prior to this, it | ||
852 | * will not take affect and hang the player. | ||
853 | */ | ||
854 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
855 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) | ||
856 | SET_UNIPERIF_CTRL_SPDIF_FMT_ON(player); | ||
857 | |||
858 | /* Force channel status update (no update if clk disable) */ | ||
859 | if (player->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
860 | SET_UNIPERIF_CONFIG_CHL_STS_UPDATE(player); | ||
861 | else | ||
862 | SET_UNIPERIF_BIT_CONTROL_CHL_STS_UPDATE(player); | ||
863 | |||
864 | /* Update state to started */ | ||
865 | player->state = UNIPERIF_STATE_STARTED; | ||
866 | |||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int uni_player_stop(struct uniperif *player) | ||
871 | { | ||
872 | int ret; | ||
873 | |||
874 | /* The player should not be in stopped state */ | ||
875 | if (player->state == UNIPERIF_STATE_STOPPED) { | ||
876 | dev_err(player->dev, "%s: invalid player state", __func__); | ||
877 | return -EINVAL; | ||
878 | } | ||
879 | |||
880 | /* Turn the player off */ | ||
881 | SET_UNIPERIF_CTRL_OPERATION_OFF(player); | ||
882 | |||
883 | /* Soft reset the player */ | ||
884 | SET_UNIPERIF_SOFT_RST_SOFT_RST(player); | ||
885 | |||
886 | ret = reset_player(player); | ||
887 | if (ret < 0) | ||
888 | return ret; | ||
889 | |||
890 | /* Disable interrupts */ | ||
891 | SET_UNIPERIF_ITM_BCLR(player, GET_UNIPERIF_ITM(player)); | ||
892 | |||
893 | /* Disable clock */ | ||
894 | clk_disable_unprepare(player->clk); | ||
895 | |||
896 | /* Update state to stopped and return */ | ||
897 | player->state = UNIPERIF_STATE_STOPPED; | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | int uni_player_resume(struct uniperif *player) | ||
903 | { | ||
904 | int ret; | ||
905 | |||
906 | /* Select the frequency synthesizer clock */ | ||
907 | if (player->clk_sel) { | ||
908 | ret = regmap_field_write(player->clk_sel, 1); | ||
909 | if (ret) { | ||
910 | dev_err(player->dev, | ||
911 | "%s: Failed to select freq synth clock", | ||
912 | __func__); | ||
913 | return ret; | ||
914 | } | ||
915 | } | ||
916 | |||
917 | SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); | ||
918 | SET_UNIPERIF_CTRL_ROUNDING_OFF(player); | ||
919 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | ||
920 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); | ||
921 | |||
922 | return 0; | ||
923 | } | ||
924 | EXPORT_SYMBOL_GPL(uni_player_resume); | ||
925 | |||
926 | static int uni_player_trigger(struct snd_pcm_substream *substream, | ||
927 | int cmd, struct snd_soc_dai *dai) | ||
928 | { | ||
929 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
930 | struct uniperif *player = priv->dai_data.uni; | ||
931 | |||
932 | switch (cmd) { | ||
933 | case SNDRV_PCM_TRIGGER_START: | ||
934 | return uni_player_start(player); | ||
935 | case SNDRV_PCM_TRIGGER_STOP: | ||
936 | return uni_player_stop(player); | ||
937 | case SNDRV_PCM_TRIGGER_RESUME: | ||
938 | return uni_player_resume(player); | ||
939 | default: | ||
940 | return -EINVAL; | ||
941 | } | ||
942 | } | ||
943 | |||
944 | static void uni_player_shutdown(struct snd_pcm_substream *substream, | ||
945 | struct snd_soc_dai *dai) | ||
946 | { | ||
947 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
948 | struct uniperif *player = priv->dai_data.uni; | ||
949 | |||
950 | if (player->state != UNIPERIF_STATE_STOPPED) | ||
951 | /* Stop the player */ | ||
952 | uni_player_stop(player); | ||
953 | } | ||
954 | |||
955 | static int uni_player_parse_dt_clk_glue(struct platform_device *pdev, | ||
956 | struct uniperif *player) | ||
957 | { | ||
958 | int bit_offset; | ||
959 | struct device_node *node = pdev->dev.of_node; | ||
960 | struct regmap *regmap; | ||
961 | |||
962 | bit_offset = SYS_CFG_AUDI0_GLUE_PCM_CLKX + player->info->id; | ||
963 | |||
964 | regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); | ||
965 | |||
966 | if (regmap) { | ||
967 | struct reg_field regfield = | ||
968 | REG_FIELD(SYS_CFG_AUDIO_GLUE, bit_offset, bit_offset); | ||
969 | |||
970 | player->clk_sel = regmap_field_alloc(regmap, regfield); | ||
971 | } else { | ||
972 | dev_err(&pdev->dev, "sti-audio-clk-glue syscf not found\n"); | ||
973 | return -EINVAL; | ||
974 | } | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static int uni_player_parse_dt(struct platform_device *pdev, | ||
980 | struct uniperif *player) | ||
981 | { | ||
982 | struct uniperif_info *info; | ||
983 | struct device *dev = &pdev->dev; | ||
984 | struct device_node *pnode = pdev->dev.of_node; | ||
985 | const char *mode; | ||
986 | |||
987 | /* Allocate memory for the info structure */ | ||
988 | info = devm_kzalloc(dev, sizeof(*info), GFP_KERNEL); | ||
989 | if (!info) | ||
990 | return -ENOMEM; | ||
991 | |||
992 | of_property_read_u32(pnode, "version", &player->ver); | ||
993 | if (player->ver == SND_ST_UNIPERIF_VERSION_UNKNOWN) { | ||
994 | dev_err(dev, "Unknown uniperipheral version "); | ||
995 | return -EINVAL; | ||
996 | } | ||
997 | /* Underflow recovery is only supported on later ip revisions */ | ||
998 | if (player->ver >= SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
999 | info->underflow_enabled = 1; | ||
1000 | |||
1001 | of_property_read_u32(pnode, "uniperiph-id", &info->id); | ||
1002 | |||
1003 | /* Read the device mode property */ | ||
1004 | of_property_read_string(pnode, "mode", &mode); | ||
1005 | |||
1006 | if (strcasecmp(mode, "hdmi") == 0) | ||
1007 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_HDMI; | ||
1008 | else if (strcasecmp(mode, "pcm") == 0) | ||
1009 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_PCM; | ||
1010 | else if (strcasecmp(mode, "spdif") == 0) | ||
1011 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_SPDIF; | ||
1012 | else | ||
1013 | info->player_type = SND_ST_UNIPERIF_PLAYER_TYPE_NONE; | ||
1014 | |||
1015 | /* Save the info structure */ | ||
1016 | player->info = info; | ||
1017 | |||
1018 | /* Get the PCM_CLK_SEL bit from audio-glue-ctrl SoC register */ | ||
1019 | if (uni_player_parse_dt_clk_glue(pdev, player)) | ||
1020 | return -EINVAL; | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | static const struct snd_soc_dai_ops uni_player_dai_ops = { | ||
1026 | .startup = uni_player_startup, | ||
1027 | .shutdown = uni_player_shutdown, | ||
1028 | .prepare = uni_player_prepare, | ||
1029 | .trigger = uni_player_trigger, | ||
1030 | .hw_params = sti_uniperiph_dai_hw_params, | ||
1031 | .set_fmt = sti_uniperiph_dai_set_fmt, | ||
1032 | .set_sysclk = uni_player_set_sysclk | ||
1033 | }; | ||
1034 | |||
1035 | int uni_player_init(struct platform_device *pdev, | ||
1036 | struct uniperif *player) | ||
1037 | { | ||
1038 | int ret = 0; | ||
1039 | |||
1040 | player->dev = &pdev->dev; | ||
1041 | player->state = UNIPERIF_STATE_STOPPED; | ||
1042 | player->hw = &uni_player_pcm_hw; | ||
1043 | player->dai_ops = &uni_player_dai_ops; | ||
1044 | |||
1045 | ret = uni_player_parse_dt(pdev, player); | ||
1046 | |||
1047 | if (ret < 0) { | ||
1048 | dev_err(player->dev, "Failed to parse DeviceTree"); | ||
1049 | return ret; | ||
1050 | } | ||
1051 | |||
1052 | /* Get uniperif resource */ | ||
1053 | player->clk = of_clk_get(pdev->dev.of_node, 0); | ||
1054 | if (IS_ERR(player->clk)) | ||
1055 | ret = PTR_ERR(player->clk); | ||
1056 | |||
1057 | /* Select the frequency synthesizer clock */ | ||
1058 | if (player->clk_sel) { | ||
1059 | ret = regmap_field_write(player->clk_sel, 1); | ||
1060 | if (ret) { | ||
1061 | dev_err(player->dev, | ||
1062 | "%s: Failed to select freq synth clock", | ||
1063 | __func__); | ||
1064 | return ret; | ||
1065 | } | ||
1066 | } | ||
1067 | |||
1068 | ret = devm_request_irq(&pdev->dev, player->irq, | ||
1069 | uni_player_irq_handler, IRQF_SHARED, | ||
1070 | dev_name(&pdev->dev), player); | ||
1071 | if (ret < 0) | ||
1072 | return ret; | ||
1073 | |||
1074 | mutex_init(&player->ctrl_lock); | ||
1075 | |||
1076 | /* Ensure that disabled by default */ | ||
1077 | SET_UNIPERIF_CONFIG_BACK_STALL_REQ_DISABLE(player); | ||
1078 | SET_UNIPERIF_CTRL_ROUNDING_OFF(player); | ||
1079 | SET_UNIPERIF_CTRL_SPDIF_LAT_OFF(player); | ||
1080 | SET_UNIPERIF_CONFIG_IDLE_MOD_DISABLE(player); | ||
1081 | |||
1082 | if (UNIPERIF_PLAYER_TYPE_IS_IEC958(player)) { | ||
1083 | /* Set default iec958 status bits */ | ||
1084 | |||
1085 | /* Consumer, PCM, copyright, 2ch, mode 0 */ | ||
1086 | player->stream_settings.iec958.status[0] = 0x00; | ||
1087 | /* Broadcast reception category */ | ||
1088 | player->stream_settings.iec958.status[1] = | ||
1089 | IEC958_AES1_CON_GENERAL; | ||
1090 | /* Do not take into account source or channel number */ | ||
1091 | player->stream_settings.iec958.status[2] = | ||
1092 | IEC958_AES2_CON_SOURCE_UNSPEC; | ||
1093 | /* Sampling frequency not indicated */ | ||
1094 | player->stream_settings.iec958.status[3] = | ||
1095 | IEC958_AES3_CON_FS_NOTID; | ||
1096 | /* Max sample word 24-bit, sample word length not indicated */ | ||
1097 | player->stream_settings.iec958.status[4] = | ||
1098 | IEC958_AES4_CON_MAX_WORDLEN_24 | | ||
1099 | IEC958_AES4_CON_WORDLEN_24_20; | ||
1100 | |||
1101 | player->num_ctrls = ARRAY_SIZE(snd_sti_iec_ctl); | ||
1102 | player->snd_ctrls = snd_sti_iec_ctl[0]; | ||
1103 | } else { | ||
1104 | player->num_ctrls = ARRAY_SIZE(snd_sti_pcm_ctl); | ||
1105 | player->snd_ctrls = snd_sti_pcm_ctl[0]; | ||
1106 | } | ||
1107 | |||
1108 | return 0; | ||
1109 | } | ||
1110 | EXPORT_SYMBOL_GPL(uni_player_init); | ||
diff --git a/sound/soc/sti/uniperif_reader.c b/sound/soc/sti/uniperif_reader.c new file mode 100644 index 000000000000..c502626f339b --- /dev/null +++ b/sound/soc/sti/uniperif_reader.c | |||
@@ -0,0 +1,362 @@ | |||
1 | /* | ||
2 | * Copyright (C) STMicroelectronics SA 2015 | ||
3 | * Authors: Arnaud Pouliquen <arnaud.pouliquen@st.com> | ||
4 | * for STMicroelectronics. | ||
5 | * License terms: GNU General Public License (GPL), version 2 | ||
6 | */ | ||
7 | |||
8 | #include <linux/clk.h> | ||
9 | #include <linux/delay.h> | ||
10 | #include <linux/io.h> | ||
11 | |||
12 | #include <sound/soc.h> | ||
13 | |||
14 | #include "uniperif.h" | ||
15 | |||
16 | /* | ||
17 | * Note: snd_pcm_hardware is linked to DMA controller but is declared here to | ||
18 | * integrate unireader capability in term of rate and supported channels | ||
19 | */ | ||
20 | static const struct snd_pcm_hardware uni_reader_pcm_hw = { | ||
21 | .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
22 | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP | | ||
23 | SNDRV_PCM_INFO_MMAP_VALID, | ||
24 | .formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S16_LE, | ||
25 | |||
26 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
27 | .rate_min = 8000, | ||
28 | .rate_max = 96000, | ||
29 | |||
30 | .channels_min = 2, | ||
31 | .channels_max = 8, | ||
32 | |||
33 | .periods_min = 2, | ||
34 | .periods_max = 48, | ||
35 | |||
36 | .period_bytes_min = 128, | ||
37 | .period_bytes_max = 64 * PAGE_SIZE, | ||
38 | .buffer_bytes_max = 256 * PAGE_SIZE | ||
39 | }; | ||
40 | |||
41 | /* | ||
42 | * uni_reader_irq_handler | ||
43 | * In case of error audio stream is stopped; stop action is protected via PCM | ||
44 | * stream lock to avoid race condition with trigger callback. | ||
45 | */ | ||
46 | static irqreturn_t uni_reader_irq_handler(int irq, void *dev_id) | ||
47 | { | ||
48 | irqreturn_t ret = IRQ_NONE; | ||
49 | struct uniperif *reader = dev_id; | ||
50 | unsigned int status; | ||
51 | |||
52 | if (reader->state == UNIPERIF_STATE_STOPPED) { | ||
53 | /* Unexpected IRQ: do nothing */ | ||
54 | dev_warn(reader->dev, "unexpected IRQ "); | ||
55 | return IRQ_HANDLED; | ||
56 | } | ||
57 | |||
58 | /* Get interrupt status & clear them immediately */ | ||
59 | status = GET_UNIPERIF_ITS(reader); | ||
60 | SET_UNIPERIF_ITS_BCLR(reader, status); | ||
61 | |||
62 | /* Check for fifo overflow error */ | ||
63 | if (unlikely(status & UNIPERIF_ITS_FIFO_ERROR_MASK(reader))) { | ||
64 | dev_err(reader->dev, "FIFO error detected"); | ||
65 | |||
66 | snd_pcm_stream_lock(reader->substream); | ||
67 | snd_pcm_stop(reader->substream, SNDRV_PCM_STATE_XRUN); | ||
68 | snd_pcm_stream_unlock(reader->substream); | ||
69 | |||
70 | return IRQ_HANDLED; | ||
71 | } | ||
72 | |||
73 | return ret; | ||
74 | } | ||
75 | |||
76 | static int uni_reader_prepare(struct snd_pcm_substream *substream, | ||
77 | struct snd_soc_dai *dai) | ||
78 | { | ||
79 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
80 | struct uniperif *reader = priv->dai_data.uni; | ||
81 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
82 | int transfer_size, trigger_limit; | ||
83 | int slot_width; | ||
84 | int count = 10; | ||
85 | |||
86 | /* The reader should be stopped */ | ||
87 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
88 | dev_err(reader->dev, "%s: invalid reader state %d", __func__, | ||
89 | reader->state); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | /* Calculate transfer size (in fifo cells and bytes) for frame count */ | ||
94 | transfer_size = runtime->channels * UNIPERIF_FIFO_FRAMES; | ||
95 | |||
96 | /* Calculate number of empty cells available before asserting DREQ */ | ||
97 | if (reader->ver < SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0) | ||
98 | trigger_limit = UNIPERIF_FIFO_SIZE - transfer_size; | ||
99 | else | ||
100 | /* | ||
101 | * Since SND_ST_UNIPERIF_VERSION_UNI_PLR_TOP_1_0 | ||
102 | * FDMA_TRIGGER_LIMIT also controls when the state switches | ||
103 | * from OFF or STANDBY to AUDIO DATA. | ||
104 | */ | ||
105 | trigger_limit = transfer_size; | ||
106 | |||
107 | /* Trigger limit must be an even number */ | ||
108 | if ((!trigger_limit % 2) || | ||
109 | (trigger_limit != 1 && transfer_size % 2) || | ||
110 | (trigger_limit > UNIPERIF_CONFIG_DMA_TRIG_LIMIT_MASK(reader))) { | ||
111 | dev_err(reader->dev, "invalid trigger limit %d", trigger_limit); | ||
112 | return -EINVAL; | ||
113 | } | ||
114 | |||
115 | SET_UNIPERIF_CONFIG_DMA_TRIG_LIMIT(reader, trigger_limit); | ||
116 | |||
117 | switch (reader->daifmt & SND_SOC_DAIFMT_INV_MASK) { | ||
118 | case SND_SOC_DAIFMT_IB_IF: | ||
119 | case SND_SOC_DAIFMT_NB_IF: | ||
120 | SET_UNIPERIF_I2S_FMT_LR_POL_HIG(reader); | ||
121 | break; | ||
122 | default: | ||
123 | SET_UNIPERIF_I2S_FMT_LR_POL_LOW(reader); | ||
124 | } | ||
125 | |||
126 | /* Force slot width to 32 in I2S mode */ | ||
127 | if ((reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) | ||
128 | == SND_SOC_DAIFMT_I2S) { | ||
129 | slot_width = 32; | ||
130 | } else { | ||
131 | switch (runtime->format) { | ||
132 | case SNDRV_PCM_FORMAT_S16_LE: | ||
133 | slot_width = 16; | ||
134 | break; | ||
135 | default: | ||
136 | slot_width = 32; | ||
137 | break; | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /* Number of bits per subframe (i.e one channel sample) on input. */ | ||
142 | switch (slot_width) { | ||
143 | case 32: | ||
144 | SET_UNIPERIF_I2S_FMT_NBIT_32(reader); | ||
145 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_32(reader); | ||
146 | break; | ||
147 | case 16: | ||
148 | SET_UNIPERIF_I2S_FMT_NBIT_16(reader); | ||
149 | SET_UNIPERIF_I2S_FMT_DATA_SIZE_16(reader); | ||
150 | break; | ||
151 | default: | ||
152 | dev_err(reader->dev, "subframe format not supported"); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* Configure data memory format */ | ||
157 | switch (runtime->format) { | ||
158 | case SNDRV_PCM_FORMAT_S16_LE: | ||
159 | /* One data word contains two samples */ | ||
160 | SET_UNIPERIF_CONFIG_MEM_FMT_16_16(reader); | ||
161 | break; | ||
162 | |||
163 | case SNDRV_PCM_FORMAT_S32_LE: | ||
164 | /* | ||
165 | * Actually "16 bits/0 bits" means "32/28/24/20/18/16 bits | ||
166 | * on the MSB then zeros (if less than 32 bytes)"... | ||
167 | */ | ||
168 | SET_UNIPERIF_CONFIG_MEM_FMT_16_0(reader); | ||
169 | break; | ||
170 | |||
171 | default: | ||
172 | dev_err(reader->dev, "format not supported"); | ||
173 | return -EINVAL; | ||
174 | } | ||
175 | |||
176 | switch (reader->daifmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
177 | case SND_SOC_DAIFMT_I2S: | ||
178 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | ||
179 | SET_UNIPERIF_I2S_FMT_PADDING_I2S_MODE(reader); | ||
180 | break; | ||
181 | case SND_SOC_DAIFMT_LEFT_J: | ||
182 | SET_UNIPERIF_I2S_FMT_ALIGN_LEFT(reader); | ||
183 | SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); | ||
184 | break; | ||
185 | case SND_SOC_DAIFMT_RIGHT_J: | ||
186 | SET_UNIPERIF_I2S_FMT_ALIGN_RIGHT(reader); | ||
187 | SET_UNIPERIF_I2S_FMT_PADDING_SONY_MODE(reader); | ||
188 | break; | ||
189 | default: | ||
190 | dev_err(reader->dev, "format not supported"); | ||
191 | return -EINVAL; | ||
192 | } | ||
193 | |||
194 | SET_UNIPERIF_I2S_FMT_ORDER_MSB(reader); | ||
195 | |||
196 | /* Data clocking (changing) on the rising edge */ | ||
197 | SET_UNIPERIF_I2S_FMT_SCLK_EDGE_RISING(reader); | ||
198 | |||
199 | /* Number of channels must be even */ | ||
200 | |||
201 | if ((runtime->channels % 2) || (runtime->channels < 2) || | ||
202 | (runtime->channels > 10)) { | ||
203 | dev_err(reader->dev, "%s: invalid nb of channels", __func__); | ||
204 | return -EINVAL; | ||
205 | } | ||
206 | |||
207 | SET_UNIPERIF_I2S_FMT_NUM_CH(reader, runtime->channels / 2); | ||
208 | |||
209 | /* Clear any pending interrupts */ | ||
210 | SET_UNIPERIF_ITS_BCLR(reader, GET_UNIPERIF_ITS(reader)); | ||
211 | |||
212 | SET_UNIPERIF_I2S_FMT_NO_OF_SAMPLES_TO_READ(reader, 0); | ||
213 | |||
214 | /* Set the interrupt mask */ | ||
215 | SET_UNIPERIF_ITM_BSET_DMA_ERROR(reader); | ||
216 | SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); | ||
217 | SET_UNIPERIF_ITM_BSET_MEM_BLK_READ(reader); | ||
218 | |||
219 | /* Enable underflow recovery interrupts */ | ||
220 | if (reader->info->underflow_enabled) { | ||
221 | SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_DONE(reader); | ||
222 | SET_UNIPERIF_ITM_BSET_UNDERFLOW_REC_FAILED(reader); | ||
223 | } | ||
224 | |||
225 | /* Reset uniperipheral reader */ | ||
226 | SET_UNIPERIF_SOFT_RST_SOFT_RST(reader); | ||
227 | |||
228 | while (GET_UNIPERIF_SOFT_RST_SOFT_RST(reader)) { | ||
229 | udelay(5); | ||
230 | count--; | ||
231 | } | ||
232 | if (!count) { | ||
233 | dev_err(reader->dev, "Failed to reset uniperif"); | ||
234 | return -EIO; | ||
235 | } | ||
236 | |||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int uni_reader_start(struct uniperif *reader) | ||
241 | { | ||
242 | /* The reader should be stopped */ | ||
243 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
244 | dev_err(reader->dev, "%s: invalid reader state", __func__); | ||
245 | return -EINVAL; | ||
246 | } | ||
247 | |||
248 | /* Enable reader interrupts (and clear possible stalled ones) */ | ||
249 | SET_UNIPERIF_ITS_BCLR_FIFO_ERROR(reader); | ||
250 | SET_UNIPERIF_ITM_BSET_FIFO_ERROR(reader); | ||
251 | |||
252 | /* Launch the reader */ | ||
253 | SET_UNIPERIF_CTRL_OPERATION_PCM_DATA(reader); | ||
254 | |||
255 | /* Update state to started */ | ||
256 | reader->state = UNIPERIF_STATE_STARTED; | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | static int uni_reader_stop(struct uniperif *reader) | ||
261 | { | ||
262 | /* The reader should not be in stopped state */ | ||
263 | if (reader->state == UNIPERIF_STATE_STOPPED) { | ||
264 | dev_err(reader->dev, "%s: invalid reader state", __func__); | ||
265 | return -EINVAL; | ||
266 | } | ||
267 | |||
268 | /* Turn the reader off */ | ||
269 | SET_UNIPERIF_CTRL_OPERATION_OFF(reader); | ||
270 | |||
271 | /* Disable interrupts */ | ||
272 | SET_UNIPERIF_ITM_BCLR(reader, GET_UNIPERIF_ITM(reader)); | ||
273 | |||
274 | /* Update state to stopped and return */ | ||
275 | reader->state = UNIPERIF_STATE_STOPPED; | ||
276 | |||
277 | return 0; | ||
278 | } | ||
279 | |||
280 | static int uni_reader_trigger(struct snd_pcm_substream *substream, | ||
281 | int cmd, struct snd_soc_dai *dai) | ||
282 | { | ||
283 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
284 | struct uniperif *reader = priv->dai_data.uni; | ||
285 | |||
286 | switch (cmd) { | ||
287 | case SNDRV_PCM_TRIGGER_START: | ||
288 | return uni_reader_start(reader); | ||
289 | case SNDRV_PCM_TRIGGER_STOP: | ||
290 | return uni_reader_stop(reader); | ||
291 | default: | ||
292 | return -EINVAL; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | static void uni_reader_shutdown(struct snd_pcm_substream *substream, | ||
297 | struct snd_soc_dai *dai) | ||
298 | { | ||
299 | struct sti_uniperiph_data *priv = snd_soc_dai_get_drvdata(dai); | ||
300 | struct uniperif *reader = priv->dai_data.uni; | ||
301 | |||
302 | if (reader->state != UNIPERIF_STATE_STOPPED) { | ||
303 | /* Stop the reader */ | ||
304 | uni_reader_stop(reader); | ||
305 | } | ||
306 | } | ||
307 | |||
308 | static int uni_reader_parse_dt(struct platform_device *pdev, | ||
309 | struct uniperif *reader) | ||
310 | { | ||
311 | struct uniperif_info *info; | ||
312 | struct device_node *node = pdev->dev.of_node; | ||
313 | |||
314 | /* Allocate memory for the info structure */ | ||
315 | info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); | ||
316 | if (!info) | ||
317 | return -ENOMEM; | ||
318 | |||
319 | of_property_read_u32(node, "version", &reader->ver); | ||
320 | |||
321 | /* Save the info structure */ | ||
322 | reader->info = info; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static const struct snd_soc_dai_ops uni_reader_dai_ops = { | ||
328 | .shutdown = uni_reader_shutdown, | ||
329 | .prepare = uni_reader_prepare, | ||
330 | .trigger = uni_reader_trigger, | ||
331 | .hw_params = sti_uniperiph_dai_hw_params, | ||
332 | .set_fmt = sti_uniperiph_dai_set_fmt, | ||
333 | }; | ||
334 | |||
335 | int uni_reader_init(struct platform_device *pdev, | ||
336 | struct uniperif *reader) | ||
337 | { | ||
338 | int ret = 0; | ||
339 | |||
340 | reader->dev = &pdev->dev; | ||
341 | reader->state = UNIPERIF_STATE_STOPPED; | ||
342 | reader->hw = &uni_reader_pcm_hw; | ||
343 | reader->dai_ops = &uni_reader_dai_ops; | ||
344 | |||
345 | dev_err(reader->dev, "%s: enter\n", __func__); | ||
346 | ret = uni_reader_parse_dt(pdev, reader); | ||
347 | if (ret < 0) { | ||
348 | dev_err(reader->dev, "Failed to parse DeviceTree"); | ||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | ret = devm_request_irq(&pdev->dev, reader->irq, | ||
353 | uni_reader_irq_handler, IRQF_SHARED, | ||
354 | dev_name(&pdev->dev), reader); | ||
355 | if (ret < 0) { | ||
356 | dev_err(&pdev->dev, "Failed to request IRQ"); | ||
357 | return -EBUSY; | ||
358 | } | ||
359 | |||
360 | return 0; | ||
361 | } | ||
362 | EXPORT_SYMBOL_GPL(uni_reader_init); | ||