diff options
29 files changed, 2830 insertions, 2268 deletions
diff --git a/Documentation/devicetree/bindings/sound/inno-rk3036.txt b/Documentation/devicetree/bindings/sound/inno-rk3036.txt new file mode 100644 index 000000000000..758de8e27561 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/inno-rk3036.txt | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | Inno audio codec for RK3036 | ||
| 2 | |||
| 3 | Inno audio codec is integrated inside RK3036 SoC. | ||
| 4 | |||
| 5 | Required properties: | ||
| 6 | - compatible : Should be "rockchip,rk3036-codec". | ||
| 7 | - reg : The registers of codec. | ||
| 8 | - clock-names : Should be "acodec_pclk". | ||
| 9 | - clocks : The clock of codec. | ||
| 10 | - rockchip,grf : The phandle of grf device node. | ||
| 11 | |||
| 12 | Example: | ||
| 13 | |||
| 14 | acodec: acodec-ana@20030000 { | ||
| 15 | compatible = "rk3036-codec"; | ||
| 16 | reg = <0x20030000 0x4000>; | ||
| 17 | rockchip,grf = <&grf>; | ||
| 18 | clock-names = "acodec_pclk"; | ||
| 19 | clocks = <&cru ACLK_VCODEC>; | ||
| 20 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt index c57cbd65736c..8ee0fa91e4a0 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt | |||
| @@ -7,8 +7,11 @@ Required properties: | |||
| 7 | "renesas,rcar_sound-gen3" if generation3 | 7 | "renesas,rcar_sound-gen3" if generation3 |
| 8 | Examples with soctypes are: | 8 | Examples with soctypes are: |
| 9 | - "renesas,rcar_sound-r8a7778" (R-Car M1A) | 9 | - "renesas,rcar_sound-r8a7778" (R-Car M1A) |
| 10 | - "renesas,rcar_sound-r8a7779" (R-Car H1) | ||
| 10 | - "renesas,rcar_sound-r8a7790" (R-Car H2) | 11 | - "renesas,rcar_sound-r8a7790" (R-Car H2) |
| 11 | - "renesas,rcar_sound-r8a7791" (R-Car M2-W) | 12 | - "renesas,rcar_sound-r8a7791" (R-Car M2-W) |
| 13 | - "renesas,rcar_sound-r8a7793" (R-Car M2-N) | ||
| 14 | - "renesas,rcar_sound-r8a7794" (R-Car E2) | ||
| 12 | - "renesas,rcar_sound-r8a7795" (R-Car H3) | 15 | - "renesas,rcar_sound-r8a7795" (R-Car H3) |
| 13 | - reg : Should contain the register physical address. | 16 | - reg : Should contain the register physical address. |
| 14 | required register is | 17 | required register is |
| @@ -34,6 +37,8 @@ Required properties: | |||
| 34 | see below for detail. | 37 | see below for detail. |
| 35 | - #sound-dai-cells : it must be 0 if your system is using single DAI | 38 | - #sound-dai-cells : it must be 0 if your system is using single DAI |
| 36 | it must be 1 if your system is using multi DAI | 39 | it must be 1 if your system is using multi DAI |
| 40 | |||
| 41 | Optional properties: | ||
| 37 | - #clock-cells : it must be 0 if your system has audio_clkout | 42 | - #clock-cells : it must be 0 if your system has audio_clkout |
| 38 | it must be 1 if your system has audio_clkout0/1/2/3 | 43 | it must be 1 if your system has audio_clkout0/1/2/3 |
| 39 | - clock-frequency : for all audio_clkout0/1/2/3 | 44 | - clock-frequency : for all audio_clkout0/1/2/3 |
| @@ -244,3 +249,80 @@ rcar_sound: sound@ec500000 { | |||
| 244 | }; | 249 | }; |
| 245 | }; | 250 | }; |
| 246 | }; | 251 | }; |
| 252 | |||
| 253 | Example: simple sound card | ||
| 254 | |||
| 255 | rsnd_ak4643: sound { | ||
| 256 | compatible = "simple-audio-card"; | ||
| 257 | |||
| 258 | simple-audio-card,format = "left_j"; | ||
| 259 | simple-audio-card,bitclock-master = <&sndcodec>; | ||
| 260 | simple-audio-card,frame-master = <&sndcodec>; | ||
| 261 | |||
| 262 | sndcpu: simple-audio-card,cpu { | ||
| 263 | sound-dai = <&rcar_sound>; | ||
| 264 | }; | ||
| 265 | |||
| 266 | sndcodec: simple-audio-card,codec { | ||
| 267 | sound-dai = <&ak4643>; | ||
| 268 | clocks = <&audio_clock>; | ||
| 269 | }; | ||
| 270 | }; | ||
| 271 | |||
| 272 | &rcar_sound { | ||
| 273 | pinctrl-0 = <&sound_pins &sound_clk_pins>; | ||
| 274 | pinctrl-names = "default"; | ||
| 275 | |||
| 276 | /* Single DAI */ | ||
| 277 | #sound-dai-cells = <0>; | ||
| 278 | |||
| 279 | status = "okay"; | ||
| 280 | |||
| 281 | rcar_sound,dai { | ||
| 282 | dai0 { | ||
| 283 | playback = <&ssi0 &src2 &dvc0>; | ||
| 284 | capture = <&ssi1 &src3 &dvc1>; | ||
| 285 | }; | ||
| 286 | }; | ||
| 287 | }; | ||
| 288 | |||
| 289 | &ssi1 { | ||
| 290 | shared-pin; | ||
| 291 | }; | ||
| 292 | |||
| 293 | Example: simple sound card for TDM | ||
| 294 | |||
| 295 | rsnd_tdm: sound { | ||
| 296 | compatible = "simple-audio-card"; | ||
| 297 | |||
| 298 | simple-audio-card,format = "left_j"; | ||
| 299 | simple-audio-card,bitclock-master = <&sndcodec>; | ||
| 300 | simple-audio-card,frame-master = <&sndcodec>; | ||
| 301 | |||
| 302 | sndcpu: simple-audio-card,cpu { | ||
| 303 | sound-dai = <&rcar_sound>; | ||
| 304 | dai-tdm-slot-num = <6>; | ||
| 305 | }; | ||
| 306 | |||
| 307 | sndcodec: simple-audio-card,codec { | ||
| 308 | sound-dai = <&xxx>; | ||
| 309 | }; | ||
| 310 | }; | ||
| 311 | |||
| 312 | Example: simple sound card for Multi channel | ||
| 313 | |||
| 314 | &rcar_sound { | ||
| 315 | pinctrl-0 = <&sound_pins &sound_clk_pins>; | ||
| 316 | pinctrl-names = "default"; | ||
| 317 | |||
| 318 | /* Single DAI */ | ||
| 319 | #sound-dai-cells = <0>; | ||
| 320 | |||
| 321 | status = "okay"; | ||
| 322 | |||
| 323 | rcar_sound,dai { | ||
| 324 | dai0 { | ||
| 325 | playback = <&ssi0 &ssi1 &ssi2 &src0 &dvc0>; | ||
| 326 | }; | ||
| 327 | }; | ||
| 328 | }; | ||
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt index 962748a8d919..2b2caa281ce3 100644 --- a/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt +++ b/Documentation/devicetree/bindings/sound/renesas,rsrc-card.txt | |||
| @@ -4,8 +4,8 @@ Renesas Sampling Rate Convert Sound Card specifies audio DAI connections of SoC | |||
| 4 | 4 | ||
| 5 | Required properties: | 5 | Required properties: |
| 6 | 6 | ||
| 7 | - compatible : "renesas,rsrc-card,<board>" | 7 | - compatible : "renesas,rsrc-card{,<board>}" |
| 8 | Examples with soctypes are: | 8 | Examples with boards are: |
| 9 | - "renesas,rsrc-card" | 9 | - "renesas,rsrc-card" |
| 10 | - "renesas,rsrc-card,lager" | 10 | - "renesas,rsrc-card,lager" |
| 11 | - "renesas,rsrc-card,koelsch" | 11 | - "renesas,rsrc-card,koelsch" |
diff --git a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt index 2267d249ca0e..b7f3a9325ebd 100644 --- a/Documentation/devicetree/bindings/sound/rockchip-i2s.txt +++ b/Documentation/devicetree/bindings/sound/rockchip-i2s.txt | |||
| @@ -19,6 +19,7 @@ Required properties: | |||
| 19 | - clock-names: should contain followings: | 19 | - clock-names: should contain followings: |
| 20 | - "i2s_hclk": clock for I2S BUS | 20 | - "i2s_hclk": clock for I2S BUS |
| 21 | - "i2s_clk" : clock for I2S controller | 21 | - "i2s_clk" : clock for I2S controller |
| 22 | - rockchip,playback-channels: max playback channels, if not set, 8 channels default. | ||
| 22 | - rockchip,capture-channels: max capture channels, if not set, 2 channels default. | 23 | - rockchip,capture-channels: max capture channels, if not set, 2 channels default. |
| 23 | 24 | ||
| 24 | Example for rk3288 I2S controller: | 25 | Example for rk3288 I2S controller: |
| @@ -31,5 +32,6 @@ i2s@ff890000 { | |||
| 31 | dma-names = "tx", "rx"; | 32 | dma-names = "tx", "rx"; |
| 32 | clock-names = "i2s_hclk", "i2s_clk"; | 33 | clock-names = "i2s_hclk", "i2s_clk"; |
| 33 | clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; | 34 | clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>; |
| 35 | rockchip,playback-channels = <8>; | ||
| 34 | rockchip,capture-channels = <2>; | 36 | rockchip,capture-channels = <2>; |
| 35 | }; | 37 | }; |
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 08433a8d9d40..784468e1cbad 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig | |||
| @@ -70,6 +70,7 @@ config SND_SOC_ALL_CODECS | |||
| 70 | select SND_SOC_GTM601 | 70 | select SND_SOC_GTM601 |
| 71 | select SND_SOC_HDAC_HDMI | 71 | select SND_SOC_HDAC_HDMI |
| 72 | select SND_SOC_ICS43432 | 72 | select SND_SOC_ICS43432 |
| 73 | select SND_SOC_INNO_RK3036 | ||
| 73 | select SND_SOC_ISABELLE if I2C | 74 | select SND_SOC_ISABELLE if I2C |
| 74 | select SND_SOC_JZ4740_CODEC | 75 | select SND_SOC_JZ4740_CODEC |
| 75 | select SND_SOC_LM4857 if I2C | 76 | select SND_SOC_LM4857 if I2C |
| @@ -492,6 +493,9 @@ config SND_SOC_HDAC_HDMI | |||
| 492 | config SND_SOC_ICS43432 | 493 | config SND_SOC_ICS43432 |
| 493 | tristate | 494 | tristate |
| 494 | 495 | ||
| 496 | config SND_SOC_INNO_RK3036 | ||
| 497 | tristate "Inno codec driver for RK3036 SoC" | ||
| 498 | |||
| 495 | config SND_SOC_ISABELLE | 499 | config SND_SOC_ISABELLE |
| 496 | tristate | 500 | tristate |
| 497 | 501 | ||
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index fdf5b3146774..44d8958bd032 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile | |||
| @@ -63,6 +63,7 @@ snd-soc-es8328-spi-objs := es8328-spi.o | |||
| 63 | snd-soc-gtm601-objs := gtm601.o | 63 | snd-soc-gtm601-objs := gtm601.o |
| 64 | snd-soc-hdac-hdmi-objs := hdac_hdmi.o | 64 | snd-soc-hdac-hdmi-objs := hdac_hdmi.o |
| 65 | snd-soc-ics43432-objs := ics43432.o | 65 | snd-soc-ics43432-objs := ics43432.o |
| 66 | snd-soc-inno-rk3036-objs := inno_rk3036.o | ||
| 66 | snd-soc-isabelle-objs := isabelle.o | 67 | snd-soc-isabelle-objs := isabelle.o |
| 67 | snd-soc-jz4740-codec-objs := jz4740.o | 68 | snd-soc-jz4740-codec-objs := jz4740.o |
| 68 | snd-soc-l3-objs := l3.o | 69 | snd-soc-l3-objs := l3.o |
| @@ -264,6 +265,7 @@ obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o | |||
| 264 | obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o | 265 | obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o |
| 265 | obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o | 266 | obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o |
| 266 | obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o | 267 | obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o |
| 268 | obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o | ||
| 267 | obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o | 269 | obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o |
| 268 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o | 270 | obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o |
| 269 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o | 271 | obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o |
diff --git a/sound/soc/codecs/inno_rk3036.c b/sound/soc/codecs/inno_rk3036.c new file mode 100644 index 000000000000..9b6e8840a1b5 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.c | |||
| @@ -0,0 +1,490 @@ | |||
| 1 | /* | ||
| 2 | * Driver of Inno codec for rk3036 by Rockchip Inc. | ||
| 3 | * | ||
| 4 | * Author: Rockchip Inc. | ||
| 5 | * Author: Zheng ShunQian<zhengsq@rock-chips.com> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <sound/soc.h> | ||
| 9 | #include <sound/tlv.h> | ||
| 10 | #include <sound/soc-dapm.h> | ||
| 11 | #include <sound/soc-dai.h> | ||
| 12 | #include <sound/pcm.h> | ||
| 13 | #include <sound/pcm_params.h> | ||
| 14 | |||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | #include <linux/clk.h> | ||
| 18 | #include <linux/regmap.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/mfd/syscon.h> | ||
| 21 | #include <linux/module.h> | ||
| 22 | #include <linux/io.h> | ||
| 23 | |||
| 24 | #include "inno_rk3036.h" | ||
| 25 | |||
| 26 | struct rk3036_codec_priv { | ||
| 27 | void __iomem *base; | ||
| 28 | struct clk *pclk; | ||
| 29 | struct regmap *regmap; | ||
| 30 | struct device *dev; | ||
| 31 | }; | ||
| 32 | |||
| 33 | static const DECLARE_TLV_DB_MINMAX(rk3036_codec_hp_tlv, -39, 0); | ||
| 34 | |||
| 35 | static int rk3036_codec_antipop_info(struct snd_kcontrol *kcontrol, | ||
| 36 | struct snd_ctl_elem_info *uinfo) | ||
| 37 | { | ||
| 38 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
| 39 | uinfo->count = 2; | ||
| 40 | uinfo->value.integer.min = 0; | ||
| 41 | uinfo->value.integer.max = 1; | ||
| 42 | |||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static int rk3036_codec_antipop_get(struct snd_kcontrol *kcontrol, | ||
| 47 | struct snd_ctl_elem_value *ucontrol) | ||
| 48 | { | ||
| 49 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
| 50 | int val, ret, regval; | ||
| 51 | |||
| 52 | ret = snd_soc_component_read(component, INNO_R09, ®val); | ||
| 53 | if (ret) | ||
| 54 | return ret; | ||
| 55 | val = ((regval >> INNO_R09_HPL_ANITPOP_SHIFT) & | ||
| 56 | INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; | ||
| 57 | ucontrol->value.integer.value[0] = val; | ||
| 58 | |||
| 59 | val = ((regval >> INNO_R09_HPR_ANITPOP_SHIFT) & | ||
| 60 | INNO_R09_HP_ANTIPOP_MSK) == INNO_R09_HP_ANTIPOP_ON; | ||
| 61 | ucontrol->value.integer.value[1] = val; | ||
| 62 | |||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | static int rk3036_codec_antipop_put(struct snd_kcontrol *kcontrol, | ||
| 67 | struct snd_ctl_elem_value *ucontrol) | ||
| 68 | { | ||
| 69 | struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); | ||
| 70 | int val, ret, regmsk; | ||
| 71 | |||
| 72 | val = (ucontrol->value.integer.value[0] ? | ||
| 73 | INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << | ||
| 74 | INNO_R09_HPL_ANITPOP_SHIFT; | ||
| 75 | val |= (ucontrol->value.integer.value[1] ? | ||
| 76 | INNO_R09_HP_ANTIPOP_ON : INNO_R09_HP_ANTIPOP_OFF) << | ||
| 77 | INNO_R09_HPR_ANITPOP_SHIFT; | ||
| 78 | |||
| 79 | regmsk = INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPL_ANITPOP_SHIFT | | ||
| 80 | INNO_R09_HP_ANTIPOP_MSK << INNO_R09_HPR_ANITPOP_SHIFT; | ||
| 81 | |||
| 82 | ret = snd_soc_component_update_bits(component, INNO_R09, | ||
| 83 | regmsk, val); | ||
| 84 | if (ret < 0) | ||
| 85 | return ret; | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | #define SOC_RK3036_CODEC_ANTIPOP_DECL(xname) \ | ||
| 91 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
| 92 | .info = rk3036_codec_antipop_info, .get = rk3036_codec_antipop_get, \ | ||
| 93 | .put = rk3036_codec_antipop_put, } | ||
| 94 | |||
| 95 | static const struct snd_kcontrol_new rk3036_codec_dapm_controls[] = { | ||
| 96 | SOC_DOUBLE_R_RANGE_TLV("Headphone Volume", INNO_R07, INNO_R08, | ||
| 97 | INNO_HP_GAIN_SHIFT, INNO_HP_GAIN_N39DB, | ||
| 98 | INNO_HP_GAIN_0DB, 0, rk3036_codec_hp_tlv), | ||
| 99 | SOC_DOUBLE("Zero Cross Switch", INNO_R06, INNO_R06_VOUTL_CZ_SHIFT, | ||
| 100 | INNO_R06_VOUTR_CZ_SHIFT, 1, 0), | ||
| 101 | SOC_DOUBLE("Headphone Switch", INNO_R09, INNO_R09_HPL_MUTE_SHIFT, | ||
| 102 | INNO_R09_HPR_MUTE_SHIFT, 1, 0), | ||
| 103 | SOC_RK3036_CODEC_ANTIPOP_DECL("Anti-pop Switch"), | ||
| 104 | }; | ||
| 105 | |||
| 106 | static const struct snd_kcontrol_new rk3036_codec_hpl_mixer_controls[] = { | ||
| 107 | SOC_DAPM_SINGLE("DAC Left Out Switch", INNO_R09, | ||
| 108 | INNO_R09_DACL_SWITCH_SHIFT, 1, 0), | ||
| 109 | }; | ||
| 110 | |||
| 111 | static const struct snd_kcontrol_new rk3036_codec_hpr_mixer_controls[] = { | ||
| 112 | SOC_DAPM_SINGLE("DAC Right Out Switch", INNO_R09, | ||
| 113 | INNO_R09_DACR_SWITCH_SHIFT, 1, 0), | ||
| 114 | }; | ||
| 115 | |||
| 116 | static const struct snd_kcontrol_new rk3036_codec_hpl_switch_controls[] = { | ||
| 117 | SOC_DAPM_SINGLE("HP Left Out Switch", INNO_R05, | ||
| 118 | INNO_R05_HPL_WORK_SHIFT, 1, 0), | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const struct snd_kcontrol_new rk3036_codec_hpr_switch_controls[] = { | ||
| 122 | SOC_DAPM_SINGLE("HP Right Out Switch", INNO_R05, | ||
| 123 | INNO_R05_HPR_WORK_SHIFT, 1, 0), | ||
| 124 | }; | ||
| 125 | |||
| 126 | static const struct snd_soc_dapm_widget rk3036_codec_dapm_widgets[] = { | ||
| 127 | SND_SOC_DAPM_SUPPLY_S("DAC PWR", 1, INNO_R06, | ||
| 128 | INNO_R06_DAC_EN_SHIFT, 0, NULL, 0), | ||
| 129 | SND_SOC_DAPM_SUPPLY_S("DACL VREF", 2, INNO_R04, | ||
| 130 | INNO_R04_DACL_VREF_SHIFT, 0, NULL, 0), | ||
| 131 | SND_SOC_DAPM_SUPPLY_S("DACR VREF", 2, INNO_R04, | ||
| 132 | INNO_R04_DACR_VREF_SHIFT, 0, NULL, 0), | ||
| 133 | SND_SOC_DAPM_SUPPLY_S("DACL HiLo VREF", 3, INNO_R06, | ||
| 134 | INNO_R06_DACL_HILO_VREF_SHIFT, 0, NULL, 0), | ||
| 135 | SND_SOC_DAPM_SUPPLY_S("DACR HiLo VREF", 3, INNO_R06, | ||
| 136 | INNO_R06_DACR_HILO_VREF_SHIFT, 0, NULL, 0), | ||
| 137 | SND_SOC_DAPM_SUPPLY_S("DACR CLK", 3, INNO_R04, | ||
| 138 | INNO_R04_DACR_CLK_SHIFT, 0, NULL, 0), | ||
| 139 | SND_SOC_DAPM_SUPPLY_S("DACL CLK", 3, INNO_R04, | ||
| 140 | INNO_R04_DACL_CLK_SHIFT, 0, NULL, 0), | ||
| 141 | |||
| 142 | SND_SOC_DAPM_DAC("DACL", "Left Playback", INNO_R04, | ||
| 143 | INNO_R04_DACL_SW_SHIFT, 0), | ||
| 144 | SND_SOC_DAPM_DAC("DACR", "Right Playback", INNO_R04, | ||
| 145 | INNO_R04_DACR_SW_SHIFT, 0), | ||
| 146 | |||
| 147 | SND_SOC_DAPM_MIXER("Left Headphone Mixer", SND_SOC_NOPM, 0, 0, | ||
| 148 | rk3036_codec_hpl_mixer_controls, | ||
| 149 | ARRAY_SIZE(rk3036_codec_hpl_mixer_controls)), | ||
| 150 | SND_SOC_DAPM_MIXER("Right Headphone Mixer", SND_SOC_NOPM, 0, 0, | ||
| 151 | rk3036_codec_hpr_mixer_controls, | ||
| 152 | ARRAY_SIZE(rk3036_codec_hpr_mixer_controls)), | ||
| 153 | |||
| 154 | SND_SOC_DAPM_PGA("HP Left Out", INNO_R05, | ||
| 155 | INNO_R05_HPL_EN_SHIFT, 0, NULL, 0), | ||
| 156 | SND_SOC_DAPM_PGA("HP Right Out", INNO_R05, | ||
| 157 | INNO_R05_HPR_EN_SHIFT, 0, NULL, 0), | ||
| 158 | |||
| 159 | SND_SOC_DAPM_MIXER("HP Left Switch", SND_SOC_NOPM, 0, 0, | ||
| 160 | rk3036_codec_hpl_switch_controls, | ||
| 161 | ARRAY_SIZE(rk3036_codec_hpl_switch_controls)), | ||
| 162 | SND_SOC_DAPM_MIXER("HP Right Switch", SND_SOC_NOPM, 0, 0, | ||
| 163 | rk3036_codec_hpr_switch_controls, | ||
| 164 | ARRAY_SIZE(rk3036_codec_hpr_switch_controls)), | ||
| 165 | |||
| 166 | SND_SOC_DAPM_OUTPUT("HPL"), | ||
| 167 | SND_SOC_DAPM_OUTPUT("HPR"), | ||
| 168 | }; | ||
| 169 | |||
| 170 | static const struct snd_soc_dapm_route rk3036_codec_dapm_routes[] = { | ||
| 171 | {"DACL VREF", NULL, "DAC PWR"}, | ||
| 172 | {"DACR VREF", NULL, "DAC PWR"}, | ||
| 173 | {"DACL HiLo VREF", NULL, "DAC PWR"}, | ||
| 174 | {"DACR HiLo VREF", NULL, "DAC PWR"}, | ||
| 175 | {"DACL CLK", NULL, "DAC PWR"}, | ||
| 176 | {"DACR CLK", NULL, "DAC PWR"}, | ||
| 177 | |||
| 178 | {"DACL", NULL, "DACL VREF"}, | ||
| 179 | {"DACL", NULL, "DACL HiLo VREF"}, | ||
| 180 | {"DACL", NULL, "DACL CLK"}, | ||
| 181 | {"DACR", NULL, "DACR VREF"}, | ||
| 182 | {"DACR", NULL, "DACR HiLo VREF"}, | ||
| 183 | {"DACR", NULL, "DACR CLK"}, | ||
| 184 | |||
| 185 | {"Left Headphone Mixer", "DAC Left Out Switch", "DACL"}, | ||
| 186 | {"Right Headphone Mixer", "DAC Right Out Switch", "DACR"}, | ||
| 187 | {"HP Left Out", NULL, "Left Headphone Mixer"}, | ||
| 188 | {"HP Right Out", NULL, "Right Headphone Mixer"}, | ||
| 189 | |||
| 190 | {"HP Left Switch", "HP Left Out Switch", "HP Left Out"}, | ||
| 191 | {"HP Right Switch", "HP Right Out Switch", "HP Right Out"}, | ||
| 192 | |||
| 193 | {"HPL", NULL, "HP Left Switch"}, | ||
| 194 | {"HPR", NULL, "HP Right Switch"}, | ||
| 195 | }; | ||
| 196 | |||
| 197 | static int rk3036_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | ||
| 198 | { | ||
| 199 | struct snd_soc_codec *codec = dai->codec; | ||
| 200 | unsigned int reg01_val = 0, reg02_val = 0, reg03_val = 0; | ||
| 201 | |||
| 202 | dev_dbg(codec->dev, "rk3036_codec dai set fmt : %08x\n", fmt); | ||
| 203 | |||
| 204 | switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { | ||
| 205 | case SND_SOC_DAIFMT_CBS_CFS: | ||
| 206 | reg01_val |= INNO_R01_PINDIR_IN_SLAVE | | ||
| 207 | INNO_R01_I2SMODE_SLAVE; | ||
| 208 | break; | ||
| 209 | case SND_SOC_DAIFMT_CBM_CFM: | ||
| 210 | reg01_val |= INNO_R01_PINDIR_OUT_MASTER | | ||
| 211 | INNO_R01_I2SMODE_MASTER; | ||
| 212 | break; | ||
| 213 | default: | ||
| 214 | dev_err(codec->dev, "invalid fmt\n"); | ||
| 215 | return -EINVAL; | ||
| 216 | } | ||
| 217 | |||
| 218 | switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { | ||
| 219 | case SND_SOC_DAIFMT_DSP_A: | ||
| 220 | reg02_val |= INNO_R02_DACM_PCM; | ||
| 221 | break; | ||
| 222 | case SND_SOC_DAIFMT_I2S: | ||
| 223 | reg02_val |= INNO_R02_DACM_I2S; | ||
| 224 | break; | ||
| 225 | case SND_SOC_DAIFMT_RIGHT_J: | ||
| 226 | reg02_val |= INNO_R02_DACM_RJM; | ||
| 227 | break; | ||
| 228 | case SND_SOC_DAIFMT_LEFT_J: | ||
| 229 | reg02_val |= INNO_R02_DACM_LJM; | ||
| 230 | break; | ||
| 231 | default: | ||
| 232 | dev_err(codec->dev, "set dai format failed\n"); | ||
| 233 | return -EINVAL; | ||
| 234 | } | ||
| 235 | |||
| 236 | switch (fmt & SND_SOC_DAIFMT_INV_MASK) { | ||
| 237 | case SND_SOC_DAIFMT_NB_NF: | ||
| 238 | reg02_val |= INNO_R02_LRCP_NORMAL; | ||
| 239 | reg03_val |= INNO_R03_BCP_NORMAL; | ||
| 240 | break; | ||
| 241 | case SND_SOC_DAIFMT_IB_IF: | ||
| 242 | reg02_val |= INNO_R02_LRCP_REVERSAL; | ||
| 243 | reg03_val |= INNO_R03_BCP_REVERSAL; | ||
| 244 | break; | ||
| 245 | case SND_SOC_DAIFMT_IB_NF: | ||
| 246 | reg02_val |= INNO_R02_LRCP_REVERSAL; | ||
| 247 | reg03_val |= INNO_R03_BCP_NORMAL; | ||
| 248 | break; | ||
| 249 | case SND_SOC_DAIFMT_NB_IF: | ||
| 250 | reg02_val |= INNO_R02_LRCP_NORMAL; | ||
| 251 | reg03_val |= INNO_R03_BCP_REVERSAL; | ||
| 252 | break; | ||
| 253 | default: | ||
| 254 | dev_err(codec->dev, "set dai format failed\n"); | ||
| 255 | return -EINVAL; | ||
| 256 | } | ||
| 257 | |||
| 258 | snd_soc_update_bits(codec, INNO_R01, INNO_R01_I2SMODE_MSK | | ||
| 259 | INNO_R01_PINDIR_MSK, reg01_val); | ||
| 260 | snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | | ||
| 261 | INNO_R02_DACM_MSK, reg02_val); | ||
| 262 | snd_soc_update_bits(codec, INNO_R03, INNO_R03_BCP_MSK, reg03_val); | ||
| 263 | |||
| 264 | return 0; | ||
| 265 | } | ||
| 266 | |||
| 267 | static int rk3036_codec_dai_hw_params(struct snd_pcm_substream *substream, | ||
| 268 | struct snd_pcm_hw_params *hw_params, | ||
| 269 | struct snd_soc_dai *dai) | ||
| 270 | { | ||
| 271 | struct snd_soc_codec *codec = dai->codec; | ||
| 272 | unsigned int reg02_val = 0, reg03_val = 0; | ||
| 273 | |||
| 274 | switch (params_format(hw_params)) { | ||
| 275 | case SNDRV_PCM_FORMAT_S16_LE: | ||
| 276 | reg02_val |= INNO_R02_VWL_16BIT; | ||
| 277 | break; | ||
| 278 | case SNDRV_PCM_FORMAT_S20_3LE: | ||
| 279 | reg02_val |= INNO_R02_VWL_20BIT; | ||
| 280 | break; | ||
| 281 | case SNDRV_PCM_FORMAT_S24_LE: | ||
| 282 | reg02_val |= INNO_R02_VWL_24BIT; | ||
| 283 | break; | ||
| 284 | case SNDRV_PCM_FORMAT_S32_LE: | ||
| 285 | reg02_val |= INNO_R02_VWL_32BIT; | ||
| 286 | break; | ||
| 287 | default: | ||
| 288 | return -EINVAL; | ||
| 289 | } | ||
| 290 | |||
| 291 | reg02_val |= INNO_R02_LRCP_NORMAL; | ||
| 292 | reg03_val |= INNO_R03_FWL_32BIT | INNO_R03_DACR_WORK; | ||
| 293 | |||
| 294 | snd_soc_update_bits(codec, INNO_R02, INNO_R02_LRCP_MSK | | ||
| 295 | INNO_R02_VWL_MSK, reg02_val); | ||
| 296 | snd_soc_update_bits(codec, INNO_R03, INNO_R03_DACR_MSK | | ||
| 297 | INNO_R03_FWL_MSK, reg03_val); | ||
| 298 | return 0; | ||
| 299 | } | ||
| 300 | |||
| 301 | #define RK3036_CODEC_RATES (SNDRV_PCM_RATE_8000 | \ | ||
| 302 | SNDRV_PCM_RATE_16000 | \ | ||
| 303 | SNDRV_PCM_RATE_32000 | \ | ||
| 304 | SNDRV_PCM_RATE_44100 | \ | ||
| 305 | SNDRV_PCM_RATE_48000 | \ | ||
| 306 | SNDRV_PCM_RATE_96000) | ||
| 307 | |||
| 308 | #define RK3036_CODEC_FMTS (SNDRV_PCM_FMTBIT_S16_LE | \ | ||
| 309 | SNDRV_PCM_FMTBIT_S20_3LE | \ | ||
| 310 | SNDRV_PCM_FMTBIT_S24_LE | \ | ||
| 311 | SNDRV_PCM_FMTBIT_S32_LE) | ||
| 312 | |||
| 313 | static struct snd_soc_dai_ops rk3036_codec_dai_ops = { | ||
| 314 | .set_fmt = rk3036_codec_dai_set_fmt, | ||
| 315 | .hw_params = rk3036_codec_dai_hw_params, | ||
| 316 | }; | ||
| 317 | |||
| 318 | static struct snd_soc_dai_driver rk3036_codec_dai_driver[] = { | ||
| 319 | { | ||
| 320 | .name = "rk3036-codec-dai", | ||
| 321 | .playback = { | ||
| 322 | .stream_name = "Playback", | ||
| 323 | .channels_min = 1, | ||
| 324 | .channels_max = 2, | ||
| 325 | .rates = RK3036_CODEC_RATES, | ||
| 326 | .formats = RK3036_CODEC_FMTS, | ||
| 327 | }, | ||
| 328 | .ops = &rk3036_codec_dai_ops, | ||
| 329 | .symmetric_rates = 1, | ||
| 330 | }, | ||
| 331 | }; | ||
| 332 | |||
| 333 | static void rk3036_codec_reset(struct snd_soc_codec *codec) | ||
| 334 | { | ||
| 335 | snd_soc_write(codec, INNO_R00, | ||
| 336 | INNO_R00_CSR_RESET | INNO_R00_CDCR_RESET); | ||
| 337 | snd_soc_write(codec, INNO_R00, | ||
| 338 | INNO_R00_CSR_WORK | INNO_R00_CDCR_WORK); | ||
| 339 | } | ||
| 340 | |||
| 341 | static int rk3036_codec_probe(struct snd_soc_codec *codec) | ||
| 342 | { | ||
| 343 | rk3036_codec_reset(codec); | ||
| 344 | return 0; | ||
| 345 | } | ||
| 346 | |||
| 347 | static int rk3036_codec_remove(struct snd_soc_codec *codec) | ||
| 348 | { | ||
| 349 | rk3036_codec_reset(codec); | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | static int rk3036_codec_set_bias_level(struct snd_soc_codec *codec, | ||
| 354 | enum snd_soc_bias_level level) | ||
| 355 | { | ||
| 356 | switch (level) { | ||
| 357 | case SND_SOC_BIAS_STANDBY: | ||
| 358 | /* set a big current for capacitor charging. */ | ||
| 359 | snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); | ||
| 360 | /* start precharge */ | ||
| 361 | snd_soc_write(codec, INNO_R06, INNO_R06_DAC_PRECHARGE); | ||
| 362 | |||
| 363 | break; | ||
| 364 | |||
| 365 | case SND_SOC_BIAS_OFF: | ||
| 366 | /* set a big current for capacitor discharging. */ | ||
| 367 | snd_soc_write(codec, INNO_R10, INNO_R10_MAX_CUR); | ||
| 368 | /* start discharge. */ | ||
| 369 | snd_soc_write(codec, INNO_R06, INNO_R06_DAC_DISCHARGE); | ||
| 370 | |||
| 371 | break; | ||
| 372 | default: | ||
| 373 | break; | ||
| 374 | } | ||
| 375 | |||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | |||
| 379 | static struct snd_soc_codec_driver rk3036_codec_driver = { | ||
| 380 | .probe = rk3036_codec_probe, | ||
| 381 | .remove = rk3036_codec_remove, | ||
| 382 | .set_bias_level = rk3036_codec_set_bias_level, | ||
| 383 | .controls = rk3036_codec_dapm_controls, | ||
| 384 | .num_controls = ARRAY_SIZE(rk3036_codec_dapm_controls), | ||
| 385 | .dapm_routes = rk3036_codec_dapm_routes, | ||
| 386 | .num_dapm_routes = ARRAY_SIZE(rk3036_codec_dapm_routes), | ||
| 387 | .dapm_widgets = rk3036_codec_dapm_widgets, | ||
| 388 | .num_dapm_widgets = ARRAY_SIZE(rk3036_codec_dapm_widgets), | ||
| 389 | }; | ||
| 390 | |||
| 391 | static const struct regmap_config rk3036_codec_regmap_config = { | ||
| 392 | .reg_bits = 32, | ||
| 393 | .reg_stride = 4, | ||
| 394 | .val_bits = 32, | ||
| 395 | }; | ||
| 396 | |||
| 397 | #define GRF_SOC_CON0 0x00140 | ||
| 398 | #define GRF_ACODEC_SEL (BIT(10) | BIT(16 + 10)) | ||
| 399 | |||
| 400 | static int rk3036_codec_platform_probe(struct platform_device *pdev) | ||
| 401 | { | ||
| 402 | struct rk3036_codec_priv *priv; | ||
| 403 | struct device_node *of_node = pdev->dev.of_node; | ||
| 404 | struct resource *res; | ||
| 405 | void __iomem *base; | ||
| 406 | struct regmap *grf; | ||
| 407 | int ret; | ||
| 408 | |||
| 409 | priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); | ||
| 410 | if (!priv) | ||
| 411 | return -ENOMEM; | ||
| 412 | |||
| 413 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 414 | base = devm_ioremap_resource(&pdev->dev, res); | ||
| 415 | if (IS_ERR(base)) | ||
| 416 | return PTR_ERR(base); | ||
| 417 | |||
| 418 | priv->base = base; | ||
| 419 | priv->regmap = devm_regmap_init_mmio(&pdev->dev, priv->base, | ||
| 420 | &rk3036_codec_regmap_config); | ||
| 421 | if (IS_ERR(priv->regmap)) { | ||
| 422 | dev_err(&pdev->dev, "init regmap failed\n"); | ||
| 423 | return PTR_ERR(priv->regmap); | ||
| 424 | } | ||
| 425 | |||
| 426 | grf = syscon_regmap_lookup_by_phandle(of_node, "rockchip,grf"); | ||
| 427 | if (IS_ERR(grf)) { | ||
| 428 | dev_err(&pdev->dev, "needs 'rockchip,grf' property\n"); | ||
| 429 | return PTR_ERR(grf); | ||
| 430 | } | ||
| 431 | ret = regmap_write(grf, GRF_SOC_CON0, GRF_ACODEC_SEL); | ||
| 432 | if (ret) { | ||
| 433 | dev_err(&pdev->dev, "Could not write to GRF: %d\n", ret); | ||
| 434 | return ret; | ||
| 435 | } | ||
| 436 | |||
| 437 | priv->pclk = devm_clk_get(&pdev->dev, "acodec_pclk"); | ||
| 438 | if (IS_ERR(priv->pclk)) | ||
| 439 | return PTR_ERR(priv->pclk); | ||
| 440 | |||
| 441 | ret = clk_prepare_enable(priv->pclk); | ||
| 442 | if (ret < 0) { | ||
| 443 | dev_err(&pdev->dev, "failed to enable clk\n"); | ||
| 444 | return ret; | ||
| 445 | } | ||
| 446 | |||
| 447 | priv->dev = &pdev->dev; | ||
| 448 | dev_set_drvdata(&pdev->dev, priv); | ||
| 449 | |||
| 450 | ret = snd_soc_register_codec(&pdev->dev, &rk3036_codec_driver, | ||
| 451 | rk3036_codec_dai_driver, | ||
| 452 | ARRAY_SIZE(rk3036_codec_dai_driver)); | ||
| 453 | if (ret) { | ||
| 454 | clk_disable_unprepare(priv->pclk); | ||
| 455 | dev_set_drvdata(&pdev->dev, NULL); | ||
| 456 | } | ||
| 457 | |||
| 458 | return ret; | ||
| 459 | } | ||
| 460 | |||
| 461 | static int rk3036_codec_platform_remove(struct platform_device *pdev) | ||
| 462 | { | ||
| 463 | struct rk3036_codec_priv *priv = dev_get_drvdata(&pdev->dev); | ||
| 464 | |||
| 465 | snd_soc_unregister_codec(&pdev->dev); | ||
| 466 | clk_disable_unprepare(priv->pclk); | ||
| 467 | |||
| 468 | return 0; | ||
| 469 | } | ||
| 470 | |||
| 471 | static const struct of_device_id rk3036_codec_of_match[] = { | ||
| 472 | { .compatible = "rockchip,rk3036-codec", }, | ||
| 473 | {} | ||
| 474 | }; | ||
| 475 | MODULE_DEVICE_TABLE(of, rk3036_codec_of_match); | ||
| 476 | |||
| 477 | static struct platform_driver rk3036_codec_platform_driver = { | ||
| 478 | .driver = { | ||
| 479 | .name = "rk3036-codec-platform", | ||
| 480 | .of_match_table = of_match_ptr(rk3036_codec_of_match), | ||
| 481 | }, | ||
| 482 | .probe = rk3036_codec_platform_probe, | ||
| 483 | .remove = rk3036_codec_platform_remove, | ||
| 484 | }; | ||
| 485 | |||
| 486 | module_platform_driver(rk3036_codec_platform_driver); | ||
| 487 | |||
| 488 | MODULE_AUTHOR("Rockchip Inc."); | ||
| 489 | MODULE_DESCRIPTION("Rockchip rk3036 codec driver"); | ||
| 490 | MODULE_LICENSE("GPL"); | ||
diff --git a/sound/soc/codecs/inno_rk3036.h b/sound/soc/codecs/inno_rk3036.h new file mode 100644 index 000000000000..da759c6c7501 --- /dev/null +++ b/sound/soc/codecs/inno_rk3036.h | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | /* | ||
| 2 | * Driver of Inno Codec for rk3036 by Rockchip Inc. | ||
| 3 | * | ||
| 4 | * Author: Zheng ShunQian<zhengsq@rock-chips.com> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #ifndef _INNO_RK3036_CODEC_H | ||
| 8 | #define _INNO_RK3036_CODEC_H | ||
| 9 | |||
| 10 | /* codec registers */ | ||
| 11 | #define INNO_R00 0x00 | ||
| 12 | #define INNO_R01 0x0c | ||
| 13 | #define INNO_R02 0x10 | ||
| 14 | #define INNO_R03 0x14 | ||
| 15 | #define INNO_R04 0x88 | ||
| 16 | #define INNO_R05 0x8c | ||
| 17 | #define INNO_R06 0x90 | ||
| 18 | #define INNO_R07 0x94 | ||
| 19 | #define INNO_R08 0x98 | ||
| 20 | #define INNO_R09 0x9c | ||
| 21 | #define INNO_R10 0xa0 | ||
| 22 | |||
| 23 | /* register bit filed */ | ||
| 24 | #define INNO_R00_CSR_RESET (0x0 << 0) /*codec system reset*/ | ||
| 25 | #define INNO_R00_CSR_WORK (0x1 << 0) | ||
| 26 | #define INNO_R00_CDCR_RESET (0x0 << 1) /*codec digital core reset*/ | ||
| 27 | #define INNO_R00_CDCR_WORK (0x1 << 1) | ||
| 28 | #define INNO_R00_PRB_DISABLE (0x0 << 6) /*power reset bypass*/ | ||
| 29 | #define INNO_R00_PRB_ENABLE (0x1 << 6) | ||
| 30 | |||
| 31 | #define INNO_R01_I2SMODE_MSK (0x1 << 4) | ||
| 32 | #define INNO_R01_I2SMODE_SLAVE (0x0 << 4) | ||
| 33 | #define INNO_R01_I2SMODE_MASTER (0x1 << 4) | ||
| 34 | #define INNO_R01_PINDIR_MSK (0x1 << 5) | ||
| 35 | #define INNO_R01_PINDIR_IN_SLAVE (0x0 << 5) /*direction of pin*/ | ||
| 36 | #define INNO_R01_PINDIR_OUT_MASTER (0x1 << 5) | ||
| 37 | |||
| 38 | #define INNO_R02_LRS_MSK (0x1 << 2) | ||
| 39 | #define INNO_R02_LRS_NORMAL (0x0 << 2) /*DAC Left Right Swap*/ | ||
| 40 | #define INNO_R02_LRS_SWAP (0x1 << 2) | ||
| 41 | #define INNO_R02_DACM_MSK (0x3 << 3) | ||
| 42 | #define INNO_R02_DACM_PCM (0x3 << 3) /*DAC Mode*/ | ||
| 43 | #define INNO_R02_DACM_I2S (0x2 << 3) | ||
| 44 | #define INNO_R02_DACM_LJM (0x1 << 3) | ||
| 45 | #define INNO_R02_DACM_RJM (0x0 << 3) | ||
| 46 | #define INNO_R02_VWL_MSK (0x3 << 5) | ||
| 47 | #define INNO_R02_VWL_32BIT (0x3 << 5) /*1/2Frame Valid Word Len*/ | ||
| 48 | #define INNO_R02_VWL_24BIT (0x2 << 5) | ||
| 49 | #define INNO_R02_VWL_20BIT (0x1 << 5) | ||
| 50 | #define INNO_R02_VWL_16BIT (0x0 << 5) | ||
| 51 | #define INNO_R02_LRCP_MSK (0x1 << 7) | ||
| 52 | #define INNO_R02_LRCP_NORMAL (0x0 << 7) /*Left Right Polarity*/ | ||
| 53 | #define INNO_R02_LRCP_REVERSAL (0x1 << 7) | ||
| 54 | |||
| 55 | #define INNO_R03_BCP_MSK (0x1 << 0) | ||
| 56 | #define INNO_R03_BCP_NORMAL (0x0 << 0) /*DAC bit clock polarity*/ | ||
| 57 | #define INNO_R03_BCP_REVERSAL (0x1 << 0) | ||
| 58 | #define INNO_R03_DACR_MSK (0x1 << 1) | ||
| 59 | #define INNO_R03_DACR_RESET (0x0 << 1) /*DAC Reset*/ | ||
| 60 | #define INNO_R03_DACR_WORK (0x1 << 1) | ||
| 61 | #define INNO_R03_FWL_MSK (0x3 << 2) | ||
| 62 | #define INNO_R03_FWL_32BIT (0x3 << 2) /*1/2Frame Word Length*/ | ||
| 63 | #define INNO_R03_FWL_24BIT (0x2 << 2) | ||
| 64 | #define INNO_R03_FWL_20BIT (0x1 << 2) | ||
| 65 | #define INNO_R03_FWL_16BIT (0x0 << 2) | ||
| 66 | |||
| 67 | #define INNO_R04_DACR_SW_SHIFT 0 | ||
| 68 | #define INNO_R04_DACL_SW_SHIFT 1 | ||
| 69 | #define INNO_R04_DACR_CLK_SHIFT 2 | ||
| 70 | #define INNO_R04_DACL_CLK_SHIFT 3 | ||
| 71 | #define INNO_R04_DACR_VREF_SHIFT 4 | ||
| 72 | #define INNO_R04_DACL_VREF_SHIFT 5 | ||
| 73 | |||
| 74 | #define INNO_R05_HPR_EN_SHIFT 0 | ||
| 75 | #define INNO_R05_HPL_EN_SHIFT 1 | ||
| 76 | #define INNO_R05_HPR_WORK_SHIFT 2 | ||
| 77 | #define INNO_R05_HPL_WORK_SHIFT 3 | ||
| 78 | |||
| 79 | #define INNO_R06_VOUTR_CZ_SHIFT 0 | ||
| 80 | #define INNO_R06_VOUTL_CZ_SHIFT 1 | ||
| 81 | #define INNO_R06_DACR_HILO_VREF_SHIFT 2 | ||
| 82 | #define INNO_R06_DACL_HILO_VREF_SHIFT 3 | ||
| 83 | #define INNO_R06_DAC_EN_SHIFT 5 | ||
| 84 | |||
| 85 | #define INNO_R06_DAC_PRECHARGE (0x0 << 4) /*PreCharge control for DAC*/ | ||
| 86 | #define INNO_R06_DAC_DISCHARGE (0x1 << 4) | ||
| 87 | |||
| 88 | #define INNO_HP_GAIN_SHIFT 0 | ||
| 89 | /* Gain of output, 1.5db step: -39db(0x0) ~ 0db(0x1a) ~ 6db(0x1f) */ | ||
| 90 | #define INNO_HP_GAIN_0DB 0x1a | ||
| 91 | #define INNO_HP_GAIN_N39DB 0x0 | ||
| 92 | |||
| 93 | #define INNO_R09_HP_ANTIPOP_MSK 0x3 | ||
| 94 | #define INNO_R09_HP_ANTIPOP_OFF 0x1 | ||
| 95 | #define INNO_R09_HP_ANTIPOP_ON 0x2 | ||
| 96 | #define INNO_R09_HPR_ANITPOP_SHIFT 0 | ||
| 97 | #define INNO_R09_HPL_ANITPOP_SHIFT 2 | ||
| 98 | #define INNO_R09_HPR_MUTE_SHIFT 4 | ||
| 99 | #define INNO_R09_HPL_MUTE_SHIFT 5 | ||
| 100 | #define INNO_R09_DACR_SWITCH_SHIFT 6 | ||
| 101 | #define INNO_R09_DACL_SWITCH_SHIFT 7 | ||
| 102 | |||
| 103 | #define INNO_R10_CHARGE_SEL_CUR_400I_YES (0x0 << 0) | ||
| 104 | #define INNO_R10_CHARGE_SEL_CUR_400I_NO (0x1 << 0) | ||
| 105 | #define INNO_R10_CHARGE_SEL_CUR_260I_YES (0x0 << 1) | ||
| 106 | #define INNO_R10_CHARGE_SEL_CUR_260I_NO (0x1 << 1) | ||
| 107 | #define INNO_R10_CHARGE_SEL_CUR_130I_YES (0x0 << 2) | ||
| 108 | #define INNO_R10_CHARGE_SEL_CUR_130I_NO (0x1 << 2) | ||
| 109 | #define INNO_R10_CHARGE_SEL_CUR_100I_YES (0x0 << 3) | ||
| 110 | #define INNO_R10_CHARGE_SEL_CUR_100I_NO (0x1 << 3) | ||
| 111 | #define INNO_R10_CHARGE_SEL_CUR_050I_YES (0x0 << 4) | ||
| 112 | #define INNO_R10_CHARGE_SEL_CUR_050I_NO (0x1 << 4) | ||
| 113 | #define INNO_R10_CHARGE_SEL_CUR_027I_YES (0x0 << 5) | ||
| 114 | #define INNO_R10_CHARGE_SEL_CUR_027I_NO (0x1 << 5) | ||
| 115 | |||
| 116 | #define INNO_R10_MAX_CUR (INNO_R10_CHARGE_SEL_CUR_400I_YES | \ | ||
| 117 | INNO_R10_CHARGE_SEL_CUR_260I_YES | \ | ||
| 118 | INNO_R10_CHARGE_SEL_CUR_130I_YES | \ | ||
| 119 | INNO_R10_CHARGE_SEL_CUR_100I_YES | \ | ||
| 120 | INNO_R10_CHARGE_SEL_CUR_050I_YES | \ | ||
| 121 | INNO_R10_CHARGE_SEL_CUR_027I_YES) | ||
| 122 | |||
| 123 | #endif | ||
diff --git a/sound/soc/pxa/brownstone.c b/sound/soc/pxa/brownstone.c index 6147e86e9b0f..416ea646c3b1 100644 --- a/sound/soc/pxa/brownstone.c +++ b/sound/soc/pxa/brownstone.c | |||
| @@ -63,8 +63,7 @@ static int brownstone_wm8994_hw_params(struct snd_pcm_substream *substream, | |||
| 63 | sysclk = params_rate(params) * 512; | 63 | sysclk = params_rate(params) * 512; |
| 64 | sspa_mclk = params_rate(params) * 64; | 64 | sspa_mclk = params_rate(params) * 64; |
| 65 | } | 65 | } |
| 66 | sspa_div = freq_out; | 66 | sspa_div = freq_out / sspa_mclk; |
| 67 | do_div(sspa_div, sspa_mclk); | ||
| 68 | 67 | ||
| 69 | snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); | 68 | snd_soc_dai_set_sysclk(cpu_dai, MMP_SSPA_CLK_AUDIO, freq_out, 0); |
| 70 | snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); | 69 | snd_soc_dai_set_pll(cpu_dai, MMP_SYSCLK, 0, freq_out, sysclk); |
diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index e5101e0d2d37..00b6c9d039cf 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c | |||
| @@ -355,6 +355,7 @@ static struct regmap_config lpass_cpu_regmap_config = { | |||
| 355 | .readable_reg = lpass_cpu_regmap_readable, | 355 | .readable_reg = lpass_cpu_regmap_readable, |
| 356 | .volatile_reg = lpass_cpu_regmap_volatile, | 356 | .volatile_reg = lpass_cpu_regmap_volatile, |
| 357 | .cache_type = REGCACHE_FLAT, | 357 | .cache_type = REGCACHE_FLAT, |
| 358 | .val_format_endian = REGMAP_ENDIAN_LITTLE, | ||
| 358 | }; | 359 | }; |
| 359 | 360 | ||
| 360 | int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) | 361 | int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev) |
diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c index 58ee64594f07..8b0a588ed622 100644 --- a/sound/soc/rockchip/rockchip_i2s.c +++ b/sound/soc/rockchip/rockchip_i2s.c | |||
| @@ -34,13 +34,7 @@ struct rk_i2s_dev { | |||
| 34 | 34 | ||
| 35 | struct regmap *regmap; | 35 | struct regmap *regmap; |
| 36 | 36 | ||
| 37 | /* | 37 | bool is_master_mode; |
| 38 | * Used to indicate the tx/rx status. | ||
| 39 | * I2S controller hopes to start the tx and rx together, | ||
| 40 | * also to stop them when they are both try to stop. | ||
| 41 | */ | ||
| 42 | bool tx_start; | ||
| 43 | bool rx_start; | ||
| 44 | }; | 38 | }; |
| 45 | 39 | ||
| 46 | static int i2s_runtime_suspend(struct device *dev) | 40 | static int i2s_runtime_suspend(struct device *dev) |
| @@ -81,37 +75,29 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on) | |||
| 81 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); | 75 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE); |
| 82 | 76 | ||
| 83 | regmap_update_bits(i2s->regmap, I2S_XFER, | 77 | regmap_update_bits(i2s->regmap, I2S_XFER, |
| 84 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, | 78 | I2S_XFER_TXS_START, |
| 85 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); | 79 | I2S_XFER_TXS_START); |
| 86 | |||
| 87 | i2s->tx_start = true; | ||
| 88 | } else { | 80 | } else { |
| 89 | i2s->tx_start = false; | ||
| 90 | |||
| 91 | regmap_update_bits(i2s->regmap, I2S_DMACR, | 81 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
| 92 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); | 82 | I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE); |
| 93 | 83 | ||
| 94 | if (!i2s->rx_start) { | 84 | regmap_update_bits(i2s->regmap, I2S_XFER, |
| 95 | regmap_update_bits(i2s->regmap, I2S_XFER, | 85 | I2S_XFER_TXS_START, |
| 96 | I2S_XFER_TXS_START | | 86 | I2S_XFER_TXS_STOP); |
| 97 | I2S_XFER_RXS_START, | ||
| 98 | I2S_XFER_TXS_STOP | | ||
| 99 | I2S_XFER_RXS_STOP); | ||
| 100 | 87 | ||
| 101 | regmap_update_bits(i2s->regmap, I2S_CLR, | 88 | regmap_update_bits(i2s->regmap, I2S_CLR, |
| 102 | I2S_CLR_TXC | I2S_CLR_RXC, | 89 | I2S_CLR_TXC, |
| 103 | I2S_CLR_TXC | I2S_CLR_RXC); | 90 | I2S_CLR_TXC); |
| 104 | 91 | ||
| 105 | regmap_read(i2s->regmap, I2S_CLR, &val); | 92 | regmap_read(i2s->regmap, I2S_CLR, &val); |
| 106 | 93 | ||
| 107 | /* Should wait for clear operation to finish */ | 94 | /* Should wait for clear operation to finish */ |
| 108 | while (val) { | 95 | while (val & I2S_CLR_TXC) { |
| 109 | regmap_read(i2s->regmap, I2S_CLR, &val); | 96 | regmap_read(i2s->regmap, I2S_CLR, &val); |
| 110 | retry--; | 97 | retry--; |
| 111 | if (!retry) { | 98 | if (!retry) { |
| 112 | dev_warn(i2s->dev, "fail to clear\n"); | 99 | dev_warn(i2s->dev, "fail to clear\n"); |
| 113 | break; | 100 | break; |
| 114 | } | ||
| 115 | } | 101 | } |
| 116 | } | 102 | } |
| 117 | } | 103 | } |
| @@ -127,37 +113,29 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on) | |||
| 127 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); | 113 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE); |
| 128 | 114 | ||
| 129 | regmap_update_bits(i2s->regmap, I2S_XFER, | 115 | regmap_update_bits(i2s->regmap, I2S_XFER, |
| 130 | I2S_XFER_TXS_START | I2S_XFER_RXS_START, | 116 | I2S_XFER_RXS_START, |
| 131 | I2S_XFER_TXS_START | I2S_XFER_RXS_START); | 117 | I2S_XFER_RXS_START); |
| 132 | |||
| 133 | i2s->rx_start = true; | ||
| 134 | } else { | 118 | } else { |
| 135 | i2s->rx_start = false; | ||
| 136 | |||
| 137 | regmap_update_bits(i2s->regmap, I2S_DMACR, | 119 | regmap_update_bits(i2s->regmap, I2S_DMACR, |
| 138 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); | 120 | I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE); |
| 139 | 121 | ||
| 140 | if (!i2s->tx_start) { | 122 | regmap_update_bits(i2s->regmap, I2S_XFER, |
| 141 | regmap_update_bits(i2s->regmap, I2S_XFER, | 123 | I2S_XFER_RXS_START, |
| 142 | I2S_XFER_TXS_START | | 124 | I2S_XFER_RXS_STOP); |
| 143 | I2S_XFER_RXS_START, | ||
| 144 | I2S_XFER_TXS_STOP | | ||
| 145 | I2S_XFER_RXS_STOP); | ||
| 146 | 125 | ||
| 147 | regmap_update_bits(i2s->regmap, I2S_CLR, | 126 | regmap_update_bits(i2s->regmap, I2S_CLR, |
| 148 | I2S_CLR_TXC | I2S_CLR_RXC, | 127 | I2S_CLR_RXC, |
| 149 | I2S_CLR_TXC | I2S_CLR_RXC); | 128 | I2S_CLR_RXC); |
| 150 | 129 | ||
| 151 | regmap_read(i2s->regmap, I2S_CLR, &val); | 130 | regmap_read(i2s->regmap, I2S_CLR, &val); |
| 152 | 131 | ||
| 153 | /* Should wait for clear operation to finish */ | 132 | /* Should wait for clear operation to finish */ |
| 154 | while (val) { | 133 | while (val & I2S_CLR_RXC) { |
| 155 | regmap_read(i2s->regmap, I2S_CLR, &val); | 134 | regmap_read(i2s->regmap, I2S_CLR, &val); |
| 156 | retry--; | 135 | retry--; |
| 157 | if (!retry) { | 136 | if (!retry) { |
| 158 | dev_warn(i2s->dev, "fail to clear\n"); | 137 | dev_warn(i2s->dev, "fail to clear\n"); |
| 159 | break; | 138 | break; |
| 160 | } | ||
| 161 | } | 139 | } |
| 162 | } | 140 | } |
| 163 | } | 141 | } |
| @@ -174,9 +152,11 @@ static int rockchip_i2s_set_fmt(struct snd_soc_dai *cpu_dai, | |||
| 174 | case SND_SOC_DAIFMT_CBS_CFS: | 152 | case SND_SOC_DAIFMT_CBS_CFS: |
| 175 | /* Set source clock in Master mode */ | 153 | /* Set source clock in Master mode */ |
| 176 | val = I2S_CKR_MSS_MASTER; | 154 | val = I2S_CKR_MSS_MASTER; |
| 155 | i2s->is_master_mode = true; | ||
| 177 | break; | 156 | break; |
| 178 | case SND_SOC_DAIFMT_CBM_CFM: | 157 | case SND_SOC_DAIFMT_CBM_CFM: |
| 179 | val = I2S_CKR_MSS_SLAVE; | 158 | val = I2S_CKR_MSS_SLAVE; |
| 159 | i2s->is_master_mode = false; | ||
| 180 | break; | 160 | break; |
| 181 | default: | 161 | default: |
| 182 | return -EINVAL; | 162 | return -EINVAL; |
| @@ -228,6 +208,26 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream, | |||
| 228 | struct rk_i2s_dev *i2s = to_info(dai); | 208 | struct rk_i2s_dev *i2s = to_info(dai); |
| 229 | struct snd_soc_pcm_runtime *rtd = substream->private_data; | 209 | struct snd_soc_pcm_runtime *rtd = substream->private_data; |
| 230 | unsigned int val = 0; | 210 | unsigned int val = 0; |
| 211 | unsigned int mclk_rate, bclk_rate, div_bclk, div_lrck; | ||
| 212 | |||
| 213 | if (i2s->is_master_mode) { | ||
| 214 | mclk_rate = clk_get_rate(i2s->mclk); | ||
| 215 | bclk_rate = 2 * 32 * params_rate(params); | ||
| 216 | if (bclk_rate && mclk_rate % bclk_rate) | ||
| 217 | return -EINVAL; | ||
| 218 | |||
| 219 | div_bclk = mclk_rate / bclk_rate; | ||
| 220 | div_lrck = bclk_rate / params_rate(params); | ||
| 221 | regmap_update_bits(i2s->regmap, I2S_CKR, | ||
| 222 | I2S_CKR_MDIV_MASK, | ||
| 223 | I2S_CKR_MDIV(div_bclk)); | ||
| 224 | |||
| 225 | regmap_update_bits(i2s->regmap, I2S_CKR, | ||
| 226 | I2S_CKR_TSD_MASK | | ||
| 227 | I2S_CKR_RSD_MASK, | ||
| 228 | I2S_CKR_TSD(div_lrck) | | ||
| 229 | I2S_CKR_RSD(div_lrck)); | ||
| 230 | } | ||
| 231 | 231 | ||
| 232 | switch (params_format(params)) { | 232 | switch (params_format(params)) { |
| 233 | case SNDRV_PCM_FORMAT_S8: | 233 | case SNDRV_PCM_FORMAT_S8: |
| @@ -451,6 +451,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev) | |||
| 451 | { | 451 | { |
| 452 | struct device_node *node = pdev->dev.of_node; | 452 | struct device_node *node = pdev->dev.of_node; |
| 453 | struct rk_i2s_dev *i2s; | 453 | struct rk_i2s_dev *i2s; |
| 454 | struct snd_soc_dai_driver *soc_dai; | ||
| 454 | struct resource *res; | 455 | struct resource *res; |
| 455 | void __iomem *regs; | 456 | void __iomem *regs; |
| 456 | int ret; | 457 | int ret; |
| @@ -511,17 +512,26 @@ static int rockchip_i2s_probe(struct platform_device *pdev) | |||
| 511 | goto err_pm_disable; | 512 | goto err_pm_disable; |
| 512 | } | 513 | } |
| 513 | 514 | ||
| 514 | /* refine capture channels */ | 515 | soc_dai = devm_kzalloc(&pdev->dev, |
| 516 | sizeof(*soc_dai), GFP_KERNEL); | ||
| 517 | if (!soc_dai) | ||
| 518 | return -ENOMEM; | ||
| 519 | |||
| 520 | memcpy(soc_dai, &rockchip_i2s_dai, sizeof(*soc_dai)); | ||
| 521 | if (!of_property_read_u32(node, "rockchip,playback-channels", &val)) { | ||
| 522 | if (val >= 2 && val <= 8) | ||
| 523 | soc_dai->playback.channels_max = val; | ||
| 524 | } | ||
| 525 | |||
| 515 | if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { | 526 | if (!of_property_read_u32(node, "rockchip,capture-channels", &val)) { |
| 516 | if (val >= 2 && val <= 8) | 527 | if (val >= 2 && val <= 8) |
| 517 | rockchip_i2s_dai.capture.channels_max = val; | 528 | soc_dai->capture.channels_max = val; |
| 518 | else | ||
| 519 | rockchip_i2s_dai.capture.channels_max = 2; | ||
| 520 | } | 529 | } |
| 521 | 530 | ||
| 522 | ret = devm_snd_soc_register_component(&pdev->dev, | 531 | ret = devm_snd_soc_register_component(&pdev->dev, |
| 523 | &rockchip_i2s_component, | 532 | &rockchip_i2s_component, |
| 524 | &rockchip_i2s_dai, 1); | 533 | soc_dai, 1); |
| 534 | |||
| 525 | if (ret) { | 535 | if (ret) { |
| 526 | dev_err(&pdev->dev, "Could not register DAI\n"); | 536 | dev_err(&pdev->dev, "Could not register DAI\n"); |
| 527 | goto err_suspend; | 537 | goto err_suspend; |
diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c index 26567b10393a..543610282cdb 100644 --- a/sound/soc/rockchip/rockchip_max98090.c +++ b/sound/soc/rockchip/rockchip_max98090.c | |||
| @@ -80,11 +80,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, | |||
| 80 | switch (params_rate(params)) { | 80 | switch (params_rate(params)) { |
| 81 | case 8000: | 81 | case 8000: |
| 82 | case 16000: | 82 | case 16000: |
| 83 | case 24000: | ||
| 84 | case 32000: | ||
| 83 | case 48000: | 85 | case 48000: |
| 86 | case 64000: | ||
| 84 | case 96000: | 87 | case 96000: |
| 85 | mclk = 12288000; | 88 | mclk = 12288000; |
| 86 | break; | 89 | break; |
| 90 | case 11025: | ||
| 91 | case 22050: | ||
| 87 | case 44100: | 92 | case 44100: |
| 93 | case 88200: | ||
| 88 | mclk = 11289600; | 94 | mclk = 11289600; |
| 89 | break; | 95 | break; |
| 90 | default: | 96 | default: |
diff --git a/sound/soc/rockchip/rockchip_rt5645.c b/sound/soc/rockchip/rockchip_rt5645.c index 68c62e4c2316..440a8026346a 100644 --- a/sound/soc/rockchip/rockchip_rt5645.c +++ b/sound/soc/rockchip/rockchip_rt5645.c | |||
| @@ -79,11 +79,17 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream, | |||
| 79 | switch (params_rate(params)) { | 79 | switch (params_rate(params)) { |
| 80 | case 8000: | 80 | case 8000: |
| 81 | case 16000: | 81 | case 16000: |
| 82 | case 24000: | ||
| 83 | case 32000: | ||
| 82 | case 48000: | 84 | case 48000: |
| 85 | case 64000: | ||
| 83 | case 96000: | 86 | case 96000: |
| 84 | mclk = 12288000; | 87 | mclk = 12288000; |
| 85 | break; | 88 | break; |
| 89 | case 11025: | ||
| 90 | case 22050: | ||
| 86 | case 44100: | 91 | case 44100: |
| 92 | case 88200: | ||
| 87 | mclk = 11289600; | 93 | mclk = 11289600; |
| 88 | break; | 94 | break; |
| 89 | default: | 95 | default: |
diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 206d1edab07c..c9902a6d6fa0 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig | |||
| @@ -36,7 +36,6 @@ config SND_SOC_SH4_SIU | |||
| 36 | 36 | ||
| 37 | config SND_SOC_RCAR | 37 | config SND_SOC_RCAR |
| 38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" | 38 | tristate "R-Car series SRU/SCU/SSIU/SSI support" |
| 39 | depends on DMA_OF | ||
| 40 | depends on COMMON_CLK | 39 | depends on COMMON_CLK |
| 41 | select SND_SIMPLE_CARD | 40 | select SND_SIMPLE_CARD |
| 42 | select REGMAP_MMIO | 41 | select REGMAP_MMIO |
diff --git a/sound/soc/sh/rcar/Makefile b/sound/soc/sh/rcar/Makefile index 8b258501aa35..a89ddf758695 100644 --- a/sound/soc/sh/rcar/Makefile +++ b/sound/soc/sh/rcar/Makefile | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o src.o ctu.o mix.o dvc.o | 1 | snd-soc-rcar-objs := core.o gen.o dma.o adg.o ssi.o ssiu.o src.o ctu.o mix.o dvc.o cmd.o |
| 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o | 2 | obj-$(CONFIG_SND_SOC_RCAR) += snd-soc-rcar.o |
| 3 | 3 | ||
| 4 | snd-soc-rsrc-card-objs := rsrc-card.o | 4 | snd-soc-rsrc-card-objs := rsrc-card.o |
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c index 2a5b3a293cd2..6d3ef366d536 100644 --- a/sound/soc/sh/rcar/adg.c +++ b/sound/soc/sh/rcar/adg.c | |||
| @@ -68,8 +68,8 @@ static u32 rsnd_adg_calculate_rbgx(unsigned long div) | |||
| 68 | 68 | ||
| 69 | static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) | 69 | static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) |
| 70 | { | 70 | { |
| 71 | struct rsnd_mod *mod = rsnd_io_to_mod_ssi(io); | 71 | struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); |
| 72 | int id = rsnd_mod_id(mod); | 72 | int id = rsnd_mod_id(ssi_mod); |
| 73 | int ws = id; | 73 | int ws = id; |
| 74 | 74 | ||
| 75 | if (rsnd_ssi_is_pin_sharing(io)) { | 75 | if (rsnd_ssi_is_pin_sharing(io)) { |
| @@ -90,13 +90,13 @@ static u32 rsnd_adg_ssi_ws_timing_gen2(struct rsnd_dai_stream *io) | |||
| 90 | return (0x6 + ws) << 8; | 90 | return (0x6 + ws) << 8; |
| 91 | } | 91 | } |
| 92 | 92 | ||
| 93 | int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, | 93 | int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *cmd_mod, |
| 94 | struct rsnd_dai_stream *io) | 94 | struct rsnd_dai_stream *io) |
| 95 | { | 95 | { |
| 96 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 96 | struct rsnd_priv *priv = rsnd_mod_to_priv(cmd_mod); |
| 97 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 97 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
| 98 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); | 98 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); |
| 99 | int id = rsnd_mod_id(mod); | 99 | int id = rsnd_mod_id(cmd_mod); |
| 100 | int shift = (id % 2) ? 16 : 0; | 100 | int shift = (id % 2) ? 16 : 0; |
| 101 | u32 mask, val; | 101 | u32 mask, val; |
| 102 | 102 | ||
| @@ -242,68 +242,6 @@ int rsnd_adg_set_convert_timing_gen2(struct rsnd_mod *src_mod, | |||
| 242 | return rsnd_adg_set_src_timsel_gen2(src_mod, io, val); | 242 | return rsnd_adg_set_src_timsel_gen2(src_mod, io, val); |
| 243 | } | 243 | } |
| 244 | 244 | ||
| 245 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | ||
| 246 | struct rsnd_mod *mod, | ||
| 247 | unsigned int src_rate, | ||
| 248 | unsigned int dst_rate) | ||
| 249 | { | ||
| 250 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
| 251 | struct rsnd_mod *adg_mod = rsnd_mod_get(adg); | ||
| 252 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 253 | int idx, sel, div, shift; | ||
| 254 | u32 mask, val; | ||
| 255 | int id = rsnd_mod_id(mod); | ||
| 256 | unsigned int sel_rate [] = { | ||
| 257 | clk_get_rate(adg->clk[CLKA]), /* 000: CLKA */ | ||
| 258 | clk_get_rate(adg->clk[CLKB]), /* 001: CLKB */ | ||
| 259 | clk_get_rate(adg->clk[CLKC]), /* 010: CLKC */ | ||
| 260 | 0, /* 011: MLBCLK (not used) */ | ||
| 261 | adg->rbga_rate_for_441khz, /* 100: RBGA */ | ||
| 262 | adg->rbgb_rate_for_48khz, /* 101: RBGB */ | ||
| 263 | }; | ||
| 264 | |||
| 265 | /* find div (= 1/128, 1/256, 1/512, 1/1024, 1/2048 */ | ||
| 266 | for (sel = 0; sel < ARRAY_SIZE(sel_rate); sel++) { | ||
| 267 | for (div = 128, idx = 0; | ||
| 268 | div <= 2048; | ||
| 269 | div *= 2, idx++) { | ||
| 270 | if (src_rate == sel_rate[sel] / div) { | ||
| 271 | val = (idx << 4) | sel; | ||
| 272 | goto find_rate; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | } | ||
| 276 | dev_err(dev, "can't find convert src clk\n"); | ||
| 277 | return -EINVAL; | ||
| 278 | |||
| 279 | find_rate: | ||
| 280 | shift = (id % 4) * 8; | ||
| 281 | mask = 0xFF << shift; | ||
| 282 | val = val << shift; | ||
| 283 | |||
| 284 | dev_dbg(dev, "adg convert src clk = %02x\n", val); | ||
| 285 | |||
| 286 | switch (id / 4) { | ||
| 287 | case 0: | ||
| 288 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL3, mask, val); | ||
| 289 | break; | ||
| 290 | case 1: | ||
| 291 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL4, mask, val); | ||
| 292 | break; | ||
| 293 | case 2: | ||
| 294 | rsnd_mod_bset(adg_mod, AUDIO_CLK_SEL5, mask, val); | ||
| 295 | break; | ||
| 296 | } | ||
| 297 | |||
| 298 | /* | ||
| 299 | * Gen1 doesn't need dst_rate settings, | ||
| 300 | * since it uses SSI WS pin. | ||
| 301 | * see also rsnd_src_set_route_if_gen1() | ||
| 302 | */ | ||
| 303 | |||
| 304 | return 0; | ||
| 305 | } | ||
| 306 | |||
| 307 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) | 245 | static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) |
| 308 | { | 246 | { |
| 309 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | 247 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); |
| @@ -337,20 +275,16 @@ static void rsnd_adg_set_ssi_clk(struct rsnd_mod *ssi_mod, u32 val) | |||
| 337 | } | 275 | } |
| 338 | } | 276 | } |
| 339 | 277 | ||
| 340 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod) | 278 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *ssi_mod) |
| 341 | { | 279 | { |
| 342 | /* | 280 | rsnd_adg_set_ssi_clk(ssi_mod, 0); |
| 343 | * "mod" = "ssi" here. | ||
| 344 | * we can get "ssi id" from mod | ||
| 345 | */ | ||
| 346 | rsnd_adg_set_ssi_clk(mod, 0); | ||
| 347 | 281 | ||
| 348 | return 0; | 282 | return 0; |
| 349 | } | 283 | } |
| 350 | 284 | ||
| 351 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) | 285 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *ssi_mod, unsigned int rate) |
| 352 | { | 286 | { |
| 353 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 287 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); |
| 354 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | 288 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); |
| 355 | struct device *dev = rsnd_priv_to_dev(priv); | 289 | struct device *dev = rsnd_priv_to_dev(priv); |
| 356 | struct clk *clk; | 290 | struct clk *clk; |
| @@ -394,14 +328,10 @@ int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate) | |||
| 394 | 328 | ||
| 395 | found_clock: | 329 | found_clock: |
| 396 | 330 | ||
| 397 | /* | 331 | rsnd_adg_set_ssi_clk(ssi_mod, data); |
| 398 | * This "mod" = "ssi" here. | ||
| 399 | * we can get "ssi id" from mod | ||
| 400 | */ | ||
| 401 | rsnd_adg_set_ssi_clk(mod, data); | ||
| 402 | 332 | ||
| 403 | dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", | 333 | dev_dbg(dev, "ADG: %s[%d] selects 0x%x for %d\n", |
| 404 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 334 | rsnd_mod_name(ssi_mod), rsnd_mod_id(ssi_mod), |
| 405 | data, rate); | 335 | data, rate); |
| 406 | 336 | ||
| 407 | return 0; | 337 | return 0; |
| @@ -418,15 +348,20 @@ static void rsnd_adg_get_clkin(struct rsnd_priv *priv, | |||
| 418 | [CLKC] = "clk_c", | 348 | [CLKC] = "clk_c", |
| 419 | [CLKI] = "clk_i", | 349 | [CLKI] = "clk_i", |
| 420 | }; | 350 | }; |
| 421 | int i; | 351 | int i, ret; |
| 422 | 352 | ||
| 423 | for (i = 0; i < CLKMAX; i++) { | 353 | for (i = 0; i < CLKMAX; i++) { |
| 424 | clk = devm_clk_get(dev, clk_name[i]); | 354 | clk = devm_clk_get(dev, clk_name[i]); |
| 425 | adg->clk[i] = IS_ERR(clk) ? NULL : clk; | 355 | adg->clk[i] = IS_ERR(clk) ? NULL : clk; |
| 426 | } | 356 | } |
| 427 | 357 | ||
| 428 | for_each_rsnd_clk(clk, adg, i) | 358 | for_each_rsnd_clk(clk, adg, i) { |
| 359 | ret = clk_prepare_enable(clk); | ||
| 360 | if (ret < 0) | ||
| 361 | dev_warn(dev, "can't use clk %d\n", i); | ||
| 362 | |||
| 429 | dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); | 363 | dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk)); |
| 364 | } | ||
| 430 | } | 365 | } |
| 431 | 366 | ||
| 432 | static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | 367 | static void rsnd_adg_get_clkout(struct rsnd_priv *priv, |
| @@ -437,7 +372,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
| 437 | struct device *dev = rsnd_priv_to_dev(priv); | 372 | struct device *dev = rsnd_priv_to_dev(priv); |
| 438 | struct device_node *np = dev->of_node; | 373 | struct device_node *np = dev->of_node; |
| 439 | u32 ckr, rbgx, rbga, rbgb; | 374 | u32 ckr, rbgx, rbga, rbgb; |
| 440 | u32 rate, req_rate, div; | 375 | u32 rate, req_rate = 0, div; |
| 441 | uint32_t count = 0; | 376 | uint32_t count = 0; |
| 442 | unsigned long req_48kHz_rate, req_441kHz_rate; | 377 | unsigned long req_48kHz_rate, req_441kHz_rate; |
| 443 | int i; | 378 | int i; |
| @@ -572,9 +507,7 @@ static void rsnd_adg_get_clkout(struct rsnd_priv *priv, | |||
| 572 | ckr, rbga, rbgb); | 507 | ckr, rbga, rbgb); |
| 573 | } | 508 | } |
| 574 | 509 | ||
| 575 | int rsnd_adg_probe(struct platform_device *pdev, | 510 | int rsnd_adg_probe(struct rsnd_priv *priv) |
| 576 | const struct rsnd_of_data *of_data, | ||
| 577 | struct rsnd_priv *priv) | ||
| 578 | { | 511 | { |
| 579 | struct rsnd_adg *adg; | 512 | struct rsnd_adg *adg; |
| 580 | struct device *dev = rsnd_priv_to_dev(priv); | 513 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -600,3 +533,14 @@ int rsnd_adg_probe(struct platform_device *pdev, | |||
| 600 | 533 | ||
| 601 | return 0; | 534 | return 0; |
| 602 | } | 535 | } |
| 536 | |||
| 537 | void rsnd_adg_remove(struct rsnd_priv *priv) | ||
| 538 | { | ||
| 539 | struct rsnd_adg *adg = rsnd_priv_to_adg(priv); | ||
| 540 | struct clk *clk; | ||
| 541 | int i; | ||
| 542 | |||
| 543 | for_each_rsnd_clk(clk, adg, i) { | ||
| 544 | clk_disable_unprepare(clk); | ||
| 545 | } | ||
| 546 | } | ||
diff --git a/sound/soc/sh/rcar/cmd.c b/sound/soc/sh/rcar/cmd.c new file mode 100644 index 000000000000..cd1f064e63c4 --- /dev/null +++ b/sound/soc/sh/rcar/cmd.c | |||
| @@ -0,0 +1,171 @@ | |||
| 1 | /* | ||
| 2 | * Renesas R-Car CMD support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2015 Renesas Solutions Corp. | ||
| 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | #include "rsnd.h" | ||
| 12 | |||
| 13 | struct rsnd_cmd { | ||
| 14 | struct rsnd_mod mod; | ||
| 15 | }; | ||
| 16 | |||
| 17 | #define CMD_NAME "cmd" | ||
| 18 | |||
| 19 | #define rsnd_cmd_nr(priv) ((priv)->cmd_nr) | ||
| 20 | #define for_each_rsnd_cmd(pos, priv, i) \ | ||
| 21 | for ((i) = 0; \ | ||
| 22 | ((i) < rsnd_cmd_nr(priv)) && \ | ||
| 23 | ((pos) = (struct rsnd_cmd *)(priv)->cmd + i); \ | ||
| 24 | i++) | ||
| 25 | |||
| 26 | static int rsnd_cmd_init(struct rsnd_mod *mod, | ||
| 27 | struct rsnd_dai_stream *io, | ||
| 28 | struct rsnd_priv *priv) | ||
| 29 | { | ||
| 30 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | ||
| 31 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); | ||
| 32 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | ||
| 33 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 34 | u32 data; | ||
| 35 | |||
| 36 | if (!mix && !dvc) | ||
| 37 | return 0; | ||
| 38 | |||
| 39 | if (mix) { | ||
| 40 | struct rsnd_dai *rdai; | ||
| 41 | int i; | ||
| 42 | u32 path[] = { | ||
| 43 | [0] = 0, | ||
| 44 | [1] = 1 << 0, | ||
| 45 | [2] = 0, | ||
| 46 | [3] = 0, | ||
| 47 | [4] = 0, | ||
| 48 | [5] = 1 << 8 | ||
| 49 | }; | ||
| 50 | |||
| 51 | /* | ||
| 52 | * it is assuming that integrater is well understanding about | ||
| 53 | * data path. Here doesn't check impossible connection, | ||
| 54 | * like src2 + src5 | ||
| 55 | */ | ||
| 56 | data = 0; | ||
| 57 | for_each_rsnd_dai(rdai, priv, i) { | ||
| 58 | io = &rdai->playback; | ||
| 59 | if (mix == rsnd_io_to_mod_mix(io)) | ||
| 60 | data |= path[rsnd_mod_id(src)]; | ||
| 61 | |||
| 62 | io = &rdai->capture; | ||
| 63 | if (mix == rsnd_io_to_mod_mix(io)) | ||
| 64 | data |= path[rsnd_mod_id(src)]; | ||
| 65 | } | ||
| 66 | |||
| 67 | } else { | ||
| 68 | u32 path[] = { | ||
| 69 | [0] = 0x30000, | ||
| 70 | [1] = 0x30001, | ||
| 71 | [2] = 0x40000, | ||
| 72 | [3] = 0x10000, | ||
| 73 | [4] = 0x20000, | ||
| 74 | [5] = 0x40100 | ||
| 75 | }; | ||
| 76 | |||
| 77 | data = path[rsnd_mod_id(src)]; | ||
| 78 | } | ||
| 79 | |||
| 80 | dev_dbg(dev, "ctu/mix path = 0x%08x", data); | ||
| 81 | |||
| 82 | rsnd_mod_write(mod, CMD_ROUTE_SLCT, data); | ||
| 83 | rsnd_mod_write(mod, CMD_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); | ||
| 84 | |||
| 85 | rsnd_adg_set_cmd_timsel_gen2(mod, io); | ||
| 86 | |||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 90 | static int rsnd_cmd_start(struct rsnd_mod *mod, | ||
| 91 | struct rsnd_dai_stream *io, | ||
| 92 | struct rsnd_priv *priv) | ||
| 93 | { | ||
| 94 | rsnd_mod_write(mod, CMD_CTRL, 0x10); | ||
| 95 | |||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | static int rsnd_cmd_stop(struct rsnd_mod *mod, | ||
| 100 | struct rsnd_dai_stream *io, | ||
| 101 | struct rsnd_priv *priv) | ||
| 102 | { | ||
| 103 | rsnd_mod_write(mod, CMD_CTRL, 0); | ||
| 104 | |||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct rsnd_mod_ops rsnd_cmd_ops = { | ||
| 109 | .name = CMD_NAME, | ||
| 110 | .init = rsnd_cmd_init, | ||
| 111 | .start = rsnd_cmd_start, | ||
| 112 | .stop = rsnd_cmd_stop, | ||
| 113 | }; | ||
| 114 | |||
| 115 | int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id) | ||
| 116 | { | ||
| 117 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
| 118 | struct rsnd_mod *mod = rsnd_cmd_mod_get(priv, id); | ||
| 119 | |||
| 120 | return rsnd_dai_connect(mod, io, mod->type); | ||
| 121 | } | ||
| 122 | |||
| 123 | struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id) | ||
| 124 | { | ||
| 125 | if (WARN_ON(id < 0 || id >= rsnd_cmd_nr(priv))) | ||
| 126 | id = 0; | ||
| 127 | |||
| 128 | return rsnd_mod_get((struct rsnd_cmd *)(priv->cmd) + id); | ||
| 129 | } | ||
| 130 | |||
| 131 | int rsnd_cmd_probe(struct rsnd_priv *priv) | ||
| 132 | { | ||
| 133 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 134 | struct rsnd_cmd *cmd; | ||
| 135 | int i, nr, ret; | ||
| 136 | |||
| 137 | /* This driver doesn't support Gen1 at this point */ | ||
| 138 | if (rsnd_is_gen1(priv)) | ||
| 139 | return 0; | ||
| 140 | |||
| 141 | /* same number as DVC */ | ||
| 142 | nr = priv->dvc_nr; | ||
| 143 | if (!nr) | ||
| 144 | return 0; | ||
| 145 | |||
| 146 | cmd = devm_kzalloc(dev, sizeof(*cmd) * nr, GFP_KERNEL); | ||
| 147 | if (!cmd) | ||
| 148 | return -ENOMEM; | ||
| 149 | |||
| 150 | priv->cmd_nr = nr; | ||
| 151 | priv->cmd = cmd; | ||
| 152 | |||
| 153 | for_each_rsnd_cmd(cmd, priv, i) { | ||
| 154 | ret = rsnd_mod_init(priv, rsnd_mod_get(cmd), | ||
| 155 | &rsnd_cmd_ops, NULL, RSND_MOD_CMD, i); | ||
| 156 | if (ret) | ||
| 157 | return ret; | ||
| 158 | } | ||
| 159 | |||
| 160 | return 0; | ||
| 161 | } | ||
| 162 | |||
| 163 | void rsnd_cmd_remove(struct rsnd_priv *priv) | ||
| 164 | { | ||
| 165 | struct rsnd_cmd *cmd; | ||
| 166 | int i; | ||
| 167 | |||
| 168 | for_each_rsnd_cmd(cmd, priv, i) { | ||
| 169 | rsnd_mod_quit(rsnd_mod_get(cmd)); | ||
| 170 | } | ||
| 171 | } | ||
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index e1da5654fa25..02b4b085b8d7 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c | |||
| @@ -99,34 +99,17 @@ | |||
| 99 | #define RSND_RATES SNDRV_PCM_RATE_8000_96000 | 99 | #define RSND_RATES SNDRV_PCM_RATE_8000_96000 |
| 100 | #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) | 100 | #define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE) |
| 101 | 101 | ||
| 102 | static const struct rsnd_of_data rsnd_of_data_gen1 = { | ||
| 103 | .flags = RSND_GEN1, | ||
| 104 | }; | ||
| 105 | |||
| 106 | static const struct rsnd_of_data rsnd_of_data_gen2 = { | ||
| 107 | .flags = RSND_GEN2, | ||
| 108 | }; | ||
| 109 | |||
| 110 | static const struct of_device_id rsnd_of_match[] = { | 102 | static const struct of_device_id rsnd_of_match[] = { |
| 111 | { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 }, | 103 | { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 }, |
| 112 | { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 }, | 104 | { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 }, |
| 113 | { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */ | 105 | { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */ |
| 114 | {}, | 106 | {}, |
| 115 | }; | 107 | }; |
| 116 | MODULE_DEVICE_TABLE(of, rsnd_of_match); | 108 | MODULE_DEVICE_TABLE(of, rsnd_of_match); |
| 117 | 109 | ||
| 118 | /* | 110 | /* |
| 119 | * rsnd_platform functions | 111 | * rsnd_mod functions |
| 120 | */ | 112 | */ |
| 121 | #define rsnd_platform_call(priv, dai, func, param...) \ | ||
| 122 | (!(priv->info->func) ? 0 : \ | ||
| 123 | priv->info->func(param)) | ||
| 124 | |||
| 125 | #define rsnd_is_enable_path(io, name) \ | ||
| 126 | ((io)->info ? (io)->info->name : NULL) | ||
| 127 | #define rsnd_info_id(priv, io, name) \ | ||
| 128 | ((io)->info->name - priv->info->name##_info) | ||
| 129 | |||
| 130 | void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) | 113 | void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) |
| 131 | { | 114 | { |
| 132 | if (mod->type != type) { | 115 | if (mod->type != type) { |
| @@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type) | |||
| 138 | } | 121 | } |
| 139 | } | 122 | } |
| 140 | 123 | ||
| 141 | /* | ||
| 142 | * rsnd_mod functions | ||
| 143 | */ | ||
| 144 | char *rsnd_mod_name(struct rsnd_mod *mod) | 124 | char *rsnd_mod_name(struct rsnd_mod *mod) |
| 145 | { | 125 | { |
| 146 | if (!mod || !mod->ops) | 126 | if (!mod || !mod->ops) |
| @@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod, | |||
| 192 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 172 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 193 | struct rsnd_dai_stream *io; | 173 | struct rsnd_dai_stream *io; |
| 194 | struct rsnd_dai *rdai; | 174 | struct rsnd_dai *rdai; |
| 195 | int i, j; | 175 | int i; |
| 196 | |||
| 197 | for_each_rsnd_dai(rdai, priv, j) { | ||
| 198 | 176 | ||
| 199 | for (i = 0; i < RSND_MOD_MAX; i++) { | 177 | for_each_rsnd_dai(rdai, priv, i) { |
| 200 | io = &rdai->playback; | 178 | io = &rdai->playback; |
| 201 | if (mod == io->mod[i]) | 179 | if (mod == io->mod[mod->type]) |
| 202 | callback(mod, io); | 180 | callback(mod, io); |
| 203 | 181 | ||
| 204 | io = &rdai->capture; | 182 | io = &rdai->capture; |
| 205 | if (mod == io->mod[i]) | 183 | if (mod == io->mod[mod->type]) |
| 206 | callback(mod, io); | 184 | callback(mod, io); |
| 207 | } | ||
| 208 | } | 185 | } |
| 209 | } | 186 | } |
| 210 | 187 | ||
| @@ -214,6 +191,43 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io) | |||
| 214 | return !!io->substream; | 191 | return !!io->substream; |
| 215 | } | 192 | } |
| 216 | 193 | ||
| 194 | void rsnd_set_slot(struct rsnd_dai *rdai, | ||
| 195 | int slots, int num) | ||
| 196 | { | ||
| 197 | rdai->slots = slots; | ||
| 198 | rdai->slots_num = num; | ||
| 199 | } | ||
| 200 | |||
| 201 | int rsnd_get_slot(struct rsnd_dai_stream *io) | ||
| 202 | { | ||
| 203 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 204 | |||
| 205 | return rdai->slots; | ||
| 206 | } | ||
| 207 | |||
| 208 | int rsnd_get_slot_num(struct rsnd_dai_stream *io) | ||
| 209 | { | ||
| 210 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 211 | |||
| 212 | return rdai->slots_num; | ||
| 213 | } | ||
| 214 | |||
| 215 | int rsnd_get_slot_width(struct rsnd_dai_stream *io) | ||
| 216 | { | ||
| 217 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 218 | int chan = runtime->channels; | ||
| 219 | |||
| 220 | /* Multi channel Mode */ | ||
| 221 | if (rsnd_ssi_multi_slaves(io)) | ||
| 222 | chan /= rsnd_get_slot_num(io); | ||
| 223 | |||
| 224 | /* TDM Extend Mode needs 8ch */ | ||
| 225 | if (chan == 6) | ||
| 226 | chan = 8; | ||
| 227 | |||
| 228 | return chan; | ||
| 229 | } | ||
| 230 | |||
| 217 | /* | 231 | /* |
| 218 | * ADINR function | 232 | * ADINR function |
| 219 | */ | 233 | */ |
| @@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
| 222 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 236 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 223 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 237 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| 224 | struct device *dev = rsnd_priv_to_dev(priv); | 238 | struct device *dev = rsnd_priv_to_dev(priv); |
| 225 | u32 adinr = runtime->channels; | ||
| 226 | 239 | ||
| 227 | switch (runtime->sample_bits) { | 240 | switch (runtime->sample_bits) { |
| 228 | case 16: | 241 | case 16: |
| 229 | adinr |= (8 << 16); | 242 | return 8 << 16; |
| 230 | break; | ||
| 231 | case 32: | 243 | case 32: |
| 232 | adinr |= (0 << 16); | 244 | return 0 << 16; |
| 233 | break; | ||
| 234 | default: | ||
| 235 | dev_warn(dev, "not supported sample bits\n"); | ||
| 236 | return 0; | ||
| 237 | } | 245 | } |
| 238 | 246 | ||
| 239 | return adinr; | 247 | dev_warn(dev, "not supported sample bits\n"); |
| 248 | |||
| 249 | return 0; | ||
| 240 | } | 250 | } |
| 241 | 251 | ||
| 242 | u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | 252 | u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) |
| @@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
| 267 | */ | 277 | */ |
| 268 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | 278 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) |
| 269 | { | 279 | { |
| 270 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | ||
| 271 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 280 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); |
| 272 | struct rsnd_mod *target = src ? src : ssi; | 281 | struct rsnd_mod *target; |
| 273 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 282 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| 274 | u32 val = 0x76543210; | 283 | u32 val = 0x76543210; |
| 275 | u32 mask = ~0; | 284 | u32 mask = ~0; |
| 276 | 285 | ||
| 286 | if (rsnd_io_is_play(io)) { | ||
| 287 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | ||
| 288 | |||
| 289 | target = src ? src : ssi; | ||
| 290 | } else { | ||
| 291 | struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); | ||
| 292 | |||
| 293 | target = cmd ? cmd : ssi; | ||
| 294 | } | ||
| 295 | |||
| 277 | mask <<= runtime->channels * 4; | 296 | mask <<= runtime->channels * 4; |
| 278 | val = val & mask; | 297 | val = val & mask; |
| 279 | 298 | ||
| @@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
| 300 | /* | 319 | /* |
| 301 | * rsnd_dai functions | 320 | * rsnd_dai functions |
| 302 | */ | 321 | */ |
| 303 | #define rsnd_mod_call(mod, io, func, param...) \ | 322 | #define rsnd_mod_call(idx, io, func, param...) \ |
| 304 | ({ \ | 323 | ({ \ |
| 305 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ | 324 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \ |
| 325 | struct rsnd_mod *mod = (io)->mod[idx]; \ | ||
| 306 | struct device *dev = rsnd_priv_to_dev(priv); \ | 326 | struct device *dev = rsnd_priv_to_dev(priv); \ |
| 327 | u32 *status = (io)->mod_status + idx; \ | ||
| 307 | u32 mask = 0xF << __rsnd_mod_shift_##func; \ | 328 | u32 mask = 0xF << __rsnd_mod_shift_##func; \ |
| 308 | u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \ | 329 | u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \ |
| 309 | u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ | 330 | u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \ |
| 310 | int ret = 0; \ | 331 | int ret = 0; \ |
| 311 | int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ | 332 | int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \ |
| 312 | mod->status = (mod->status & ~mask) + \ | 333 | *status = (*status & ~mask) + \ |
| 313 | (add << __rsnd_mod_shift_##func); \ | 334 | (add << __rsnd_mod_shift_##func); \ |
| 314 | dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ | 335 | dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ |
| 315 | rsnd_mod_name(mod), rsnd_mod_id(mod), \ | 336 | rsnd_mod_name(mod), rsnd_mod_id(mod), \ |
| 316 | mod->status, call ? #func : ""); \ | 337 | *status, call ? #func : ""); \ |
| 317 | if (call) \ | 338 | if (call) \ |
| 318 | ret = (mod)->ops->func(mod, io, param); \ | 339 | ret = (mod)->ops->func(mod, io, param); \ |
| 319 | ret; \ | 340 | ret; \ |
| @@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) | |||
| 327 | mod = (io)->mod[i]; \ | 348 | mod = (io)->mod[i]; \ |
| 328 | if (!mod) \ | 349 | if (!mod) \ |
| 329 | continue; \ | 350 | continue; \ |
| 330 | ret |= rsnd_mod_call(mod, io, fn, param); \ | 351 | ret |= rsnd_mod_call(i, io, fn, param); \ |
| 331 | } \ | 352 | } \ |
| 332 | ret; \ | 353 | ret; \ |
| 333 | }) | 354 | }) |
| 334 | 355 | ||
| 335 | static int rsnd_dai_connect(struct rsnd_mod *mod, | 356 | int rsnd_dai_connect(struct rsnd_mod *mod, |
| 336 | struct rsnd_dai_stream *io) | 357 | struct rsnd_dai_stream *io, |
| 358 | enum rsnd_mod_type type) | ||
| 337 | { | 359 | { |
| 338 | struct rsnd_priv *priv; | 360 | struct rsnd_priv *priv; |
| 339 | struct device *dev; | 361 | struct device *dev; |
| @@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
| 341 | if (!mod) | 363 | if (!mod) |
| 342 | return -EIO; | 364 | return -EIO; |
| 343 | 365 | ||
| 366 | if (io->mod[type]) | ||
| 367 | return -EINVAL; | ||
| 368 | |||
| 344 | priv = rsnd_mod_to_priv(mod); | 369 | priv = rsnd_mod_to_priv(mod); |
| 345 | dev = rsnd_priv_to_dev(priv); | 370 | dev = rsnd_priv_to_dev(priv); |
| 346 | 371 | ||
| 347 | io->mod[mod->type] = mod; | 372 | io->mod[type] = mod; |
| 348 | 373 | ||
| 349 | dev_dbg(dev, "%s[%d] is connected to io (%s)\n", | 374 | dev_dbg(dev, "%s[%d] is connected to io (%s)\n", |
| 350 | rsnd_mod_name(mod), rsnd_mod_id(mod), | 375 | rsnd_mod_name(mod), rsnd_mod_id(mod), |
| @@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod, | |||
| 354 | } | 379 | } |
| 355 | 380 | ||
| 356 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, | 381 | static void rsnd_dai_disconnect(struct rsnd_mod *mod, |
| 357 | struct rsnd_dai_stream *io) | 382 | struct rsnd_dai_stream *io, |
| 383 | enum rsnd_mod_type type) | ||
| 358 | { | 384 | { |
| 359 | io->mod[mod->type] = NULL; | 385 | io->mod[type] = NULL; |
| 360 | } | 386 | } |
| 361 | 387 | ||
| 362 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) | 388 | struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) |
| @@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 469 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); | 495 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
| 470 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); | 496 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
| 471 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); | 497 | struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream); |
| 472 | int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io)); | ||
| 473 | int ret; | 498 | int ret; |
| 474 | unsigned long flags; | 499 | unsigned long flags; |
| 475 | 500 | ||
| @@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 479 | case SNDRV_PCM_TRIGGER_START: | 504 | case SNDRV_PCM_TRIGGER_START: |
| 480 | rsnd_dai_stream_init(io, substream); | 505 | rsnd_dai_stream_init(io, substream); |
| 481 | 506 | ||
| 482 | ret = rsnd_platform_call(priv, dai, start, ssi_id); | ||
| 483 | if (ret < 0) | ||
| 484 | goto dai_trigger_end; | ||
| 485 | |||
| 486 | ret = rsnd_dai_call(init, io, priv); | 507 | ret = rsnd_dai_call(init, io, priv); |
| 487 | if (ret < 0) | 508 | if (ret < 0) |
| 488 | goto dai_trigger_end; | 509 | goto dai_trigger_end; |
| @@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd, | |||
| 496 | 517 | ||
| 497 | ret |= rsnd_dai_call(quit, io, priv); | 518 | ret |= rsnd_dai_call(quit, io, priv); |
| 498 | 519 | ||
| 499 | ret |= rsnd_platform_call(priv, dai, stop, ssi_id); | ||
| 500 | |||
| 501 | rsnd_dai_stream_quit(io); | 520 | rsnd_dai_stream_quit(io); |
| 502 | break; | 521 | break; |
| 503 | default: | 522 | default: |
| @@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) | |||
| 567 | return 0; | 586 | return 0; |
| 568 | } | 587 | } |
| 569 | 588 | ||
| 570 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { | 589 | static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, |
| 571 | .trigger = rsnd_soc_dai_trigger, | 590 | u32 tx_mask, u32 rx_mask, |
| 572 | .set_fmt = rsnd_soc_dai_set_fmt, | 591 | int slots, int slot_width) |
| 573 | }; | ||
| 574 | |||
| 575 | #define rsnd_path_add(priv, io, type) \ | ||
| 576 | ({ \ | ||
| 577 | struct rsnd_mod *mod; \ | ||
| 578 | int ret = 0; \ | ||
| 579 | int id = -1; \ | ||
| 580 | \ | ||
| 581 | if (rsnd_is_enable_path(io, type)) { \ | ||
| 582 | id = rsnd_info_id(priv, io, type); \ | ||
| 583 | if (id >= 0) { \ | ||
| 584 | mod = rsnd_##type##_mod_get(priv, id); \ | ||
| 585 | ret = rsnd_dai_connect(mod, io); \ | ||
| 586 | } \ | ||
| 587 | } \ | ||
| 588 | ret; \ | ||
| 589 | }) | ||
| 590 | |||
| 591 | #define rsnd_path_remove(priv, io, type) \ | ||
| 592 | { \ | ||
| 593 | struct rsnd_mod *mod; \ | ||
| 594 | int id = -1; \ | ||
| 595 | \ | ||
| 596 | if (rsnd_is_enable_path(io, type)) { \ | ||
| 597 | id = rsnd_info_id(priv, io, type); \ | ||
| 598 | if (id >= 0) { \ | ||
| 599 | mod = rsnd_##type##_mod_get(priv, id); \ | ||
| 600 | rsnd_dai_disconnect(mod, io); \ | ||
| 601 | } \ | ||
| 602 | } \ | ||
| 603 | } | ||
| 604 | |||
| 605 | void rsnd_path_parse(struct rsnd_priv *priv, | ||
| 606 | struct rsnd_dai_stream *io) | ||
| 607 | { | 592 | { |
| 608 | struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io); | 593 | struct rsnd_priv *priv = rsnd_dai_to_priv(dai); |
| 609 | struct rsnd_mod *mix = rsnd_io_to_mod_mix(io); | 594 | struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); |
| 610 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | ||
| 611 | struct rsnd_mod *cmd; | ||
| 612 | struct device *dev = rsnd_priv_to_dev(priv); | 595 | struct device *dev = rsnd_priv_to_dev(priv); |
| 613 | u32 data; | ||
| 614 | 596 | ||
| 615 | /* Gen1 is not supported */ | 597 | switch (slots) { |
| 616 | if (rsnd_is_gen1(priv)) | 598 | case 6: |
| 617 | return; | 599 | /* TDM Extend Mode */ |
| 618 | 600 | rsnd_set_slot(rdai, slots, 1); | |
| 619 | if (!mix && !dvc) | 601 | break; |
| 620 | return; | 602 | default: |
| 621 | 603 | dev_err(dev, "unsupported TDM slots (%d)\n", slots); | |
| 622 | if (mix) { | 604 | return -EINVAL; |
| 623 | struct rsnd_dai *rdai; | ||
| 624 | int i; | ||
| 625 | u32 path[] = { | ||
| 626 | [0] = 0, | ||
| 627 | [1] = 1 << 0, | ||
| 628 | [2] = 0, | ||
| 629 | [3] = 0, | ||
| 630 | [4] = 0, | ||
| 631 | [5] = 1 << 8 | ||
| 632 | }; | ||
| 633 | |||
| 634 | /* | ||
| 635 | * it is assuming that integrater is well understanding about | ||
| 636 | * data path. Here doesn't check impossible connection, | ||
| 637 | * like src2 + src5 | ||
| 638 | */ | ||
| 639 | data = 0; | ||
| 640 | for_each_rsnd_dai(rdai, priv, i) { | ||
| 641 | io = &rdai->playback; | ||
| 642 | if (mix == rsnd_io_to_mod_mix(io)) | ||
| 643 | data |= path[rsnd_mod_id(src)]; | ||
| 644 | |||
| 645 | io = &rdai->capture; | ||
| 646 | if (mix == rsnd_io_to_mod_mix(io)) | ||
| 647 | data |= path[rsnd_mod_id(src)]; | ||
| 648 | } | ||
| 649 | |||
| 650 | /* | ||
| 651 | * We can't use ctu = rsnd_io_ctu() here. | ||
| 652 | * Since, ID of dvc/mix are 0 or 1 (= same as CMD number) | ||
| 653 | * but ctu IDs are 0 - 7 (= CTU00 - CTU13) | ||
| 654 | */ | ||
| 655 | cmd = mix; | ||
| 656 | } else { | ||
| 657 | u32 path[] = { | ||
| 658 | [0] = 0x30000, | ||
| 659 | [1] = 0x30001, | ||
| 660 | [2] = 0x40000, | ||
| 661 | [3] = 0x10000, | ||
| 662 | [4] = 0x20000, | ||
| 663 | [5] = 0x40100 | ||
| 664 | }; | ||
| 665 | |||
| 666 | data = path[rsnd_mod_id(src)]; | ||
| 667 | |||
| 668 | cmd = dvc; | ||
| 669 | } | 605 | } |
| 670 | 606 | ||
| 671 | dev_dbg(dev, "ctu/mix path = 0x%08x", data); | 607 | return 0; |
| 672 | |||
| 673 | rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data); | ||
| 674 | |||
| 675 | rsnd_mod_write(cmd, CMD_CTRL, 0x10); | ||
| 676 | } | 608 | } |
| 677 | 609 | ||
| 678 | static int rsnd_path_init(struct rsnd_priv *priv, | 610 | static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { |
| 679 | struct rsnd_dai *rdai, | 611 | .trigger = rsnd_soc_dai_trigger, |
| 680 | struct rsnd_dai_stream *io) | 612 | .set_fmt = rsnd_soc_dai_set_fmt, |
| 681 | { | 613 | .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, |
| 682 | int ret; | 614 | }; |
| 683 | |||
| 684 | /* | ||
| 685 | * Gen1 is created by SRU/SSI, and this SRU is base module of | ||
| 686 | * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU) | ||
| 687 | * | ||
| 688 | * Easy image is.. | ||
| 689 | * Gen1 SRU = Gen2 SCU + SSIU + etc | ||
| 690 | * | ||
| 691 | * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is | ||
| 692 | * using fixed path. | ||
| 693 | */ | ||
| 694 | |||
| 695 | /* SSI */ | ||
| 696 | ret = rsnd_path_add(priv, io, ssi); | ||
| 697 | if (ret < 0) | ||
| 698 | return ret; | ||
| 699 | |||
| 700 | /* SRC */ | ||
| 701 | ret = rsnd_path_add(priv, io, src); | ||
| 702 | if (ret < 0) | ||
| 703 | return ret; | ||
| 704 | 615 | ||
| 705 | /* CTU */ | 616 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, |
| 706 | ret = rsnd_path_add(priv, io, ctu); | 617 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), |
| 707 | if (ret < 0) | 618 | struct device_node *node, |
| 708 | return ret; | 619 | struct device_node *playback, |
| 620 | struct device_node *capture) | ||
| 621 | { | ||
| 622 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
| 623 | struct device_node *np; | ||
| 624 | struct rsnd_mod *mod; | ||
| 625 | int i; | ||
| 709 | 626 | ||
| 710 | /* MIX */ | 627 | if (!node) |
| 711 | ret = rsnd_path_add(priv, io, mix); | 628 | return; |
| 712 | if (ret < 0) | ||
| 713 | return ret; | ||
| 714 | 629 | ||
| 715 | /* DVC */ | 630 | i = 0; |
| 716 | ret = rsnd_path_add(priv, io, dvc); | 631 | for_each_child_of_node(node, np) { |
| 717 | if (ret < 0) | 632 | mod = mod_get(priv, i); |
| 718 | return ret; | 633 | if (np == playback) |
| 634 | rsnd_dai_connect(mod, &rdai->playback, mod->type); | ||
| 635 | if (np == capture) | ||
| 636 | rsnd_dai_connect(mod, &rdai->capture, mod->type); | ||
| 637 | i++; | ||
| 638 | } | ||
| 719 | 639 | ||
| 720 | return ret; | 640 | of_node_put(node); |
| 721 | } | 641 | } |
| 722 | 642 | ||
| 723 | static void rsnd_of_parse_dai(struct platform_device *pdev, | 643 | static int rsnd_dai_probe(struct rsnd_priv *priv) |
| 724 | const struct rsnd_of_data *of_data, | ||
| 725 | struct rsnd_priv *priv) | ||
| 726 | { | 644 | { |
| 727 | struct device_node *dai_node, *dai_np; | 645 | struct device_node *dai_node; |
| 728 | struct device_node *ssi_node, *ssi_np; | 646 | struct device_node *dai_np; |
| 729 | struct device_node *src_node, *src_np; | ||
| 730 | struct device_node *ctu_node, *ctu_np; | ||
| 731 | struct device_node *mix_node, *mix_np; | ||
| 732 | struct device_node *dvc_node, *dvc_np; | ||
| 733 | struct device_node *playback, *capture; | 647 | struct device_node *playback, *capture; |
| 734 | struct rsnd_dai_platform_info *dai_info; | 648 | struct rsnd_dai_stream *io_playback; |
| 735 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | 649 | struct rsnd_dai_stream *io_capture; |
| 736 | struct device *dev = &pdev->dev; | 650 | struct snd_soc_dai_driver *rdrv, *drv; |
| 737 | int nr, i; | 651 | struct rsnd_dai *rdai; |
| 738 | int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i; | 652 | struct device *dev = rsnd_priv_to_dev(priv); |
| 739 | 653 | int nr, dai_i, io_i; | |
| 740 | if (!of_data) | 654 | int ret; |
| 741 | return; | ||
| 742 | |||
| 743 | dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai"); | ||
| 744 | if (!dai_node) | ||
| 745 | return; | ||
| 746 | 655 | ||
| 656 | dai_node = rsnd_dai_of_node(priv); | ||
| 747 | nr = of_get_child_count(dai_node); | 657 | nr = of_get_child_count(dai_node); |
| 748 | if (!nr) | 658 | if (!nr) { |
| 749 | return; | 659 | ret = -EINVAL; |
| 660 | goto rsnd_dai_probe_done; | ||
| 661 | } | ||
| 750 | 662 | ||
| 751 | dai_info = devm_kzalloc(dev, | 663 | rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL); |
| 752 | sizeof(struct rsnd_dai_platform_info) * nr, | 664 | rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL); |
| 753 | GFP_KERNEL); | 665 | if (!rdrv || !rdai) { |
| 754 | if (!dai_info) { | 666 | ret = -ENOMEM; |
| 755 | dev_err(dev, "dai info allocation error\n"); | 667 | goto rsnd_dai_probe_done; |
| 756 | return; | ||
| 757 | } | 668 | } |
| 758 | 669 | ||
| 759 | info->dai_info_nr = nr; | 670 | priv->rdai_nr = nr; |
| 760 | info->dai_info = dai_info; | 671 | priv->daidrv = rdrv; |
| 761 | 672 | priv->rdai = rdai; | |
| 762 | ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi"); | ||
| 763 | src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src"); | ||
| 764 | ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); | ||
| 765 | mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); | ||
| 766 | dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); | ||
| 767 | |||
| 768 | #define mod_parse(name) \ | ||
| 769 | if (name##_node) { \ | ||
| 770 | struct rsnd_##name##_platform_info *name##_info; \ | ||
| 771 | \ | ||
| 772 | name##_i = 0; \ | ||
| 773 | for_each_child_of_node(name##_node, name##_np) { \ | ||
| 774 | name##_info = info->name##_info + name##_i; \ | ||
| 775 | \ | ||
| 776 | if (name##_np == playback) \ | ||
| 777 | dai_info->playback.name = name##_info; \ | ||
| 778 | if (name##_np == capture) \ | ||
| 779 | dai_info->capture.name = name##_info; \ | ||
| 780 | \ | ||
| 781 | name##_i++; \ | ||
| 782 | } \ | ||
| 783 | } | ||
| 784 | 673 | ||
| 785 | /* | 674 | /* |
| 786 | * parse all dai | 675 | * parse all dai |
| 787 | */ | 676 | */ |
| 788 | dai_i = 0; | 677 | dai_i = 0; |
| 789 | for_each_child_of_node(dai_node, dai_np) { | 678 | for_each_child_of_node(dai_node, dai_np) { |
| 790 | dai_info = info->dai_info + dai_i; | 679 | rdai = rsnd_rdai_get(priv, dai_i); |
| 791 | 680 | drv = rdrv + dai_i; | |
| 792 | for (i = 0;; i++) { | 681 | io_playback = &rdai->playback; |
| 793 | 682 | io_capture = &rdai->capture; | |
| 794 | playback = of_parse_phandle(dai_np, "playback", i); | 683 | |
| 795 | capture = of_parse_phandle(dai_np, "capture", i); | 684 | snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i); |
| 685 | |||
| 686 | rdai->priv = priv; | ||
| 687 | drv->name = rdai->name; | ||
| 688 | drv->ops = &rsnd_soc_dai_ops; | ||
| 689 | |||
| 690 | snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE, | ||
| 691 | "DAI%d Playback", dai_i); | ||
| 692 | drv->playback.rates = RSND_RATES; | ||
| 693 | drv->playback.formats = RSND_FMTS; | ||
| 694 | drv->playback.channels_min = 2; | ||
| 695 | drv->playback.channels_max = 6; | ||
| 696 | drv->playback.stream_name = rdai->playback.name; | ||
| 697 | |||
| 698 | snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE, | ||
| 699 | "DAI%d Capture", dai_i); | ||
| 700 | drv->capture.rates = RSND_RATES; | ||
| 701 | drv->capture.formats = RSND_FMTS; | ||
| 702 | drv->capture.channels_min = 2; | ||
| 703 | drv->capture.channels_max = 6; | ||
| 704 | drv->capture.stream_name = rdai->capture.name; | ||
| 705 | |||
| 706 | rdai->playback.rdai = rdai; | ||
| 707 | rdai->capture.rdai = rdai; | ||
| 708 | rsnd_set_slot(rdai, 2, 1); /* default */ | ||
| 709 | |||
| 710 | for (io_i = 0;; io_i++) { | ||
| 711 | playback = of_parse_phandle(dai_np, "playback", io_i); | ||
| 712 | capture = of_parse_phandle(dai_np, "capture", io_i); | ||
| 796 | 713 | ||
| 797 | if (!playback && !capture) | 714 | if (!playback && !capture) |
| 798 | break; | 715 | break; |
| 799 | 716 | ||
| 800 | mod_parse(ssi); | 717 | rsnd_parse_connect_ssi(rdai, playback, capture); |
| 801 | mod_parse(src); | 718 | rsnd_parse_connect_src(rdai, playback, capture); |
| 802 | mod_parse(ctu); | 719 | rsnd_parse_connect_ctu(rdai, playback, capture); |
| 803 | mod_parse(mix); | 720 | rsnd_parse_connect_mix(rdai, playback, capture); |
| 804 | mod_parse(dvc); | 721 | rsnd_parse_connect_dvc(rdai, playback, capture); |
| 805 | 722 | ||
| 806 | of_node_put(playback); | 723 | of_node_put(playback); |
| 807 | of_node_put(capture); | 724 | of_node_put(capture); |
| 808 | } | 725 | } |
| 809 | 726 | ||
| 810 | dai_i++; | 727 | dai_i++; |
| 811 | } | ||
| 812 | } | ||
| 813 | |||
| 814 | static int rsnd_dai_probe(struct platform_device *pdev, | ||
| 815 | const struct rsnd_of_data *of_data, | ||
| 816 | struct rsnd_priv *priv) | ||
| 817 | { | ||
| 818 | struct snd_soc_dai_driver *drv; | ||
| 819 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 820 | struct rsnd_dai *rdai; | ||
| 821 | struct rsnd_ssi_platform_info *pmod, *cmod; | ||
| 822 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 823 | int dai_nr; | ||
| 824 | int i; | ||
| 825 | |||
| 826 | rsnd_of_parse_dai(pdev, of_data, priv); | ||
| 827 | 728 | ||
| 828 | dai_nr = info->dai_info_nr; | 729 | dev_dbg(dev, "%s (%s/%s)\n", rdai->name, |
| 829 | if (!dai_nr) { | 730 | rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ", |
| 830 | dev_err(dev, "no dai\n"); | 731 | rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- "); |
| 831 | return -EIO; | ||
| 832 | } | 732 | } |
| 833 | 733 | ||
| 834 | drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL); | 734 | ret = 0; |
| 835 | rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL); | ||
| 836 | if (!drv || !rdai) { | ||
| 837 | dev_err(dev, "dai allocate failed\n"); | ||
| 838 | return -ENOMEM; | ||
| 839 | } | ||
| 840 | |||
| 841 | priv->rdai_nr = dai_nr; | ||
| 842 | priv->daidrv = drv; | ||
| 843 | priv->rdai = rdai; | ||
| 844 | 735 | ||
| 845 | for (i = 0; i < dai_nr; i++) { | 736 | rsnd_dai_probe_done: |
| 737 | of_node_put(dai_node); | ||
| 846 | 738 | ||
| 847 | pmod = info->dai_info[i].playback.ssi; | 739 | return ret; |
| 848 | cmod = info->dai_info[i].capture.ssi; | ||
| 849 | |||
| 850 | /* | ||
| 851 | * init rsnd_dai | ||
| 852 | */ | ||
| 853 | snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i); | ||
| 854 | rdai[i].priv = priv; | ||
| 855 | |||
| 856 | /* | ||
| 857 | * init snd_soc_dai_driver | ||
| 858 | */ | ||
| 859 | drv[i].name = rdai[i].name; | ||
| 860 | drv[i].ops = &rsnd_soc_dai_ops; | ||
| 861 | if (pmod) { | ||
| 862 | snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE, | ||
| 863 | "DAI%d Playback", i); | ||
| 864 | |||
| 865 | drv[i].playback.rates = RSND_RATES; | ||
| 866 | drv[i].playback.formats = RSND_FMTS; | ||
| 867 | drv[i].playback.channels_min = 2; | ||
| 868 | drv[i].playback.channels_max = 2; | ||
| 869 | drv[i].playback.stream_name = rdai[i].playback.name; | ||
| 870 | |||
| 871 | rdai[i].playback.info = &info->dai_info[i].playback; | ||
| 872 | rdai[i].playback.rdai = rdai + i; | ||
| 873 | rsnd_path_init(priv, &rdai[i], &rdai[i].playback); | ||
| 874 | } | ||
| 875 | if (cmod) { | ||
| 876 | snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE, | ||
| 877 | "DAI%d Capture", i); | ||
| 878 | |||
| 879 | drv[i].capture.rates = RSND_RATES; | ||
| 880 | drv[i].capture.formats = RSND_FMTS; | ||
| 881 | drv[i].capture.channels_min = 2; | ||
| 882 | drv[i].capture.channels_max = 2; | ||
| 883 | drv[i].capture.stream_name = rdai[i].capture.name; | ||
| 884 | |||
| 885 | rdai[i].capture.info = &info->dai_info[i].capture; | ||
| 886 | rdai[i].capture.rdai = rdai + i; | ||
| 887 | rsnd_path_init(priv, &rdai[i], &rdai[i].capture); | ||
| 888 | } | ||
| 889 | |||
| 890 | dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name, | ||
| 891 | pmod ? "play" : " -- ", | ||
| 892 | cmod ? "capture" : " -- "); | ||
| 893 | } | ||
| 894 | |||
| 895 | return 0; | ||
| 896 | } | 740 | } |
| 897 | 741 | ||
| 898 | /* | 742 | /* |
| @@ -1076,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, | |||
| 1076 | void (*update)(struct rsnd_dai_stream *io, | 920 | void (*update)(struct rsnd_dai_stream *io, |
| 1077 | struct rsnd_mod *mod), | 921 | struct rsnd_mod *mod), |
| 1078 | struct rsnd_kctrl_cfg_m *_cfg, | 922 | struct rsnd_kctrl_cfg_m *_cfg, |
| 923 | int ch_size, | ||
| 1079 | u32 max) | 924 | u32 max) |
| 1080 | { | 925 | { |
| 926 | if (ch_size > RSND_DVC_CHANNELS) | ||
| 927 | return -EINVAL; | ||
| 928 | |||
| 1081 | _cfg->cfg.max = max; | 929 | _cfg->cfg.max = max; |
| 1082 | _cfg->cfg.size = RSND_DVC_CHANNELS; | 930 | _cfg->cfg.size = ch_size; |
| 1083 | _cfg->cfg.val = _cfg->val; | 931 | _cfg->cfg.val = _cfg->val; |
| 1084 | return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); | 932 | return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update); |
| 1085 | } | 933 | } |
| @@ -1160,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, | |||
| 1160 | 1008 | ||
| 1161 | ret = rsnd_dai_call(probe, io, priv); | 1009 | ret = rsnd_dai_call(probe, io, priv); |
| 1162 | if (ret == -EAGAIN) { | 1010 | if (ret == -EAGAIN) { |
| 1011 | struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io); | ||
| 1012 | int i; | ||
| 1013 | |||
| 1163 | /* | 1014 | /* |
| 1164 | * Fallback to PIO mode | 1015 | * Fallback to PIO mode |
| 1165 | */ | 1016 | */ |
| @@ -1174,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, | |||
| 1174 | rsnd_dai_call(remove, io, priv); | 1025 | rsnd_dai_call(remove, io, priv); |
| 1175 | 1026 | ||
| 1176 | /* | 1027 | /* |
| 1177 | * remove SRC/DVC from DAI, | 1028 | * remove all mod from io |
| 1029 | * and, re connect ssi | ||
| 1178 | */ | 1030 | */ |
| 1179 | rsnd_path_remove(priv, io, src); | 1031 | for (i = 0; i < RSND_MOD_MAX; i++) |
| 1180 | rsnd_path_remove(priv, io, dvc); | 1032 | rsnd_dai_disconnect((io)->mod[i], io, i); |
| 1033 | rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); | ||
| 1181 | 1034 | ||
| 1182 | /* | 1035 | /* |
| 1183 | * fallback | 1036 | * fallback |
| @@ -1199,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, | |||
| 1199 | */ | 1052 | */ |
| 1200 | static int rsnd_probe(struct platform_device *pdev) | 1053 | static int rsnd_probe(struct platform_device *pdev) |
| 1201 | { | 1054 | { |
| 1202 | struct rcar_snd_info *info; | ||
| 1203 | struct rsnd_priv *priv; | 1055 | struct rsnd_priv *priv; |
| 1204 | struct device *dev = &pdev->dev; | 1056 | struct device *dev = &pdev->dev; |
| 1205 | struct rsnd_dai *rdai; | 1057 | struct rsnd_dai *rdai; |
| 1206 | const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); | 1058 | const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev); |
| 1207 | const struct rsnd_of_data *of_data; | 1059 | int (*probe_func[])(struct rsnd_priv *priv) = { |
| 1208 | int (*probe_func[])(struct platform_device *pdev, | ||
| 1209 | const struct rsnd_of_data *of_data, | ||
| 1210 | struct rsnd_priv *priv) = { | ||
| 1211 | rsnd_gen_probe, | 1060 | rsnd_gen_probe, |
| 1212 | rsnd_dma_probe, | 1061 | rsnd_dma_probe, |
| 1213 | rsnd_ssi_probe, | 1062 | rsnd_ssi_probe, |
| 1063 | rsnd_ssiu_probe, | ||
| 1214 | rsnd_src_probe, | 1064 | rsnd_src_probe, |
| 1215 | rsnd_ctu_probe, | 1065 | rsnd_ctu_probe, |
| 1216 | rsnd_mix_probe, | 1066 | rsnd_mix_probe, |
| 1217 | rsnd_dvc_probe, | 1067 | rsnd_dvc_probe, |
| 1068 | rsnd_cmd_probe, | ||
| 1218 | rsnd_adg_probe, | 1069 | rsnd_adg_probe, |
| 1219 | rsnd_dai_probe, | 1070 | rsnd_dai_probe, |
| 1220 | }; | 1071 | }; |
| 1221 | int ret, i; | 1072 | int ret, i; |
| 1222 | 1073 | ||
| 1223 | info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info), | ||
| 1224 | GFP_KERNEL); | ||
| 1225 | if (!info) | ||
| 1226 | return -ENOMEM; | ||
| 1227 | of_data = of_id->data; | ||
| 1228 | |||
| 1229 | /* | 1074 | /* |
| 1230 | * init priv data | 1075 | * init priv data |
| 1231 | */ | 1076 | */ |
| @@ -1236,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev) | |||
| 1236 | } | 1081 | } |
| 1237 | 1082 | ||
| 1238 | priv->pdev = pdev; | 1083 | priv->pdev = pdev; |
| 1239 | priv->info = info; | 1084 | priv->flags = (unsigned long)of_id->data; |
| 1240 | spin_lock_init(&priv->lock); | 1085 | spin_lock_init(&priv->lock); |
| 1241 | 1086 | ||
| 1242 | /* | 1087 | /* |
| 1243 | * init each module | 1088 | * init each module |
| 1244 | */ | 1089 | */ |
| 1245 | for (i = 0; i < ARRAY_SIZE(probe_func); i++) { | 1090 | for (i = 0; i < ARRAY_SIZE(probe_func); i++) { |
| 1246 | ret = probe_func[i](pdev, of_data, priv); | 1091 | ret = probe_func[i](priv); |
| 1247 | if (ret) | 1092 | if (ret) |
| 1248 | return ret; | 1093 | return ret; |
| 1249 | } | 1094 | } |
| @@ -1296,13 +1141,15 @@ static int rsnd_remove(struct platform_device *pdev) | |||
| 1296 | { | 1141 | { |
| 1297 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); | 1142 | struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev); |
| 1298 | struct rsnd_dai *rdai; | 1143 | struct rsnd_dai *rdai; |
| 1299 | void (*remove_func[])(struct platform_device *pdev, | 1144 | void (*remove_func[])(struct rsnd_priv *priv) = { |
| 1300 | struct rsnd_priv *priv) = { | ||
| 1301 | rsnd_ssi_remove, | 1145 | rsnd_ssi_remove, |
| 1146 | rsnd_ssiu_remove, | ||
| 1302 | rsnd_src_remove, | 1147 | rsnd_src_remove, |
| 1303 | rsnd_ctu_remove, | 1148 | rsnd_ctu_remove, |
| 1304 | rsnd_mix_remove, | 1149 | rsnd_mix_remove, |
| 1305 | rsnd_dvc_remove, | 1150 | rsnd_dvc_remove, |
| 1151 | rsnd_cmd_remove, | ||
| 1152 | rsnd_adg_remove, | ||
| 1306 | }; | 1153 | }; |
| 1307 | int ret = 0, i; | 1154 | int ret = 0, i; |
| 1308 | 1155 | ||
| @@ -1314,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev) | |||
| 1314 | } | 1161 | } |
| 1315 | 1162 | ||
| 1316 | for (i = 0; i < ARRAY_SIZE(remove_func); i++) | 1163 | for (i = 0; i < ARRAY_SIZE(remove_func); i++) |
| 1317 | remove_func[i](pdev, priv); | 1164 | remove_func[i](priv); |
| 1318 | 1165 | ||
| 1319 | snd_soc_unregister_component(&pdev->dev); | 1166 | snd_soc_unregister_component(&pdev->dev); |
| 1320 | snd_soc_unregister_platform(&pdev->dev); | 1167 | snd_soc_unregister_platform(&pdev->dev); |
diff --git a/sound/soc/sh/rcar/ctu.c b/sound/soc/sh/rcar/ctu.c index 3cb214ab848b..d53a225d19e9 100644 --- a/sound/soc/sh/rcar/ctu.c +++ b/sound/soc/sh/rcar/ctu.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #define CTU_NAME "ctu" | 13 | #define CTU_NAME "ctu" |
| 14 | 14 | ||
| 15 | struct rsnd_ctu { | 15 | struct rsnd_ctu { |
| 16 | struct rsnd_ctu_platform_info *info; /* rcar_snd.h */ | ||
| 17 | struct rsnd_mod mod; | 16 | struct rsnd_mod mod; |
| 18 | }; | 17 | }; |
| 19 | 18 | ||
| @@ -24,6 +23,7 @@ struct rsnd_ctu { | |||
| 24 | ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ | 23 | ((pos) = (struct rsnd_ctu *)(priv)->ctu + i); \ |
| 25 | i++) | 24 | i++) |
| 26 | 25 | ||
| 26 | #define rsnd_ctu_get(priv, id) ((struct rsnd_ctu *)(priv->ctu) + id) | ||
| 27 | #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) | 27 | #define rsnd_ctu_initialize_lock(mod) __rsnd_ctu_initialize_lock(mod, 1) |
| 28 | #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) | 28 | #define rsnd_ctu_initialize_unlock(mod) __rsnd_ctu_initialize_lock(mod, 0) |
| 29 | static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) | 29 | static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) |
| @@ -31,6 +31,13 @@ static void __rsnd_ctu_initialize_lock(struct rsnd_mod *mod, u32 enable) | |||
| 31 | rsnd_mod_write(mod, CTU_CTUIR, enable); | 31 | rsnd_mod_write(mod, CTU_CTUIR, enable); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | static int rsnd_ctu_probe_(struct rsnd_mod *mod, | ||
| 35 | struct rsnd_dai_stream *io, | ||
| 36 | struct rsnd_priv *priv) | ||
| 37 | { | ||
| 38 | return rsnd_cmd_attach(io, rsnd_mod_id(mod) / 4); | ||
| 39 | } | ||
| 40 | |||
| 34 | static int rsnd_ctu_init(struct rsnd_mod *mod, | 41 | static int rsnd_ctu_init(struct rsnd_mod *mod, |
| 35 | struct rsnd_dai_stream *io, | 42 | struct rsnd_dai_stream *io, |
| 36 | struct rsnd_priv *priv) | 43 | struct rsnd_priv *priv) |
| @@ -57,6 +64,7 @@ static int rsnd_ctu_quit(struct rsnd_mod *mod, | |||
| 57 | 64 | ||
| 58 | static struct rsnd_mod_ops rsnd_ctu_ops = { | 65 | static struct rsnd_mod_ops rsnd_ctu_ops = { |
| 59 | .name = CTU_NAME, | 66 | .name = CTU_NAME, |
| 67 | .probe = rsnd_ctu_probe_, | ||
| 60 | .init = rsnd_ctu_init, | 68 | .init = rsnd_ctu_init, |
| 61 | .quit = rsnd_ctu_quit, | 69 | .quit = rsnd_ctu_quit, |
| 62 | }; | 70 | }; |
| @@ -66,51 +74,13 @@ struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id) | |||
| 66 | if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) | 74 | if (WARN_ON(id < 0 || id >= rsnd_ctu_nr(priv))) |
| 67 | id = 0; | 75 | id = 0; |
| 68 | 76 | ||
| 69 | return rsnd_mod_get((struct rsnd_ctu *)(priv->ctu) + id); | 77 | return rsnd_mod_get(rsnd_ctu_get(priv, id)); |
| 70 | } | 78 | } |
| 71 | 79 | ||
| 72 | static void rsnd_of_parse_ctu(struct platform_device *pdev, | 80 | int rsnd_ctu_probe(struct rsnd_priv *priv) |
| 73 | const struct rsnd_of_data *of_data, | ||
| 74 | struct rsnd_priv *priv) | ||
| 75 | { | 81 | { |
| 76 | struct device_node *node; | 82 | struct device_node *node; |
| 77 | struct rsnd_ctu_platform_info *ctu_info; | 83 | struct device_node *np; |
| 78 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 79 | struct device *dev = &pdev->dev; | ||
| 80 | int nr; | ||
| 81 | |||
| 82 | if (!of_data) | ||
| 83 | return; | ||
| 84 | |||
| 85 | node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu"); | ||
| 86 | if (!node) | ||
| 87 | return; | ||
| 88 | |||
| 89 | nr = of_get_child_count(node); | ||
| 90 | if (!nr) | ||
| 91 | goto rsnd_of_parse_ctu_end; | ||
| 92 | |||
| 93 | ctu_info = devm_kzalloc(dev, | ||
| 94 | sizeof(struct rsnd_ctu_platform_info) * nr, | ||
| 95 | GFP_KERNEL); | ||
| 96 | if (!ctu_info) { | ||
| 97 | dev_err(dev, "ctu info allocation error\n"); | ||
| 98 | goto rsnd_of_parse_ctu_end; | ||
| 99 | } | ||
| 100 | |||
| 101 | info->ctu_info = ctu_info; | ||
| 102 | info->ctu_info_nr = nr; | ||
| 103 | |||
| 104 | rsnd_of_parse_ctu_end: | ||
| 105 | of_node_put(node); | ||
| 106 | |||
| 107 | } | ||
| 108 | |||
| 109 | int rsnd_ctu_probe(struct platform_device *pdev, | ||
| 110 | const struct rsnd_of_data *of_data, | ||
| 111 | struct rsnd_priv *priv) | ||
| 112 | { | ||
| 113 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 114 | struct device *dev = rsnd_priv_to_dev(priv); | 84 | struct device *dev = rsnd_priv_to_dev(priv); |
| 115 | struct rsnd_ctu *ctu; | 85 | struct rsnd_ctu *ctu; |
| 116 | struct clk *clk; | 86 | struct clk *clk; |
| @@ -121,20 +91,30 @@ int rsnd_ctu_probe(struct platform_device *pdev, | |||
| 121 | if (rsnd_is_gen1(priv)) | 91 | if (rsnd_is_gen1(priv)) |
| 122 | return 0; | 92 | return 0; |
| 123 | 93 | ||
| 124 | rsnd_of_parse_ctu(pdev, of_data, priv); | 94 | node = rsnd_ctu_of_node(priv); |
| 95 | if (!node) | ||
| 96 | return 0; /* not used is not error */ | ||
| 125 | 97 | ||
| 126 | nr = info->ctu_info_nr; | 98 | nr = of_get_child_count(node); |
| 127 | if (!nr) | 99 | if (!nr) { |
| 128 | return 0; | 100 | ret = -EINVAL; |
| 101 | goto rsnd_ctu_probe_done; | ||
| 102 | } | ||
| 129 | 103 | ||
| 130 | ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); | 104 | ctu = devm_kzalloc(dev, sizeof(*ctu) * nr, GFP_KERNEL); |
| 131 | if (!ctu) | 105 | if (!ctu) { |
| 132 | return -ENOMEM; | 106 | ret = -ENOMEM; |
| 107 | goto rsnd_ctu_probe_done; | ||
| 108 | } | ||
| 133 | 109 | ||
| 134 | priv->ctu_nr = nr; | 110 | priv->ctu_nr = nr; |
| 135 | priv->ctu = ctu; | 111 | priv->ctu = ctu; |
| 136 | 112 | ||
| 137 | for_each_rsnd_ctu(ctu, priv, i) { | 113 | i = 0; |
| 114 | ret = 0; | ||
| 115 | for_each_child_of_node(node, np) { | ||
| 116 | ctu = rsnd_ctu_get(priv, i); | ||
| 117 | |||
| 138 | /* | 118 | /* |
| 139 | * CTU00, CTU01, CTU02, CTU03 => CTU0 | 119 | * CTU00, CTU01, CTU02, CTU03 => CTU0 |
| 140 | * CTU10, CTU11, CTU12, CTU13 => CTU1 | 120 | * CTU10, CTU11, CTU12, CTU13 => CTU1 |
| @@ -143,22 +123,27 @@ int rsnd_ctu_probe(struct platform_device *pdev, | |||
| 143 | CTU_NAME, i / 4); | 123 | CTU_NAME, i / 4); |
| 144 | 124 | ||
| 145 | clk = devm_clk_get(dev, name); | 125 | clk = devm_clk_get(dev, name); |
| 146 | if (IS_ERR(clk)) | 126 | if (IS_ERR(clk)) { |
| 147 | return PTR_ERR(clk); | 127 | ret = PTR_ERR(clk); |
| 148 | 128 | goto rsnd_ctu_probe_done; | |
| 149 | ctu->info = &info->ctu_info[i]; | 129 | } |
| 150 | 130 | ||
| 151 | ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, | 131 | ret = rsnd_mod_init(priv, rsnd_mod_get(ctu), &rsnd_ctu_ops, |
| 152 | clk, RSND_MOD_CTU, i); | 132 | clk, RSND_MOD_CTU, i); |
| 153 | if (ret) | 133 | if (ret) |
| 154 | return ret; | 134 | goto rsnd_ctu_probe_done; |
| 135 | |||
| 136 | i++; | ||
| 155 | } | 137 | } |
| 156 | 138 | ||
| 157 | return 0; | 139 | |
| 140 | rsnd_ctu_probe_done: | ||
| 141 | of_node_put(node); | ||
| 142 | |||
| 143 | return ret; | ||
| 158 | } | 144 | } |
| 159 | 145 | ||
| 160 | void rsnd_ctu_remove(struct platform_device *pdev, | 146 | void rsnd_ctu_remove(struct rsnd_priv *priv) |
| 161 | struct rsnd_priv *priv) | ||
| 162 | { | 147 | { |
| 163 | struct rsnd_ctu *ctu; | 148 | struct rsnd_ctu *ctu; |
| 164 | int i; | 149 | int i; |
diff --git a/sound/soc/sh/rcar/dma.c b/sound/soc/sh/rcar/dma.c index 5d084d040961..418e6fdd06a3 100644 --- a/sound/soc/sh/rcar/dma.c +++ b/sound/soc/sh/rcar/dma.c | |||
| @@ -22,21 +22,36 @@ | |||
| 22 | /* PDMACHCR */ | 22 | /* PDMACHCR */ |
| 23 | #define PDMACHCR_DE (1 << 0) | 23 | #define PDMACHCR_DE (1 << 0) |
| 24 | 24 | ||
| 25 | |||
| 26 | struct rsnd_dmaen { | ||
| 27 | struct dma_chan *chan; | ||
| 28 | }; | ||
| 29 | |||
| 30 | struct rsnd_dmapp { | ||
| 31 | int dmapp_id; | ||
| 32 | u32 chcr; | ||
| 33 | }; | ||
| 34 | |||
| 35 | struct rsnd_dma { | ||
| 36 | struct rsnd_mod mod; | ||
| 37 | dma_addr_t src_addr; | ||
| 38 | dma_addr_t dst_addr; | ||
| 39 | union { | ||
| 40 | struct rsnd_dmaen en; | ||
| 41 | struct rsnd_dmapp pp; | ||
| 42 | } dma; | ||
| 43 | }; | ||
| 44 | |||
| 25 | struct rsnd_dma_ctrl { | 45 | struct rsnd_dma_ctrl { |
| 26 | void __iomem *base; | 46 | void __iomem *base; |
| 47 | int dmaen_num; | ||
| 27 | int dmapp_num; | 48 | int dmapp_num; |
| 28 | }; | 49 | }; |
| 29 | 50 | ||
| 30 | struct rsnd_dma_ops { | ||
| 31 | char *name; | ||
| 32 | void (*start)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 33 | void (*stop)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 34 | int (*init)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, | ||
| 35 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); | ||
| 36 | void (*quit)(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 37 | }; | ||
| 38 | |||
| 39 | #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) | 51 | #define rsnd_priv_to_dmac(p) ((struct rsnd_dma_ctrl *)(p)->dma) |
| 52 | #define rsnd_mod_to_dma(_mod) container_of((_mod), struct rsnd_dma, mod) | ||
| 53 | #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) | ||
| 54 | #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) | ||
| 40 | 55 | ||
| 41 | /* | 56 | /* |
| 42 | * Audio DMAC | 57 | * Audio DMAC |
| @@ -77,18 +92,24 @@ static void rsnd_dmaen_complete(void *data) | |||
| 77 | rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); | 92 | rsnd_mod_interrupt(mod, __rsnd_dmaen_complete); |
| 78 | } | 93 | } |
| 79 | 94 | ||
| 80 | static void rsnd_dmaen_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 95 | static int rsnd_dmaen_stop(struct rsnd_mod *mod, |
| 96 | struct rsnd_dai_stream *io, | ||
| 97 | struct rsnd_priv *priv) | ||
| 81 | { | 98 | { |
| 99 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 82 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 100 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
| 83 | 101 | ||
| 84 | dmaengine_terminate_all(dmaen->chan); | 102 | dmaengine_terminate_all(dmaen->chan); |
| 103 | |||
| 104 | return 0; | ||
| 85 | } | 105 | } |
| 86 | 106 | ||
| 87 | static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 107 | static int rsnd_dmaen_start(struct rsnd_mod *mod, |
| 108 | struct rsnd_dai_stream *io, | ||
| 109 | struct rsnd_priv *priv) | ||
| 88 | { | 110 | { |
| 111 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 89 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 112 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
| 90 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | ||
| 91 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 92 | struct snd_pcm_substream *substream = io->substream; | 113 | struct snd_pcm_substream *substream = io->substream; |
| 93 | struct device *dev = rsnd_priv_to_dev(priv); | 114 | struct device *dev = rsnd_priv_to_dev(priv); |
| 94 | struct dma_async_tx_descriptor *desc; | 115 | struct dma_async_tx_descriptor *desc; |
| @@ -103,18 +124,20 @@ static void rsnd_dmaen_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | |||
| 103 | 124 | ||
| 104 | if (!desc) { | 125 | if (!desc) { |
| 105 | dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); | 126 | dev_err(dev, "dmaengine_prep_slave_sg() fail\n"); |
| 106 | return; | 127 | return -EIO; |
| 107 | } | 128 | } |
| 108 | 129 | ||
| 109 | desc->callback = rsnd_dmaen_complete; | 130 | desc->callback = rsnd_dmaen_complete; |
| 110 | desc->callback_param = mod; | 131 | desc->callback_param = rsnd_mod_get(dma); |
| 111 | 132 | ||
| 112 | if (dmaengine_submit(desc) < 0) { | 133 | if (dmaengine_submit(desc) < 0) { |
| 113 | dev_err(dev, "dmaengine_submit() fail\n"); | 134 | dev_err(dev, "dmaengine_submit() fail\n"); |
| 114 | return; | 135 | return -EIO; |
| 115 | } | 136 | } |
| 116 | 137 | ||
| 117 | dma_async_issue_pending(dmaen->chan); | 138 | dma_async_issue_pending(dmaen->chan); |
| 139 | |||
| 140 | return 0; | ||
| 118 | } | 141 | } |
| 119 | 142 | ||
| 120 | struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, | 143 | struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, |
| @@ -152,12 +175,29 @@ static struct dma_chan *rsnd_dmaen_request_channel(struct rsnd_dai_stream *io, | |||
| 152 | return rsnd_mod_dma_req(io, mod_to); | 175 | return rsnd_mod_dma_req(io, mod_to); |
| 153 | } | 176 | } |
| 154 | 177 | ||
| 155 | static int rsnd_dmaen_init(struct rsnd_dai_stream *io, | 178 | static int rsnd_dmaen_remove(struct rsnd_mod *mod, |
| 179 | struct rsnd_dai_stream *io, | ||
| 180 | struct rsnd_priv *priv) | ||
| 181 | { | ||
| 182 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 183 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | ||
| 184 | |||
| 185 | if (dmaen->chan) | ||
| 186 | dma_release_channel(dmaen->chan); | ||
| 187 | |||
| 188 | dmaen->chan = NULL; | ||
| 189 | |||
| 190 | return 0; | ||
| 191 | } | ||
| 192 | |||
| 193 | static int rsnd_dmaen_attach(struct rsnd_dai_stream *io, | ||
| 156 | struct rsnd_dma *dma, int id, | 194 | struct rsnd_dma *dma, int id, |
| 157 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) | 195 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) |
| 158 | { | 196 | { |
| 197 | struct rsnd_mod *mod = rsnd_mod_get(dma); | ||
| 159 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | 198 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); |
| 160 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 199 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
| 200 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | ||
| 161 | struct device *dev = rsnd_priv_to_dev(priv); | 201 | struct device *dev = rsnd_priv_to_dev(priv); |
| 162 | struct dma_slave_config cfg = {}; | 202 | struct dma_slave_config cfg = {}; |
| 163 | int is_play = rsnd_io_is_play(io); | 203 | int is_play = rsnd_io_is_play(io); |
| @@ -191,18 +231,20 @@ static int rsnd_dmaen_init(struct rsnd_dai_stream *io, | |||
| 191 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 231 | cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
| 192 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; | 232 | cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; |
| 193 | 233 | ||
| 194 | dev_dbg(dev, "%s %pad -> %pad\n", | 234 | dev_dbg(dev, "%s[%d] %pad -> %pad\n", |
| 195 | dma->ops->name, | 235 | rsnd_mod_name(mod), rsnd_mod_id(mod), |
| 196 | &cfg.src_addr, &cfg.dst_addr); | 236 | &cfg.src_addr, &cfg.dst_addr); |
| 197 | 237 | ||
| 198 | ret = dmaengine_slave_config(dmaen->chan, &cfg); | 238 | ret = dmaengine_slave_config(dmaen->chan, &cfg); |
| 199 | if (ret < 0) | 239 | if (ret < 0) |
| 200 | goto rsnd_dma_init_err; | 240 | goto rsnd_dma_attach_err; |
| 241 | |||
| 242 | dmac->dmaen_num++; | ||
| 201 | 243 | ||
| 202 | return 0; | 244 | return 0; |
| 203 | 245 | ||
| 204 | rsnd_dma_init_err: | 246 | rsnd_dma_attach_err: |
| 205 | rsnd_dma_quit(io, dma); | 247 | rsnd_dmaen_remove(mod, io, priv); |
| 206 | rsnd_dma_channel_err: | 248 | rsnd_dma_channel_err: |
| 207 | 249 | ||
| 208 | /* | 250 | /* |
| @@ -214,22 +256,11 @@ rsnd_dma_channel_err: | |||
| 214 | return -EAGAIN; | 256 | return -EAGAIN; |
| 215 | } | 257 | } |
| 216 | 258 | ||
| 217 | static void rsnd_dmaen_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 259 | static struct rsnd_mod_ops rsnd_dmaen_ops = { |
| 218 | { | ||
| 219 | struct rsnd_dmaen *dmaen = rsnd_dma_to_dmaen(dma); | ||
| 220 | |||
| 221 | if (dmaen->chan) | ||
| 222 | dma_release_channel(dmaen->chan); | ||
| 223 | |||
| 224 | dmaen->chan = NULL; | ||
| 225 | } | ||
| 226 | |||
| 227 | static struct rsnd_dma_ops rsnd_dmaen_ops = { | ||
| 228 | .name = "audmac", | 260 | .name = "audmac", |
| 229 | .start = rsnd_dmaen_start, | 261 | .start = rsnd_dmaen_start, |
| 230 | .stop = rsnd_dmaen_stop, | 262 | .stop = rsnd_dmaen_stop, |
| 231 | .init = rsnd_dmaen_init, | 263 | .remove = rsnd_dmaen_remove, |
| 232 | .quit = rsnd_dmaen_quit, | ||
| 233 | }; | 264 | }; |
| 234 | 265 | ||
| 235 | /* | 266 | /* |
| @@ -307,7 +338,7 @@ static u32 rsnd_dmapp_get_chcr(struct rsnd_dai_stream *io, | |||
| 307 | (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) | 338 | (0x10 * rsnd_dma_to_dmapp(dma)->dmapp_id)) |
| 308 | static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) | 339 | static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) |
| 309 | { | 340 | { |
| 310 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 341 | struct rsnd_mod *mod = rsnd_mod_get(dma); |
| 311 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 342 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 312 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | 343 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); |
| 313 | struct device *dev = rsnd_priv_to_dev(priv); | 344 | struct device *dev = rsnd_priv_to_dev(priv); |
| @@ -319,38 +350,48 @@ static void rsnd_dmapp_write(struct rsnd_dma *dma, u32 data, u32 reg) | |||
| 319 | 350 | ||
| 320 | static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) | 351 | static u32 rsnd_dmapp_read(struct rsnd_dma *dma, u32 reg) |
| 321 | { | 352 | { |
| 322 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | 353 | struct rsnd_mod *mod = rsnd_mod_get(dma); |
| 323 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 354 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 324 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | 355 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); |
| 325 | 356 | ||
| 326 | return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); | 357 | return ioread32(rsnd_dmapp_addr(dmac, dma, reg)); |
| 327 | } | 358 | } |
| 328 | 359 | ||
| 329 | static void rsnd_dmapp_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 360 | static int rsnd_dmapp_stop(struct rsnd_mod *mod, |
| 361 | struct rsnd_dai_stream *io, | ||
| 362 | struct rsnd_priv *priv) | ||
| 330 | { | 363 | { |
| 364 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 331 | int i; | 365 | int i; |
| 332 | 366 | ||
| 333 | rsnd_dmapp_write(dma, 0, PDMACHCR); | 367 | rsnd_dmapp_write(dma, 0, PDMACHCR); |
| 334 | 368 | ||
| 335 | for (i = 0; i < 1024; i++) { | 369 | for (i = 0; i < 1024; i++) { |
| 336 | if (0 == rsnd_dmapp_read(dma, PDMACHCR)) | 370 | if (0 == rsnd_dmapp_read(dma, PDMACHCR)) |
| 337 | return; | 371 | return 0; |
| 338 | udelay(1); | 372 | udelay(1); |
| 339 | } | 373 | } |
| 374 | |||
| 375 | return -EIO; | ||
| 340 | } | 376 | } |
| 341 | 377 | ||
| 342 | static void rsnd_dmapp_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 378 | static int rsnd_dmapp_start(struct rsnd_mod *mod, |
| 379 | struct rsnd_dai_stream *io, | ||
| 380 | struct rsnd_priv *priv) | ||
| 343 | { | 381 | { |
| 382 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 344 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); | 383 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); |
| 345 | 384 | ||
| 346 | rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); | 385 | rsnd_dmapp_write(dma, dma->src_addr, PDMASAR); |
| 347 | rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); | 386 | rsnd_dmapp_write(dma, dma->dst_addr, PDMADAR); |
| 348 | rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); | 387 | rsnd_dmapp_write(dma, dmapp->chcr, PDMACHCR); |
| 388 | |||
| 389 | return 0; | ||
| 349 | } | 390 | } |
| 350 | 391 | ||
| 351 | static int rsnd_dmapp_init(struct rsnd_dai_stream *io, | 392 | static int rsnd_dmapp_attach(struct rsnd_dai_stream *io, |
| 352 | struct rsnd_dma *dma, int id, | 393 | struct rsnd_dma *dma, int id, |
| 353 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) | 394 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to) |
| 354 | { | 395 | { |
| 355 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); | 396 | struct rsnd_dmapp *dmapp = rsnd_dma_to_dmapp(dma); |
| 356 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 397 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
| @@ -362,19 +403,16 @@ static int rsnd_dmapp_init(struct rsnd_dai_stream *io, | |||
| 362 | 403 | ||
| 363 | dmac->dmapp_num++; | 404 | dmac->dmapp_num++; |
| 364 | 405 | ||
| 365 | rsnd_dmapp_stop(io, dma); | ||
| 366 | |||
| 367 | dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", | 406 | dev_dbg(dev, "id/src/dst/chcr = %d/%pad/%pad/%08x\n", |
| 368 | dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); | 407 | dmapp->dmapp_id, &dma->src_addr, &dma->dst_addr, dmapp->chcr); |
| 369 | 408 | ||
| 370 | return 0; | 409 | return 0; |
| 371 | } | 410 | } |
| 372 | 411 | ||
| 373 | static struct rsnd_dma_ops rsnd_dmapp_ops = { | 412 | static struct rsnd_mod_ops rsnd_dmapp_ops = { |
| 374 | .name = "audmac-pp", | 413 | .name = "audmac-pp", |
| 375 | .start = rsnd_dmapp_start, | 414 | .start = rsnd_dmapp_start, |
| 376 | .stop = rsnd_dmapp_stop, | 415 | .stop = rsnd_dmapp_stop, |
| 377 | .init = rsnd_dmapp_init, | ||
| 378 | .quit = rsnd_dmapp_stop, | 416 | .quit = rsnd_dmapp_stop, |
| 379 | }; | 417 | }; |
| 380 | 418 | ||
| @@ -497,13 +535,12 @@ static dma_addr_t rsnd_dma_addr(struct rsnd_dai_stream *io, | |||
| 497 | } | 535 | } |
| 498 | 536 | ||
| 499 | #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ | 537 | #define MOD_MAX (RSND_MOD_MAX + 1) /* +Memory */ |
| 500 | static void rsnd_dma_of_path(struct rsnd_dma *dma, | 538 | static void rsnd_dma_of_path(struct rsnd_mod *this, |
| 501 | struct rsnd_dai_stream *io, | 539 | struct rsnd_dai_stream *io, |
| 502 | int is_play, | 540 | int is_play, |
| 503 | struct rsnd_mod **mod_from, | 541 | struct rsnd_mod **mod_from, |
| 504 | struct rsnd_mod **mod_to) | 542 | struct rsnd_mod **mod_to) |
| 505 | { | 543 | { |
| 506 | struct rsnd_mod *this = rsnd_dma_to_mod(dma); | ||
| 507 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); | 544 | struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io); |
| 508 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); | 545 | struct rsnd_mod *src = rsnd_io_to_mod_src(io); |
| 509 | struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); | 546 | struct rsnd_mod *ctu = rsnd_io_to_mod_ctu(io); |
| @@ -513,7 +550,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
| 513 | struct rsnd_mod *mod_start, *mod_end; | 550 | struct rsnd_mod *mod_start, *mod_end; |
| 514 | struct rsnd_priv *priv = rsnd_mod_to_priv(this); | 551 | struct rsnd_priv *priv = rsnd_mod_to_priv(this); |
| 515 | struct device *dev = rsnd_priv_to_dev(priv); | 552 | struct device *dev = rsnd_priv_to_dev(priv); |
| 516 | int nr, i; | 553 | int nr, i, idx; |
| 517 | 554 | ||
| 518 | if (!ssi) | 555 | if (!ssi) |
| 519 | return; | 556 | return; |
| @@ -542,23 +579,24 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
| 542 | mod_start = (is_play) ? NULL : ssi; | 579 | mod_start = (is_play) ? NULL : ssi; |
| 543 | mod_end = (is_play) ? ssi : NULL; | 580 | mod_end = (is_play) ? ssi : NULL; |
| 544 | 581 | ||
| 545 | mod[0] = mod_start; | 582 | idx = 0; |
| 583 | mod[idx++] = mod_start; | ||
| 546 | for (i = 1; i < nr; i++) { | 584 | for (i = 1; i < nr; i++) { |
| 547 | if (src) { | 585 | if (src) { |
| 548 | mod[i] = src; | 586 | mod[idx++] = src; |
| 549 | src = NULL; | 587 | src = NULL; |
| 550 | } else if (ctu) { | 588 | } else if (ctu) { |
| 551 | mod[i] = ctu; | 589 | mod[idx++] = ctu; |
| 552 | ctu = NULL; | 590 | ctu = NULL; |
| 553 | } else if (mix) { | 591 | } else if (mix) { |
| 554 | mod[i] = mix; | 592 | mod[idx++] = mix; |
| 555 | mix = NULL; | 593 | mix = NULL; |
| 556 | } else if (dvc) { | 594 | } else if (dvc) { |
| 557 | mod[i] = dvc; | 595 | mod[idx++] = dvc; |
| 558 | dvc = NULL; | 596 | dvc = NULL; |
| 559 | } | 597 | } |
| 560 | } | 598 | } |
| 561 | mod[i] = mod_end; | 599 | mod[idx] = mod_end; |
| 562 | 600 | ||
| 563 | /* | 601 | /* |
| 564 | * | SSI | SRC | | 602 | * | SSI | SRC | |
| @@ -567,8 +605,8 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
| 567 | * !is_play | * | o | | 605 | * !is_play | * | o | |
| 568 | */ | 606 | */ |
| 569 | if ((this == ssi) == (is_play)) { | 607 | if ((this == ssi) == (is_play)) { |
| 570 | *mod_from = mod[nr - 1]; | 608 | *mod_from = mod[idx - 1]; |
| 571 | *mod_to = mod[nr]; | 609 | *mod_to = mod[idx]; |
| 572 | } else { | 610 | } else { |
| 573 | *mod_from = mod[0]; | 611 | *mod_from = mod[0]; |
| 574 | *mod_to = mod[1]; | 612 | *mod_to = mod[1]; |
| @@ -576,7 +614,7 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
| 576 | 614 | ||
| 577 | dev_dbg(dev, "module connection (this is %s[%d])\n", | 615 | dev_dbg(dev, "module connection (this is %s[%d])\n", |
| 578 | rsnd_mod_name(this), rsnd_mod_id(this)); | 616 | rsnd_mod_name(this), rsnd_mod_id(this)); |
| 579 | for (i = 0; i <= nr; i++) { | 617 | for (i = 0; i <= idx; i++) { |
| 580 | dev_dbg(dev, " %s[%d]%s\n", | 618 | dev_dbg(dev, " %s[%d]%s\n", |
| 581 | rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), | 619 | rsnd_mod_name(mod[i]), rsnd_mod_id(mod[i]), |
| 582 | (mod[i] == *mod_from) ? " from" : | 620 | (mod[i] == *mod_from) ? " from" : |
| @@ -584,36 +622,22 @@ static void rsnd_dma_of_path(struct rsnd_dma *dma, | |||
| 584 | } | 622 | } |
| 585 | } | 623 | } |
| 586 | 624 | ||
| 587 | void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | 625 | struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, |
| 588 | { | 626 | struct rsnd_mod *mod, int id) |
| 589 | dma->ops->stop(io, dma); | ||
| 590 | } | ||
| 591 | |||
| 592 | void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | ||
| 593 | { | ||
| 594 | dma->ops->start(io, dma); | ||
| 595 | } | ||
| 596 | |||
| 597 | void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma) | ||
| 598 | { | ||
| 599 | struct rsnd_mod *mod = rsnd_dma_to_mod(dma); | ||
| 600 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 601 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | ||
| 602 | |||
| 603 | if (!dmac) | ||
| 604 | return; | ||
| 605 | |||
| 606 | dma->ops->quit(io, dma); | ||
| 607 | } | ||
| 608 | |||
| 609 | int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) | ||
| 610 | { | 627 | { |
| 628 | struct rsnd_mod *dma_mod; | ||
| 611 | struct rsnd_mod *mod_from = NULL; | 629 | struct rsnd_mod *mod_from = NULL; |
| 612 | struct rsnd_mod *mod_to = NULL; | 630 | struct rsnd_mod *mod_to = NULL; |
| 613 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 631 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
| 614 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); | 632 | struct rsnd_dma_ctrl *dmac = rsnd_priv_to_dmac(priv); |
| 633 | struct rsnd_dma *dma; | ||
| 615 | struct device *dev = rsnd_priv_to_dev(priv); | 634 | struct device *dev = rsnd_priv_to_dev(priv); |
| 635 | struct rsnd_mod_ops *ops; | ||
| 636 | enum rsnd_mod_type type; | ||
| 637 | int (*attach)(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id, | ||
| 638 | struct rsnd_mod *mod_from, struct rsnd_mod *mod_to); | ||
| 616 | int is_play = rsnd_io_is_play(io); | 639 | int is_play = rsnd_io_is_play(io); |
| 640 | int ret, dma_id; | ||
| 617 | 641 | ||
| 618 | /* | 642 | /* |
| 619 | * DMA failed. try to PIO mode | 643 | * DMA failed. try to PIO mode |
| @@ -622,35 +646,64 @@ int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id) | |||
| 622 | * rsnd_rdai_continuance_probe() | 646 | * rsnd_rdai_continuance_probe() |
| 623 | */ | 647 | */ |
| 624 | if (!dmac) | 648 | if (!dmac) |
| 625 | return -EAGAIN; | 649 | return ERR_PTR(-EAGAIN); |
| 626 | 650 | ||
| 627 | rsnd_dma_of_path(dma, io, is_play, &mod_from, &mod_to); | 651 | dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); |
| 652 | if (!dma) | ||
| 653 | return ERR_PTR(-ENOMEM); | ||
| 654 | |||
| 655 | rsnd_dma_of_path(mod, io, is_play, &mod_from, &mod_to); | ||
| 628 | 656 | ||
| 629 | dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); | 657 | dma->src_addr = rsnd_dma_addr(io, mod_from, is_play, 1); |
| 630 | dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); | 658 | dma->dst_addr = rsnd_dma_addr(io, mod_to, is_play, 0); |
| 631 | 659 | ||
| 632 | /* for Gen2 */ | 660 | /* for Gen2 */ |
| 633 | if (mod_from && mod_to) | 661 | if (mod_from && mod_to) { |
| 634 | dma->ops = &rsnd_dmapp_ops; | 662 | ops = &rsnd_dmapp_ops; |
| 635 | else | 663 | attach = rsnd_dmapp_attach; |
| 636 | dma->ops = &rsnd_dmaen_ops; | 664 | dma_id = dmac->dmapp_num; |
| 665 | type = RSND_MOD_AUDMAPP; | ||
| 666 | } else { | ||
| 667 | ops = &rsnd_dmaen_ops; | ||
| 668 | attach = rsnd_dmaen_attach; | ||
| 669 | dma_id = dmac->dmaen_num; | ||
| 670 | type = RSND_MOD_AUDMA; | ||
| 671 | } | ||
| 637 | 672 | ||
| 638 | /* for Gen1, overwrite */ | 673 | /* for Gen1, overwrite */ |
| 639 | if (rsnd_is_gen1(priv)) | 674 | if (rsnd_is_gen1(priv)) { |
| 640 | dma->ops = &rsnd_dmaen_ops; | 675 | ops = &rsnd_dmaen_ops; |
| 676 | attach = rsnd_dmaen_attach; | ||
| 677 | dma_id = dmac->dmaen_num; | ||
| 678 | type = RSND_MOD_AUDMA; | ||
| 679 | } | ||
| 680 | |||
| 681 | dma_mod = rsnd_mod_get(dma); | ||
| 682 | |||
| 683 | ret = rsnd_mod_init(priv, dma_mod, | ||
| 684 | ops, NULL, type, dma_id); | ||
| 685 | if (ret < 0) | ||
| 686 | return ERR_PTR(ret); | ||
| 641 | 687 | ||
| 642 | dev_dbg(dev, "%s %s[%d] -> %s[%d]\n", | 688 | dev_dbg(dev, "%s[%d] %s[%d] -> %s[%d]\n", |
| 643 | dma->ops->name, | 689 | rsnd_mod_name(dma_mod), rsnd_mod_id(dma_mod), |
| 644 | rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), | 690 | rsnd_mod_name(mod_from), rsnd_mod_id(mod_from), |
| 645 | rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); | 691 | rsnd_mod_name(mod_to), rsnd_mod_id(mod_to)); |
| 646 | 692 | ||
| 647 | return dma->ops->init(io, dma, id, mod_from, mod_to); | 693 | ret = attach(io, dma, id, mod_from, mod_to); |
| 694 | if (ret < 0) | ||
| 695 | return ERR_PTR(ret); | ||
| 696 | |||
| 697 | ret = rsnd_dai_connect(dma_mod, io, type); | ||
| 698 | if (ret < 0) | ||
| 699 | return ERR_PTR(ret); | ||
| 700 | |||
| 701 | return rsnd_mod_get(dma); | ||
| 648 | } | 702 | } |
| 649 | 703 | ||
| 650 | int rsnd_dma_probe(struct platform_device *pdev, | 704 | int rsnd_dma_probe(struct rsnd_priv *priv) |
| 651 | const struct rsnd_of_data *of_data, | ||
| 652 | struct rsnd_priv *priv) | ||
| 653 | { | 705 | { |
| 706 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); | ||
| 654 | struct device *dev = rsnd_priv_to_dev(priv); | 707 | struct device *dev = rsnd_priv_to_dev(priv); |
| 655 | struct rsnd_dma_ctrl *dmac; | 708 | struct rsnd_dma_ctrl *dmac; |
| 656 | struct resource *res; | 709 | struct resource *res; |
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c index 58f690900e6d..d45ffe496397 100644 --- a/sound/soc/sh/rcar/dvc.c +++ b/sound/soc/sh/rcar/dvc.c | |||
| @@ -15,7 +15,6 @@ | |||
| 15 | #define DVC_NAME "dvc" | 15 | #define DVC_NAME "dvc" |
| 16 | 16 | ||
| 17 | struct rsnd_dvc { | 17 | struct rsnd_dvc { |
| 18 | struct rsnd_dvc_platform_info *info; /* rcar_snd.h */ | ||
| 19 | struct rsnd_mod mod; | 18 | struct rsnd_mod mod; |
| 20 | struct rsnd_kctrl_cfg_m volume; | 19 | struct rsnd_kctrl_cfg_m volume; |
| 21 | struct rsnd_kctrl_cfg_m mute; | 20 | struct rsnd_kctrl_cfg_m mute; |
| @@ -24,6 +23,7 @@ struct rsnd_dvc { | |||
| 24 | struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ | 23 | struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */ |
| 25 | }; | 24 | }; |
| 26 | 25 | ||
| 26 | #define rsnd_dvc_get(priv, id) ((struct rsnd_dvc *)(priv->dvc) + id) | ||
| 27 | #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) | 27 | #define rsnd_dvc_nr(priv) ((priv)->dvc_nr) |
| 28 | #define rsnd_dvc_of_node(priv) \ | 28 | #define rsnd_dvc_of_node(priv) \ |
| 29 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") | 29 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") |
| @@ -64,79 +64,142 @@ static const char * const dvc_ramp_rate[] = { | |||
| 64 | "0.125 dB/8192 steps", /* 10111 */ | 64 | "0.125 dB/8192 steps", /* 10111 */ |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | static void rsnd_dvc_soft_reset(struct rsnd_mod *mod) | 67 | static void rsnd_dvc_activation(struct rsnd_mod *mod) |
| 68 | { | 68 | { |
| 69 | rsnd_mod_write(mod, DVC_SWRSR, 0); | 69 | rsnd_mod_write(mod, DVC_SWRSR, 0); |
| 70 | rsnd_mod_write(mod, DVC_SWRSR, 1); | 70 | rsnd_mod_write(mod, DVC_SWRSR, 1); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | #define rsnd_dvc_initialize_lock(mod) __rsnd_dvc_initialize_lock(mod, 1) | 73 | static void rsnd_dvc_halt(struct rsnd_mod *mod) |
| 74 | #define rsnd_dvc_initialize_unlock(mod) __rsnd_dvc_initialize_lock(mod, 0) | ||
| 75 | static void __rsnd_dvc_initialize_lock(struct rsnd_mod *mod, u32 enable) | ||
| 76 | { | 74 | { |
| 77 | rsnd_mod_write(mod, DVC_DVUIR, enable); | 75 | rsnd_mod_write(mod, DVC_DVUIR, 1); |
| 76 | rsnd_mod_write(mod, DVC_SWRSR, 0); | ||
| 78 | } | 77 | } |
| 79 | 78 | ||
| 80 | static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, | 79 | #define rsnd_dvc_get_vrpdr(dvc) (dvc->rup.val << 8 | dvc->rdown.val) |
| 81 | struct rsnd_mod *mod) | 80 | #define rsnd_dvc_get_vrdbr(dvc) (0x3ff - (dvc->volume.val[0] >> 13)) |
| 81 | |||
| 82 | static void rsnd_dvc_volume_parameter(struct rsnd_dai_stream *io, | ||
| 83 | struct rsnd_mod *mod) | ||
| 82 | { | 84 | { |
| 83 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 85 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
| 84 | u32 val[RSND_DVC_CHANNELS]; | 86 | u32 val[RSND_DVC_CHANNELS]; |
| 85 | u32 dvucr = 0; | ||
| 86 | u32 mute = 0; | ||
| 87 | int i; | 87 | int i; |
| 88 | 88 | ||
| 89 | for (i = 0; i < dvc->mute.cfg.size; i++) | 89 | /* Enable Ramp */ |
| 90 | mute |= (!!dvc->mute.cfg.val[i]) << i; | 90 | if (dvc->ren.val) |
| 91 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
| 92 | val[i] = dvc->volume.cfg.max; | ||
| 93 | else | ||
| 94 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
| 95 | val[i] = dvc->volume.val[i]; | ||
| 91 | 96 | ||
| 92 | /* Disable DVC Register access */ | 97 | /* Enable Digital Volume */ |
| 93 | rsnd_mod_write(mod, DVC_DVUER, 0); | 98 | rsnd_mod_write(mod, DVC_VOL0R, val[0]); |
| 99 | rsnd_mod_write(mod, DVC_VOL1R, val[1]); | ||
| 100 | rsnd_mod_write(mod, DVC_VOL2R, val[2]); | ||
| 101 | rsnd_mod_write(mod, DVC_VOL3R, val[3]); | ||
| 102 | rsnd_mod_write(mod, DVC_VOL4R, val[4]); | ||
| 103 | rsnd_mod_write(mod, DVC_VOL5R, val[5]); | ||
| 104 | rsnd_mod_write(mod, DVC_VOL6R, val[6]); | ||
| 105 | rsnd_mod_write(mod, DVC_VOL7R, val[7]); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void rsnd_dvc_volume_init(struct rsnd_dai_stream *io, | ||
| 109 | struct rsnd_mod *mod) | ||
| 110 | { | ||
| 111 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
| 112 | u32 adinr = 0; | ||
| 113 | u32 dvucr = 0; | ||
| 114 | u32 vrctr = 0; | ||
| 115 | u32 vrpdr = 0; | ||
| 116 | u32 vrdbr = 0; | ||
| 117 | |||
| 118 | adinr = rsnd_get_adinr_bit(mod, io) | | ||
| 119 | rsnd_get_adinr_chan(mod, io); | ||
| 120 | |||
| 121 | /* Enable Digital Volume, Zero Cross Mute Mode */ | ||
| 122 | dvucr |= 0x101; | ||
| 94 | 123 | ||
| 95 | /* Enable Ramp */ | 124 | /* Enable Ramp */ |
| 96 | if (dvc->ren.val) { | 125 | if (dvc->ren.val) { |
| 97 | dvucr |= 0x10; | 126 | dvucr |= 0x10; |
| 98 | 127 | ||
| 99 | /* Digital Volume Max */ | ||
| 100 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
| 101 | val[i] = dvc->volume.cfg.max; | ||
| 102 | |||
| 103 | rsnd_mod_write(mod, DVC_VRCTR, 0xff); | ||
| 104 | rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 | | ||
| 105 | dvc->rdown.val); | ||
| 106 | /* | 128 | /* |
| 107 | * FIXME !! | 129 | * FIXME !! |
| 108 | * use scale-downed Digital Volume | 130 | * use scale-downed Digital Volume |
| 109 | * as Volume Ramp | 131 | * as Volume Ramp |
| 110 | * 7F FFFF -> 3FF | 132 | * 7F FFFF -> 3FF |
| 111 | */ | 133 | */ |
| 112 | rsnd_mod_write(mod, DVC_VRDBR, | 134 | vrctr = 0xff; |
| 113 | 0x3ff - (dvc->volume.val[0] >> 13)); | 135 | vrpdr = rsnd_dvc_get_vrpdr(dvc); |
| 114 | 136 | vrdbr = rsnd_dvc_get_vrdbr(dvc); | |
| 115 | } else { | ||
| 116 | for (i = 0; i < RSND_DVC_CHANNELS; i++) | ||
| 117 | val[i] = dvc->volume.val[i]; | ||
| 118 | } | 137 | } |
| 119 | 138 | ||
| 120 | /* Enable Digital Volume */ | 139 | /* Initialize operation */ |
| 121 | dvucr |= 0x100; | 140 | rsnd_mod_write(mod, DVC_DVUIR, 1); |
| 122 | rsnd_mod_write(mod, DVC_VOL0R, val[0]); | 141 | |
| 123 | rsnd_mod_write(mod, DVC_VOL1R, val[1]); | 142 | /* General Information */ |
| 143 | rsnd_mod_write(mod, DVC_ADINR, adinr); | ||
| 144 | rsnd_mod_write(mod, DVC_DVUCR, dvucr); | ||
| 145 | |||
| 146 | /* Volume Ramp Parameter */ | ||
| 147 | rsnd_mod_write(mod, DVC_VRCTR, vrctr); | ||
| 148 | rsnd_mod_write(mod, DVC_VRPDR, vrpdr); | ||
| 149 | rsnd_mod_write(mod, DVC_VRDBR, vrdbr); | ||
| 150 | |||
| 151 | /* Digital Volume Function Parameter */ | ||
| 152 | rsnd_dvc_volume_parameter(io, mod); | ||
| 153 | |||
| 154 | /* cancel operation */ | ||
| 155 | rsnd_mod_write(mod, DVC_DVUIR, 0); | ||
| 156 | } | ||
| 157 | |||
| 158 | static void rsnd_dvc_volume_update(struct rsnd_dai_stream *io, | ||
| 159 | struct rsnd_mod *mod) | ||
| 160 | { | ||
| 161 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | ||
| 162 | u32 zcmcr = 0; | ||
| 163 | u32 vrpdr = 0; | ||
| 164 | u32 vrdbr = 0; | ||
| 165 | int i; | ||
| 166 | |||
| 167 | for (i = 0; i < dvc->mute.cfg.size; i++) | ||
| 168 | zcmcr |= (!!dvc->mute.cfg.val[i]) << i; | ||
| 124 | 169 | ||
| 125 | /* Enable Mute */ | 170 | if (dvc->ren.val) { |
| 126 | if (mute) { | 171 | vrpdr = rsnd_dvc_get_vrpdr(dvc); |
| 127 | dvucr |= 0x1; | 172 | vrdbr = rsnd_dvc_get_vrdbr(dvc); |
| 128 | rsnd_mod_write(mod, DVC_ZCMCR, mute); | ||
| 129 | } | 173 | } |
| 130 | 174 | ||
| 131 | rsnd_mod_write(mod, DVC_DVUCR, dvucr); | 175 | /* Disable DVC Register access */ |
| 176 | rsnd_mod_write(mod, DVC_DVUER, 0); | ||
| 177 | |||
| 178 | /* Zero Cross Mute Function */ | ||
| 179 | rsnd_mod_write(mod, DVC_ZCMCR, zcmcr); | ||
| 180 | |||
| 181 | /* Volume Ramp Function */ | ||
| 182 | rsnd_mod_write(mod, DVC_VRPDR, vrpdr); | ||
| 183 | rsnd_mod_write(mod, DVC_VRDBR, vrdbr); | ||
| 184 | /* add DVC_VRWTR here */ | ||
| 185 | |||
| 186 | /* Digital Volume Function Parameter */ | ||
| 187 | rsnd_dvc_volume_parameter(io, mod); | ||
| 132 | 188 | ||
| 133 | /* Enable DVC Register access */ | 189 | /* Enable DVC Register access */ |
| 134 | rsnd_mod_write(mod, DVC_DVUER, 1); | 190 | rsnd_mod_write(mod, DVC_DVUER, 1); |
| 135 | } | 191 | } |
| 136 | 192 | ||
| 137 | static int rsnd_dvc_remove_gen2(struct rsnd_mod *mod, | 193 | static int rsnd_dvc_probe_(struct rsnd_mod *mod, |
| 138 | struct rsnd_dai_stream *io, | 194 | struct rsnd_dai_stream *io, |
| 139 | struct rsnd_priv *priv) | 195 | struct rsnd_priv *priv) |
| 196 | { | ||
| 197 | return rsnd_cmd_attach(io, rsnd_mod_id(mod)); | ||
| 198 | } | ||
| 199 | |||
| 200 | static int rsnd_dvc_remove_(struct rsnd_mod *mod, | ||
| 201 | struct rsnd_dai_stream *io, | ||
| 202 | struct rsnd_priv *priv) | ||
| 140 | { | 203 | { |
| 141 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 204 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
| 142 | 205 | ||
| @@ -155,19 +218,12 @@ static int rsnd_dvc_init(struct rsnd_mod *mod, | |||
| 155 | { | 218 | { |
| 156 | rsnd_mod_power_on(mod); | 219 | rsnd_mod_power_on(mod); |
| 157 | 220 | ||
| 158 | rsnd_dvc_soft_reset(mod); | 221 | rsnd_dvc_activation(mod); |
| 159 | |||
| 160 | rsnd_dvc_initialize_lock(mod); | ||
| 161 | |||
| 162 | rsnd_path_parse(priv, io); | ||
| 163 | 222 | ||
| 164 | rsnd_mod_write(mod, DVC_ADINR, rsnd_get_adinr_bit(mod, io)); | 223 | rsnd_dvc_volume_init(io, mod); |
| 165 | 224 | ||
| 166 | /* ch0/ch1 Volume */ | ||
| 167 | rsnd_dvc_volume_update(io, mod); | 225 | rsnd_dvc_volume_update(io, mod); |
| 168 | 226 | ||
| 169 | rsnd_adg_set_cmd_timsel_gen2(mod, io); | ||
| 170 | |||
| 171 | return 0; | 227 | return 0; |
| 172 | } | 228 | } |
| 173 | 229 | ||
| @@ -175,27 +231,9 @@ static int rsnd_dvc_quit(struct rsnd_mod *mod, | |||
| 175 | struct rsnd_dai_stream *io, | 231 | struct rsnd_dai_stream *io, |
| 176 | struct rsnd_priv *priv) | 232 | struct rsnd_priv *priv) |
| 177 | { | 233 | { |
| 178 | rsnd_mod_power_off(mod); | 234 | rsnd_dvc_halt(mod); |
| 179 | 235 | ||
| 180 | return 0; | 236 | rsnd_mod_power_off(mod); |
| 181 | } | ||
| 182 | |||
| 183 | static int rsnd_dvc_start(struct rsnd_mod *mod, | ||
| 184 | struct rsnd_dai_stream *io, | ||
| 185 | struct rsnd_priv *priv) | ||
| 186 | { | ||
| 187 | rsnd_dvc_initialize_unlock(mod); | ||
| 188 | |||
| 189 | rsnd_mod_write(mod, CMD_CTRL, 0x10); | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int rsnd_dvc_stop(struct rsnd_mod *mod, | ||
| 195 | struct rsnd_dai_stream *io, | ||
| 196 | struct rsnd_priv *priv) | ||
| 197 | { | ||
| 198 | rsnd_mod_write(mod, CMD_CTRL, 0); | ||
| 199 | 237 | ||
| 200 | return 0; | 238 | return 0; |
| 201 | } | 239 | } |
| @@ -206,6 +244,7 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
| 206 | { | 244 | { |
| 207 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); | 245 | struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod); |
| 208 | int is_play = rsnd_io_is_play(io); | 246 | int is_play = rsnd_io_is_play(io); |
| 247 | int slots = rsnd_get_slot(io); | ||
| 209 | int ret; | 248 | int ret; |
| 210 | 249 | ||
| 211 | /* Volume */ | 250 | /* Volume */ |
| @@ -213,7 +252,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
| 213 | is_play ? | 252 | is_play ? |
| 214 | "DVC Out Playback Volume" : "DVC In Capture Volume", | 253 | "DVC Out Playback Volume" : "DVC In Capture Volume", |
| 215 | rsnd_dvc_volume_update, | 254 | rsnd_dvc_volume_update, |
| 216 | &dvc->volume, 0x00800000 - 1); | 255 | &dvc->volume, slots, |
| 256 | 0x00800000 - 1); | ||
| 217 | if (ret < 0) | 257 | if (ret < 0) |
| 218 | return ret; | 258 | return ret; |
| 219 | 259 | ||
| @@ -222,7 +262,8 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod, | |||
| 222 | is_play ? | 262 | is_play ? |
| 223 | "DVC Out Mute Switch" : "DVC In Mute Switch", | 263 | "DVC Out Mute Switch" : "DVC In Mute Switch", |
| 224 | rsnd_dvc_volume_update, | 264 | rsnd_dvc_volume_update, |
| 225 | &dvc->mute, 1); | 265 | &dvc->mute, slots, |
| 266 | 1); | ||
| 226 | if (ret < 0) | 267 | if (ret < 0) |
| 227 | return ret; | 268 | return ret; |
| 228 | 269 | ||
| @@ -269,11 +310,10 @@ static struct dma_chan *rsnd_dvc_dma_req(struct rsnd_dai_stream *io, | |||
| 269 | static struct rsnd_mod_ops rsnd_dvc_ops = { | 310 | static struct rsnd_mod_ops rsnd_dvc_ops = { |
| 270 | .name = DVC_NAME, | 311 | .name = DVC_NAME, |
| 271 | .dma_req = rsnd_dvc_dma_req, | 312 | .dma_req = rsnd_dvc_dma_req, |
| 272 | .remove = rsnd_dvc_remove_gen2, | 313 | .probe = rsnd_dvc_probe_, |
| 314 | .remove = rsnd_dvc_remove_, | ||
| 273 | .init = rsnd_dvc_init, | 315 | .init = rsnd_dvc_init, |
| 274 | .quit = rsnd_dvc_quit, | 316 | .quit = rsnd_dvc_quit, |
| 275 | .start = rsnd_dvc_start, | ||
| 276 | .stop = rsnd_dvc_stop, | ||
| 277 | .pcm_new = rsnd_dvc_pcm_new, | 317 | .pcm_new = rsnd_dvc_pcm_new, |
| 278 | }; | 318 | }; |
| 279 | 319 | ||
| @@ -282,50 +322,13 @@ struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id) | |||
| 282 | if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) | 322 | if (WARN_ON(id < 0 || id >= rsnd_dvc_nr(priv))) |
| 283 | id = 0; | 323 | id = 0; |
| 284 | 324 | ||
| 285 | return rsnd_mod_get((struct rsnd_dvc *)(priv->dvc) + id); | 325 | return rsnd_mod_get(rsnd_dvc_get(priv, id)); |
| 286 | } | 326 | } |
| 287 | 327 | ||
| 288 | static void rsnd_of_parse_dvc(struct platform_device *pdev, | 328 | int rsnd_dvc_probe(struct rsnd_priv *priv) |
| 289 | const struct rsnd_of_data *of_data, | ||
| 290 | struct rsnd_priv *priv) | ||
| 291 | { | 329 | { |
| 292 | struct device_node *node; | 330 | struct device_node *node; |
| 293 | struct rsnd_dvc_platform_info *dvc_info; | 331 | struct device_node *np; |
| 294 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 295 | struct device *dev = &pdev->dev; | ||
| 296 | int nr; | ||
| 297 | |||
| 298 | if (!of_data) | ||
| 299 | return; | ||
| 300 | |||
| 301 | node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc"); | ||
| 302 | if (!node) | ||
| 303 | return; | ||
| 304 | |||
| 305 | nr = of_get_child_count(node); | ||
| 306 | if (!nr) | ||
| 307 | goto rsnd_of_parse_dvc_end; | ||
| 308 | |||
| 309 | dvc_info = devm_kzalloc(dev, | ||
| 310 | sizeof(struct rsnd_dvc_platform_info) * nr, | ||
| 311 | GFP_KERNEL); | ||
| 312 | if (!dvc_info) { | ||
| 313 | dev_err(dev, "dvc info allocation error\n"); | ||
| 314 | goto rsnd_of_parse_dvc_end; | ||
| 315 | } | ||
| 316 | |||
| 317 | info->dvc_info = dvc_info; | ||
| 318 | info->dvc_info_nr = nr; | ||
| 319 | |||
| 320 | rsnd_of_parse_dvc_end: | ||
| 321 | of_node_put(node); | ||
| 322 | } | ||
| 323 | |||
| 324 | int rsnd_dvc_probe(struct platform_device *pdev, | ||
| 325 | const struct rsnd_of_data *of_data, | ||
| 326 | struct rsnd_priv *priv) | ||
| 327 | { | ||
| 328 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 329 | struct device *dev = rsnd_priv_to_dev(priv); | 332 | struct device *dev = rsnd_priv_to_dev(priv); |
| 330 | struct rsnd_dvc *dvc; | 333 | struct rsnd_dvc *dvc; |
| 331 | struct clk *clk; | 334 | struct clk *clk; |
| @@ -336,40 +339,54 @@ int rsnd_dvc_probe(struct platform_device *pdev, | |||
| 336 | if (rsnd_is_gen1(priv)) | 339 | if (rsnd_is_gen1(priv)) |
| 337 | return 0; | 340 | return 0; |
| 338 | 341 | ||
| 339 | rsnd_of_parse_dvc(pdev, of_data, priv); | 342 | node = rsnd_dvc_of_node(priv); |
| 343 | if (!node) | ||
| 344 | return 0; /* not used is not error */ | ||
| 340 | 345 | ||
| 341 | nr = info->dvc_info_nr; | 346 | nr = of_get_child_count(node); |
| 342 | if (!nr) | 347 | if (!nr) { |
| 343 | return 0; | 348 | ret = -EINVAL; |
| 349 | goto rsnd_dvc_probe_done; | ||
| 350 | } | ||
| 344 | 351 | ||
| 345 | dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); | 352 | dvc = devm_kzalloc(dev, sizeof(*dvc) * nr, GFP_KERNEL); |
| 346 | if (!dvc) | 353 | if (!dvc) { |
| 347 | return -ENOMEM; | 354 | ret = -ENOMEM; |
| 355 | goto rsnd_dvc_probe_done; | ||
| 356 | } | ||
| 348 | 357 | ||
| 349 | priv->dvc_nr = nr; | 358 | priv->dvc_nr = nr; |
| 350 | priv->dvc = dvc; | 359 | priv->dvc = dvc; |
| 351 | 360 | ||
| 352 | for_each_rsnd_dvc(dvc, priv, i) { | 361 | i = 0; |
| 362 | ret = 0; | ||
| 363 | for_each_child_of_node(node, np) { | ||
| 364 | dvc = rsnd_dvc_get(priv, i); | ||
| 365 | |||
| 353 | snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", | 366 | snprintf(name, RSND_DVC_NAME_SIZE, "%s.%d", |
| 354 | DVC_NAME, i); | 367 | DVC_NAME, i); |
| 355 | 368 | ||
| 356 | clk = devm_clk_get(dev, name); | 369 | clk = devm_clk_get(dev, name); |
| 357 | if (IS_ERR(clk)) | 370 | if (IS_ERR(clk)) { |
| 358 | return PTR_ERR(clk); | 371 | ret = PTR_ERR(clk); |
| 359 | 372 | goto rsnd_dvc_probe_done; | |
| 360 | dvc->info = &info->dvc_info[i]; | 373 | } |
| 361 | 374 | ||
| 362 | ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, | 375 | ret = rsnd_mod_init(priv, rsnd_mod_get(dvc), &rsnd_dvc_ops, |
| 363 | clk, RSND_MOD_DVC, i); | 376 | clk, RSND_MOD_DVC, i); |
| 364 | if (ret) | 377 | if (ret) |
| 365 | return ret; | 378 | goto rsnd_dvc_probe_done; |
| 379 | |||
| 380 | i++; | ||
| 366 | } | 381 | } |
| 367 | 382 | ||
| 368 | return 0; | 383 | rsnd_dvc_probe_done: |
| 384 | of_node_put(node); | ||
| 385 | |||
| 386 | return ret; | ||
| 369 | } | 387 | } |
| 370 | 388 | ||
| 371 | void rsnd_dvc_remove(struct platform_device *pdev, | 389 | void rsnd_dvc_remove(struct rsnd_priv *priv) |
| 372 | struct rsnd_priv *priv) | ||
| 373 | { | 390 | { |
| 374 | struct rsnd_dvc *dvc; | 391 | struct rsnd_dvc *dvc; |
| 375 | int i; | 392 | int i; |
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c index edcf4cc2e84f..ea24247eba73 100644 --- a/sound/soc/sh/rcar/gen.c +++ b/sound/soc/sh/rcar/gen.c | |||
| @@ -31,29 +31,33 @@ struct rsnd_gen { | |||
| 31 | 31 | ||
| 32 | /* RSND_REG_MAX base */ | 32 | /* RSND_REG_MAX base */ |
| 33 | struct regmap_field *regs[RSND_REG_MAX]; | 33 | struct regmap_field *regs[RSND_REG_MAX]; |
| 34 | const char *reg_name[RSND_REG_MAX]; | ||
| 34 | }; | 35 | }; |
| 35 | 36 | ||
| 36 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) | 37 | #define rsnd_priv_to_gen(p) ((struct rsnd_gen *)(p)->gen) |
| 38 | #define rsnd_reg_name(gen, id) ((gen)->reg_name[id]) | ||
| 37 | 39 | ||
| 38 | struct rsnd_regmap_field_conf { | 40 | struct rsnd_regmap_field_conf { |
| 39 | int idx; | 41 | int idx; |
| 40 | unsigned int reg_offset; | 42 | unsigned int reg_offset; |
| 41 | unsigned int id_offset; | 43 | unsigned int id_offset; |
| 44 | const char *reg_name; | ||
| 42 | }; | 45 | }; |
| 43 | 46 | ||
| 44 | #define RSND_REG_SET(id, offset, _id_offset) \ | 47 | #define RSND_REG_SET(id, offset, _id_offset, n) \ |
| 45 | { \ | 48 | { \ |
| 46 | .idx = id, \ | 49 | .idx = id, \ |
| 47 | .reg_offset = offset, \ | 50 | .reg_offset = offset, \ |
| 48 | .id_offset = _id_offset, \ | 51 | .id_offset = _id_offset, \ |
| 52 | .reg_name = n, \ | ||
| 49 | } | 53 | } |
| 50 | /* single address mapping */ | 54 | /* single address mapping */ |
| 51 | #define RSND_GEN_S_REG(id, offset) \ | 55 | #define RSND_GEN_S_REG(id, offset) \ |
| 52 | RSND_REG_SET(RSND_REG_##id, offset, 0) | 56 | RSND_REG_SET(RSND_REG_##id, offset, 0, #id) |
| 53 | 57 | ||
| 54 | /* multi address mapping */ | 58 | /* multi address mapping */ |
| 55 | #define RSND_GEN_M_REG(id, offset, _id_offset) \ | 59 | #define RSND_GEN_M_REG(id, offset, _id_offset) \ |
| 56 | RSND_REG_SET(RSND_REG_##id, offset, _id_offset) | 60 | RSND_REG_SET(RSND_REG_##id, offset, _id_offset, #id) |
| 57 | 61 | ||
| 58 | /* | 62 | /* |
| 59 | * basic function | 63 | * basic function |
| @@ -83,8 +87,9 @@ u32 rsnd_read(struct rsnd_priv *priv, | |||
| 83 | 87 | ||
| 84 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); | 88 | regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val); |
| 85 | 89 | ||
| 86 | dev_dbg(dev, "r %s[%d] - %4d : %08x\n", | 90 | dev_dbg(dev, "r %s[%d] - %-18s (%4d) : %08x\n", |
| 87 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val); | 91 | rsnd_mod_name(mod), rsnd_mod_id(mod), |
| 92 | rsnd_reg_name(gen, reg), reg, val); | ||
| 88 | 93 | ||
| 89 | return val; | 94 | return val; |
| 90 | } | 95 | } |
| @@ -99,10 +104,11 @@ void rsnd_write(struct rsnd_priv *priv, | |||
| 99 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 104 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
| 100 | return; | 105 | return; |
| 101 | 106 | ||
| 102 | dev_dbg(dev, "w %s[%d] - %4d : %08x\n", | ||
| 103 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); | ||
| 104 | |||
| 105 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); | 107 | regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data); |
| 108 | |||
| 109 | dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", | ||
| 110 | rsnd_mod_name(mod), rsnd_mod_id(mod), | ||
| 111 | rsnd_reg_name(gen, reg), reg, data); | ||
| 106 | } | 112 | } |
| 107 | 113 | ||
| 108 | void rsnd_force_write(struct rsnd_priv *priv, | 114 | void rsnd_force_write(struct rsnd_priv *priv, |
| @@ -115,10 +121,11 @@ void rsnd_force_write(struct rsnd_priv *priv, | |||
| 115 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 121 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
| 116 | return; | 122 | return; |
| 117 | 123 | ||
| 118 | dev_dbg(dev, "w %s[%d] - %4d : %08x\n", | ||
| 119 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data); | ||
| 120 | |||
| 121 | regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); | 124 | regmap_fields_force_write(gen->regs[reg], rsnd_mod_id(mod), data); |
| 125 | |||
| 126 | dev_dbg(dev, "w %s[%d] - %-18s (%4d) : %08x\n", | ||
| 127 | rsnd_mod_name(mod), rsnd_mod_id(mod), | ||
| 128 | rsnd_reg_name(gen, reg), reg, data); | ||
| 122 | } | 129 | } |
| 123 | 130 | ||
| 124 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | 131 | void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, |
| @@ -130,11 +137,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, | |||
| 130 | if (!rsnd_is_accessible_reg(priv, gen, reg)) | 137 | if (!rsnd_is_accessible_reg(priv, gen, reg)) |
| 131 | return; | 138 | return; |
| 132 | 139 | ||
| 133 | dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n", | ||
| 134 | rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask); | ||
| 135 | |||
| 136 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), | 140 | regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod), |
| 137 | mask, data); | 141 | mask, data); |
| 142 | |||
| 143 | dev_dbg(dev, "b %s[%d] - %-18s (%4d) : %08x/%08x\n", | ||
| 144 | rsnd_mod_name(mod), rsnd_mod_id(mod), | ||
| 145 | rsnd_reg_name(gen, reg), reg, data, mask); | ||
| 146 | |||
| 138 | } | 147 | } |
| 139 | 148 | ||
| 140 | phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) | 149 | phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id) |
| @@ -150,7 +159,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
| 150 | int id_size, | 159 | int id_size, |
| 151 | int reg_id, | 160 | int reg_id, |
| 152 | const char *name, | 161 | const char *name, |
| 153 | struct rsnd_regmap_field_conf *conf, | 162 | const struct rsnd_regmap_field_conf *conf, |
| 154 | int conf_size) | 163 | int conf_size) |
| 155 | { | 164 | { |
| 156 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); | 165 | struct platform_device *pdev = rsnd_priv_to_pdev(priv); |
| @@ -203,6 +212,7 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
| 203 | 212 | ||
| 204 | /* RSND_REG_MAX base */ | 213 | /* RSND_REG_MAX base */ |
| 205 | gen->regs[conf[i].idx] = regs; | 214 | gen->regs[conf[i].idx] = regs; |
| 215 | gen->reg_name[conf[i].idx] = conf[i].reg_name; | ||
| 206 | } | 216 | } |
| 207 | 217 | ||
| 208 | return 0; | 218 | return 0; |
| @@ -211,25 +221,31 @@ static int _rsnd_gen_regmap_init(struct rsnd_priv *priv, | |||
| 211 | /* | 221 | /* |
| 212 | * Gen2 | 222 | * Gen2 |
| 213 | */ | 223 | */ |
| 214 | static int rsnd_gen2_probe(struct platform_device *pdev, | 224 | static int rsnd_gen2_probe(struct rsnd_priv *priv) |
| 215 | struct rsnd_priv *priv) | ||
| 216 | { | 225 | { |
| 217 | struct rsnd_regmap_field_conf conf_ssiu[] = { | 226 | const static struct rsnd_regmap_field_conf conf_ssiu[] = { |
| 218 | RSND_GEN_S_REG(SSI_MODE0, 0x800), | 227 | RSND_GEN_S_REG(SSI_MODE0, 0x800), |
| 219 | RSND_GEN_S_REG(SSI_MODE1, 0x804), | 228 | RSND_GEN_S_REG(SSI_MODE1, 0x804), |
| 229 | RSND_GEN_S_REG(SSI_MODE2, 0x808), | ||
| 230 | RSND_GEN_S_REG(SSI_CONTROL, 0x810), | ||
| 231 | |||
| 220 | /* FIXME: it needs SSI_MODE2/3 in the future */ | 232 | /* FIXME: it needs SSI_MODE2/3 in the future */ |
| 221 | RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), | 233 | RSND_GEN_M_REG(SSI_BUSIF_MODE, 0x0, 0x80), |
| 222 | RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), | 234 | RSND_GEN_M_REG(SSI_BUSIF_ADINR, 0x4, 0x80), |
| 223 | RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), | 235 | RSND_GEN_M_REG(SSI_BUSIF_DALIGN,0x8, 0x80), |
| 236 | RSND_GEN_M_REG(SSI_MODE, 0xc, 0x80), | ||
| 224 | RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), | 237 | RSND_GEN_M_REG(SSI_CTRL, 0x10, 0x80), |
| 225 | RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), | 238 | RSND_GEN_M_REG(SSI_INT_ENABLE, 0x18, 0x80), |
| 226 | }; | 239 | }; |
| 227 | struct rsnd_regmap_field_conf conf_scu[] = { | 240 | |
| 228 | RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x0, 0x20), | 241 | const static struct rsnd_regmap_field_conf conf_scu[] = { |
| 242 | RSND_GEN_M_REG(SRC_I_BUSIF_MODE,0x0, 0x20), | ||
| 243 | RSND_GEN_M_REG(SRC_O_BUSIF_MODE,0x4, 0x20), | ||
| 229 | RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), | 244 | RSND_GEN_M_REG(SRC_BUSIF_DALIGN,0x8, 0x20), |
| 230 | RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), | 245 | RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0xc, 0x20), |
| 231 | RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), | 246 | RSND_GEN_M_REG(SRC_CTRL, 0x10, 0x20), |
| 232 | RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), | 247 | RSND_GEN_M_REG(SRC_INT_ENABLE0, 0x18, 0x20), |
| 248 | RSND_GEN_M_REG(CMD_BUSIF_DALIGN,0x188, 0x20), | ||
| 233 | RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), | 249 | RSND_GEN_M_REG(CMD_ROUTE_SLCT, 0x18c, 0x20), |
| 234 | RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), | 250 | RSND_GEN_M_REG(CMD_CTRL, 0x190, 0x20), |
| 235 | RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), | 251 | RSND_GEN_S_REG(SCU_SYS_STATUS0, 0x1c8), |
| @@ -266,9 +282,15 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
| 266 | RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), | 282 | RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100), |
| 267 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), | 283 | RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100), |
| 268 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), | 284 | RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100), |
| 285 | RSND_GEN_M_REG(DVC_VOL2R, 0xe30, 0x100), | ||
| 286 | RSND_GEN_M_REG(DVC_VOL3R, 0xe34, 0x100), | ||
| 287 | RSND_GEN_M_REG(DVC_VOL4R, 0xe38, 0x100), | ||
| 288 | RSND_GEN_M_REG(DVC_VOL5R, 0xe3c, 0x100), | ||
| 289 | RSND_GEN_M_REG(DVC_VOL6R, 0xe40, 0x100), | ||
| 290 | RSND_GEN_M_REG(DVC_VOL7R, 0xe44, 0x100), | ||
| 269 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), | 291 | RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100), |
| 270 | }; | 292 | }; |
| 271 | struct rsnd_regmap_field_conf conf_adg[] = { | 293 | const static struct rsnd_regmap_field_conf conf_adg[] = { |
| 272 | RSND_GEN_S_REG(BRRA, 0x00), | 294 | RSND_GEN_S_REG(BRRA, 0x00), |
| 273 | RSND_GEN_S_REG(BRRB, 0x04), | 295 | RSND_GEN_S_REG(BRRB, 0x04), |
| 274 | RSND_GEN_S_REG(SSICKR, 0x08), | 296 | RSND_GEN_S_REG(SSICKR, 0x08), |
| @@ -288,7 +310,7 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
| 288 | RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), | 310 | RSND_GEN_S_REG(SRCOUT_TIMSEL4, 0x58), |
| 289 | RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), | 311 | RSND_GEN_S_REG(CMDOUT_TIMSEL, 0x5c), |
| 290 | }; | 312 | }; |
| 291 | struct rsnd_regmap_field_conf conf_ssi[] = { | 313 | const static struct rsnd_regmap_field_conf conf_ssi[] = { |
| 292 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | 314 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), |
| 293 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | 315 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), |
| 294 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | 316 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), |
| @@ -317,65 +339,30 @@ static int rsnd_gen2_probe(struct platform_device *pdev, | |||
| 317 | * Gen1 | 339 | * Gen1 |
| 318 | */ | 340 | */ |
| 319 | 341 | ||
| 320 | static int rsnd_gen1_probe(struct platform_device *pdev, | 342 | static int rsnd_gen1_probe(struct rsnd_priv *priv) |
| 321 | struct rsnd_priv *priv) | ||
| 322 | { | 343 | { |
| 323 | struct rsnd_regmap_field_conf conf_sru[] = { | 344 | const static struct rsnd_regmap_field_conf conf_adg[] = { |
| 324 | RSND_GEN_S_REG(SRC_ROUTE_SEL, 0x00), | ||
| 325 | RSND_GEN_S_REG(SRC_TMG_SEL0, 0x08), | ||
| 326 | RSND_GEN_S_REG(SRC_TMG_SEL1, 0x0c), | ||
| 327 | RSND_GEN_S_REG(SRC_TMG_SEL2, 0x10), | ||
| 328 | RSND_GEN_S_REG(SRC_ROUTE_CTRL, 0xc0), | ||
| 329 | RSND_GEN_S_REG(SSI_MODE0, 0xD0), | ||
| 330 | RSND_GEN_S_REG(SSI_MODE1, 0xD4), | ||
| 331 | RSND_GEN_M_REG(SRC_BUSIF_MODE, 0x20, 0x4), | ||
| 332 | RSND_GEN_M_REG(SRC_ROUTE_MODE0, 0x50, 0x8), | ||
| 333 | RSND_GEN_M_REG(SRC_SWRSR, 0x200, 0x40), | ||
| 334 | RSND_GEN_M_REG(SRC_SRCIR, 0x204, 0x40), | ||
| 335 | RSND_GEN_M_REG(SRC_ADINR, 0x214, 0x40), | ||
| 336 | RSND_GEN_M_REG(SRC_IFSCR, 0x21c, 0x40), | ||
| 337 | RSND_GEN_M_REG(SRC_IFSVR, 0x220, 0x40), | ||
| 338 | RSND_GEN_M_REG(SRC_SRCCR, 0x224, 0x40), | ||
| 339 | RSND_GEN_M_REG(SRC_MNFSR, 0x228, 0x40), | ||
| 340 | /* | ||
| 341 | * ADD US | ||
| 342 | * | ||
| 343 | * SRC_STATUS | ||
| 344 | * SRC_INT_EN | ||
| 345 | * SCU_SYS_STATUS0 | ||
| 346 | * SCU_SYS_STATUS1 | ||
| 347 | * SCU_SYS_INT_EN0 | ||
| 348 | * SCU_SYS_INT_EN1 | ||
| 349 | */ | ||
| 350 | }; | ||
| 351 | struct rsnd_regmap_field_conf conf_adg[] = { | ||
| 352 | RSND_GEN_S_REG(BRRA, 0x00), | 345 | RSND_GEN_S_REG(BRRA, 0x00), |
| 353 | RSND_GEN_S_REG(BRRB, 0x04), | 346 | RSND_GEN_S_REG(BRRB, 0x04), |
| 354 | RSND_GEN_S_REG(SSICKR, 0x08), | 347 | RSND_GEN_S_REG(SSICKR, 0x08), |
| 355 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), | 348 | RSND_GEN_S_REG(AUDIO_CLK_SEL0, 0x0c), |
| 356 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), | 349 | RSND_GEN_S_REG(AUDIO_CLK_SEL1, 0x10), |
| 357 | RSND_GEN_S_REG(AUDIO_CLK_SEL3, 0x18), | ||
| 358 | RSND_GEN_S_REG(AUDIO_CLK_SEL4, 0x1c), | ||
| 359 | RSND_GEN_S_REG(AUDIO_CLK_SEL5, 0x20), | ||
| 360 | }; | 350 | }; |
| 361 | struct rsnd_regmap_field_conf conf_ssi[] = { | 351 | const static struct rsnd_regmap_field_conf conf_ssi[] = { |
| 362 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), | 352 | RSND_GEN_M_REG(SSICR, 0x00, 0x40), |
| 363 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), | 353 | RSND_GEN_M_REG(SSISR, 0x04, 0x40), |
| 364 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), | 354 | RSND_GEN_M_REG(SSITDR, 0x08, 0x40), |
| 365 | RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), | 355 | RSND_GEN_M_REG(SSIRDR, 0x0c, 0x40), |
| 366 | RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), | 356 | RSND_GEN_M_REG(SSIWSR, 0x20, 0x40), |
| 367 | }; | 357 | }; |
| 368 | int ret_sru; | ||
| 369 | int ret_adg; | 358 | int ret_adg; |
| 370 | int ret_ssi; | 359 | int ret_ssi; |
| 371 | 360 | ||
| 372 | ret_sru = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SRU, "sru", conf_sru); | ||
| 373 | ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); | 361 | ret_adg = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_ADG, "adg", conf_adg); |
| 374 | ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); | 362 | ret_ssi = rsnd_gen_regmap_init(priv, 9, RSND_GEN1_SSI, "ssi", conf_ssi); |
| 375 | if (ret_sru < 0 || | 363 | if (ret_adg < 0 || |
| 376 | ret_adg < 0 || | ||
| 377 | ret_ssi < 0) | 364 | ret_ssi < 0) |
| 378 | return ret_sru | ret_adg | ret_ssi; | 365 | return ret_adg | ret_ssi; |
| 379 | 366 | ||
| 380 | return 0; | 367 | return 0; |
| 381 | } | 368 | } |
| @@ -383,28 +370,12 @@ static int rsnd_gen1_probe(struct platform_device *pdev, | |||
| 383 | /* | 370 | /* |
| 384 | * Gen | 371 | * Gen |
| 385 | */ | 372 | */ |
| 386 | static void rsnd_of_parse_gen(struct platform_device *pdev, | 373 | int rsnd_gen_probe(struct rsnd_priv *priv) |
| 387 | const struct rsnd_of_data *of_data, | ||
| 388 | struct rsnd_priv *priv) | ||
| 389 | { | ||
| 390 | struct rcar_snd_info *info = priv->info; | ||
| 391 | |||
| 392 | if (!of_data) | ||
| 393 | return; | ||
| 394 | |||
| 395 | info->flags = of_data->flags; | ||
| 396 | } | ||
| 397 | |||
| 398 | int rsnd_gen_probe(struct platform_device *pdev, | ||
| 399 | const struct rsnd_of_data *of_data, | ||
| 400 | struct rsnd_priv *priv) | ||
| 401 | { | 374 | { |
| 402 | struct device *dev = rsnd_priv_to_dev(priv); | 375 | struct device *dev = rsnd_priv_to_dev(priv); |
| 403 | struct rsnd_gen *gen; | 376 | struct rsnd_gen *gen; |
| 404 | int ret; | 377 | int ret; |
| 405 | 378 | ||
| 406 | rsnd_of_parse_gen(pdev, of_data, priv); | ||
| 407 | |||
| 408 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); | 379 | gen = devm_kzalloc(dev, sizeof(*gen), GFP_KERNEL); |
| 409 | if (!gen) { | 380 | if (!gen) { |
| 410 | dev_err(dev, "GEN allocate failed\n"); | 381 | dev_err(dev, "GEN allocate failed\n"); |
| @@ -415,9 +386,9 @@ int rsnd_gen_probe(struct platform_device *pdev, | |||
| 415 | 386 | ||
| 416 | ret = -ENODEV; | 387 | ret = -ENODEV; |
| 417 | if (rsnd_is_gen1(priv)) | 388 | if (rsnd_is_gen1(priv)) |
| 418 | ret = rsnd_gen1_probe(pdev, priv); | 389 | ret = rsnd_gen1_probe(priv); |
| 419 | else if (rsnd_is_gen2(priv)) | 390 | else if (rsnd_is_gen2(priv)) |
| 420 | ret = rsnd_gen2_probe(pdev, priv); | 391 | ret = rsnd_gen2_probe(priv); |
| 421 | 392 | ||
| 422 | if (ret < 0) | 393 | if (ret < 0) |
| 423 | dev_err(dev, "unknown generation R-Car sound device\n"); | 394 | dev_err(dev, "unknown generation R-Car sound device\n"); |
diff --git a/sound/soc/sh/rcar/mix.c b/sound/soc/sh/rcar/mix.c index 953dd0be9b60..65542b6a89e9 100644 --- a/sound/soc/sh/rcar/mix.c +++ b/sound/soc/sh/rcar/mix.c | |||
| @@ -13,10 +13,10 @@ | |||
| 13 | #define MIX_NAME "mix" | 13 | #define MIX_NAME "mix" |
| 14 | 14 | ||
| 15 | struct rsnd_mix { | 15 | struct rsnd_mix { |
| 16 | struct rsnd_mix_platform_info *info; /* rcar_snd.h */ | ||
| 17 | struct rsnd_mod mod; | 16 | struct rsnd_mod mod; |
| 18 | }; | 17 | }; |
| 19 | 18 | ||
| 19 | #define rsnd_mix_get(priv, id) ((struct rsnd_mix *)(priv->mix) + id) | ||
| 20 | #define rsnd_mix_nr(priv) ((priv)->mix_nr) | 20 | #define rsnd_mix_nr(priv) ((priv)->mix_nr) |
| 21 | #define for_each_rsnd_mix(pos, priv, i) \ | 21 | #define for_each_rsnd_mix(pos, priv, i) \ |
| 22 | for ((i) = 0; \ | 22 | for ((i) = 0; \ |
| @@ -24,58 +24,77 @@ struct rsnd_mix { | |||
| 24 | ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ | 24 | ((pos) = (struct rsnd_mix *)(priv)->mix + i); \ |
| 25 | i++) | 25 | i++) |
| 26 | 26 | ||
| 27 | 27 | static void rsnd_mix_activation(struct rsnd_mod *mod) | |
| 28 | static void rsnd_mix_soft_reset(struct rsnd_mod *mod) | ||
| 29 | { | 28 | { |
| 30 | rsnd_mod_write(mod, MIX_SWRSR, 0); | 29 | rsnd_mod_write(mod, MIX_SWRSR, 0); |
| 31 | rsnd_mod_write(mod, MIX_SWRSR, 1); | 30 | rsnd_mod_write(mod, MIX_SWRSR, 1); |
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | #define rsnd_mix_initialize_lock(mod) __rsnd_mix_initialize_lock(mod, 1) | 33 | static void rsnd_mix_halt(struct rsnd_mod *mod) |
| 35 | #define rsnd_mix_initialize_unlock(mod) __rsnd_mix_initialize_lock(mod, 0) | 34 | { |
| 36 | static void __rsnd_mix_initialize_lock(struct rsnd_mod *mod, u32 enable) | 35 | rsnd_mod_write(mod, MIX_MIXIR, 1); |
| 36 | rsnd_mod_write(mod, MIX_SWRSR, 0); | ||
| 37 | } | ||
| 38 | |||
| 39 | static void rsnd_mix_volume_parameter(struct rsnd_dai_stream *io, | ||
| 40 | struct rsnd_mod *mod) | ||
| 37 | { | 41 | { |
| 38 | rsnd_mod_write(mod, MIX_MIXIR, enable); | 42 | rsnd_mod_write(mod, MIX_MDBAR, 0); |
| 43 | rsnd_mod_write(mod, MIX_MDBBR, 0); | ||
| 44 | rsnd_mod_write(mod, MIX_MDBCR, 0); | ||
| 45 | rsnd_mod_write(mod, MIX_MDBDR, 0); | ||
| 46 | } | ||
| 47 | |||
| 48 | static void rsnd_mix_volume_init(struct rsnd_dai_stream *io, | ||
| 49 | struct rsnd_mod *mod) | ||
| 50 | { | ||
| 51 | rsnd_mod_write(mod, MIX_MIXIR, 1); | ||
| 52 | |||
| 53 | /* General Information */ | ||
| 54 | rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); | ||
| 55 | |||
| 56 | /* volume step */ | ||
| 57 | rsnd_mod_write(mod, MIX_MIXMR, 0); | ||
| 58 | rsnd_mod_write(mod, MIX_MVPDR, 0); | ||
| 59 | |||
| 60 | /* common volume parameter */ | ||
| 61 | rsnd_mix_volume_parameter(io, mod); | ||
| 62 | |||
| 63 | rsnd_mod_write(mod, MIX_MIXIR, 0); | ||
| 39 | } | 64 | } |
| 40 | 65 | ||
| 41 | static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, | 66 | static void rsnd_mix_volume_update(struct rsnd_dai_stream *io, |
| 42 | struct rsnd_mod *mod) | 67 | struct rsnd_mod *mod) |
| 43 | { | 68 | { |
| 44 | |||
| 45 | /* Disable MIX dB setting */ | 69 | /* Disable MIX dB setting */ |
| 46 | rsnd_mod_write(mod, MIX_MDBER, 0); | 70 | rsnd_mod_write(mod, MIX_MDBER, 0); |
| 47 | 71 | ||
| 48 | rsnd_mod_write(mod, MIX_MDBAR, 0); | 72 | /* common volume parameter */ |
| 49 | rsnd_mod_write(mod, MIX_MDBBR, 0); | 73 | rsnd_mix_volume_parameter(io, mod); |
| 50 | rsnd_mod_write(mod, MIX_MDBCR, 0); | ||
| 51 | rsnd_mod_write(mod, MIX_MDBDR, 0); | ||
| 52 | 74 | ||
| 53 | /* Enable MIX dB setting */ | 75 | /* Enable MIX dB setting */ |
| 54 | rsnd_mod_write(mod, MIX_MDBER, 1); | 76 | rsnd_mod_write(mod, MIX_MDBER, 1); |
| 55 | } | 77 | } |
| 56 | 78 | ||
| 79 | static int rsnd_mix_probe_(struct rsnd_mod *mod, | ||
| 80 | struct rsnd_dai_stream *io, | ||
| 81 | struct rsnd_priv *priv) | ||
| 82 | { | ||
| 83 | return rsnd_cmd_attach(io, rsnd_mod_id(mod)); | ||
| 84 | } | ||
| 85 | |||
| 57 | static int rsnd_mix_init(struct rsnd_mod *mod, | 86 | static int rsnd_mix_init(struct rsnd_mod *mod, |
| 58 | struct rsnd_dai_stream *io, | 87 | struct rsnd_dai_stream *io, |
| 59 | struct rsnd_priv *priv) | 88 | struct rsnd_priv *priv) |
| 60 | { | 89 | { |
| 61 | rsnd_mod_power_on(mod); | 90 | rsnd_mod_power_on(mod); |
| 62 | 91 | ||
| 63 | rsnd_mix_soft_reset(mod); | 92 | rsnd_mix_activation(mod); |
| 64 | |||
| 65 | rsnd_mix_initialize_lock(mod); | ||
| 66 | |||
| 67 | rsnd_mod_write(mod, MIX_ADINR, rsnd_get_adinr_chan(mod, io)); | ||
| 68 | |||
| 69 | rsnd_path_parse(priv, io); | ||
| 70 | 93 | ||
| 71 | /* volume step */ | 94 | rsnd_mix_volume_init(io, mod); |
| 72 | rsnd_mod_write(mod, MIX_MIXMR, 0); | ||
| 73 | rsnd_mod_write(mod, MIX_MVPDR, 0); | ||
| 74 | 95 | ||
| 75 | rsnd_mix_volume_update(io, mod); | 96 | rsnd_mix_volume_update(io, mod); |
| 76 | 97 | ||
| 77 | rsnd_mix_initialize_unlock(mod); | ||
| 78 | |||
| 79 | return 0; | 98 | return 0; |
| 80 | } | 99 | } |
| 81 | 100 | ||
| @@ -83,6 +102,8 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, | |||
| 83 | struct rsnd_dai_stream *io, | 102 | struct rsnd_dai_stream *io, |
| 84 | struct rsnd_priv *priv) | 103 | struct rsnd_priv *priv) |
| 85 | { | 104 | { |
| 105 | rsnd_mix_halt(mod); | ||
| 106 | |||
| 86 | rsnd_mod_power_off(mod); | 107 | rsnd_mod_power_off(mod); |
| 87 | 108 | ||
| 88 | return 0; | 109 | return 0; |
| @@ -90,6 +111,7 @@ static int rsnd_mix_quit(struct rsnd_mod *mod, | |||
| 90 | 111 | ||
| 91 | static struct rsnd_mod_ops rsnd_mix_ops = { | 112 | static struct rsnd_mod_ops rsnd_mix_ops = { |
| 92 | .name = MIX_NAME, | 113 | .name = MIX_NAME, |
| 114 | .probe = rsnd_mix_probe_, | ||
| 93 | .init = rsnd_mix_init, | 115 | .init = rsnd_mix_init, |
| 94 | .quit = rsnd_mix_quit, | 116 | .quit = rsnd_mix_quit, |
| 95 | }; | 117 | }; |
| @@ -99,51 +121,13 @@ struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id) | |||
| 99 | if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) | 121 | if (WARN_ON(id < 0 || id >= rsnd_mix_nr(priv))) |
| 100 | id = 0; | 122 | id = 0; |
| 101 | 123 | ||
| 102 | return rsnd_mod_get((struct rsnd_mix *)(priv->mix) + id); | 124 | return rsnd_mod_get(rsnd_mix_get(priv, id)); |
| 103 | } | 125 | } |
| 104 | 126 | ||
| 105 | static void rsnd_of_parse_mix(struct platform_device *pdev, | 127 | int rsnd_mix_probe(struct rsnd_priv *priv) |
| 106 | const struct rsnd_of_data *of_data, | ||
| 107 | struct rsnd_priv *priv) | ||
| 108 | { | 128 | { |
| 109 | struct device_node *node; | 129 | struct device_node *node; |
| 110 | struct rsnd_mix_platform_info *mix_info; | 130 | struct device_node *np; |
| 111 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 112 | struct device *dev = &pdev->dev; | ||
| 113 | int nr; | ||
| 114 | |||
| 115 | if (!of_data) | ||
| 116 | return; | ||
| 117 | |||
| 118 | node = of_get_child_by_name(dev->of_node, "rcar_sound,mix"); | ||
| 119 | if (!node) | ||
| 120 | return; | ||
| 121 | |||
| 122 | nr = of_get_child_count(node); | ||
| 123 | if (!nr) | ||
| 124 | goto rsnd_of_parse_mix_end; | ||
| 125 | |||
| 126 | mix_info = devm_kzalloc(dev, | ||
| 127 | sizeof(struct rsnd_mix_platform_info) * nr, | ||
| 128 | GFP_KERNEL); | ||
| 129 | if (!mix_info) { | ||
| 130 | dev_err(dev, "mix info allocation error\n"); | ||
| 131 | goto rsnd_of_parse_mix_end; | ||
| 132 | } | ||
| 133 | |||
| 134 | info->mix_info = mix_info; | ||
| 135 | info->mix_info_nr = nr; | ||
| 136 | |||
| 137 | rsnd_of_parse_mix_end: | ||
| 138 | of_node_put(node); | ||
| 139 | |||
| 140 | } | ||
| 141 | |||
| 142 | int rsnd_mix_probe(struct platform_device *pdev, | ||
| 143 | const struct rsnd_of_data *of_data, | ||
| 144 | struct rsnd_priv *priv) | ||
| 145 | { | ||
| 146 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 147 | struct device *dev = rsnd_priv_to_dev(priv); | 131 | struct device *dev = rsnd_priv_to_dev(priv); |
| 148 | struct rsnd_mix *mix; | 132 | struct rsnd_mix *mix; |
| 149 | struct clk *clk; | 133 | struct clk *clk; |
| @@ -154,40 +138,54 @@ int rsnd_mix_probe(struct platform_device *pdev, | |||
| 154 | if (rsnd_is_gen1(priv)) | 138 | if (rsnd_is_gen1(priv)) |
| 155 | return 0; | 139 | return 0; |
| 156 | 140 | ||
| 157 | rsnd_of_parse_mix(pdev, of_data, priv); | 141 | node = rsnd_mix_of_node(priv); |
| 142 | if (!node) | ||
| 143 | return 0; /* not used is not error */ | ||
| 158 | 144 | ||
| 159 | nr = info->mix_info_nr; | 145 | nr = of_get_child_count(node); |
| 160 | if (!nr) | 146 | if (!nr) { |
| 161 | return 0; | 147 | ret = -EINVAL; |
| 148 | goto rsnd_mix_probe_done; | ||
| 149 | } | ||
| 162 | 150 | ||
| 163 | mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); | 151 | mix = devm_kzalloc(dev, sizeof(*mix) * nr, GFP_KERNEL); |
| 164 | if (!mix) | 152 | if (!mix) { |
| 165 | return -ENOMEM; | 153 | ret = -ENOMEM; |
| 154 | goto rsnd_mix_probe_done; | ||
| 155 | } | ||
| 166 | 156 | ||
| 167 | priv->mix_nr = nr; | 157 | priv->mix_nr = nr; |
| 168 | priv->mix = mix; | 158 | priv->mix = mix; |
| 169 | 159 | ||
| 170 | for_each_rsnd_mix(mix, priv, i) { | 160 | i = 0; |
| 161 | ret = 0; | ||
| 162 | for_each_child_of_node(node, np) { | ||
| 163 | mix = rsnd_mix_get(priv, i); | ||
| 164 | |||
| 171 | snprintf(name, MIX_NAME_SIZE, "%s.%d", | 165 | snprintf(name, MIX_NAME_SIZE, "%s.%d", |
| 172 | MIX_NAME, i); | 166 | MIX_NAME, i); |
| 173 | 167 | ||
| 174 | clk = devm_clk_get(dev, name); | 168 | clk = devm_clk_get(dev, name); |
| 175 | if (IS_ERR(clk)) | 169 | if (IS_ERR(clk)) { |
| 176 | return PTR_ERR(clk); | 170 | ret = PTR_ERR(clk); |
| 177 | 171 | goto rsnd_mix_probe_done; | |
| 178 | mix->info = &info->mix_info[i]; | 172 | } |
| 179 | 173 | ||
| 180 | ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, | 174 | ret = rsnd_mod_init(priv, rsnd_mod_get(mix), &rsnd_mix_ops, |
| 181 | clk, RSND_MOD_MIX, i); | 175 | clk, RSND_MOD_MIX, i); |
| 182 | if (ret) | 176 | if (ret) |
| 183 | return ret; | 177 | goto rsnd_mix_probe_done; |
| 178 | |||
| 179 | i++; | ||
| 184 | } | 180 | } |
| 185 | 181 | ||
| 186 | return 0; | 182 | rsnd_mix_probe_done: |
| 183 | of_node_put(node); | ||
| 184 | |||
| 185 | return ret; | ||
| 187 | } | 186 | } |
| 188 | 187 | ||
| 189 | void rsnd_mix_remove(struct platform_device *pdev, | 188 | void rsnd_mix_remove(struct rsnd_priv *priv) |
| 190 | struct rsnd_priv *priv) | ||
| 191 | { | 189 | { |
| 192 | struct rsnd_mix *mix; | 190 | struct rsnd_mix *mix; |
| 193 | int i; | 191 | int i; |
diff --git a/sound/soc/sh/rcar/rcar_snd.h b/sound/soc/sh/rcar/rcar_snd.h deleted file mode 100644 index d8e33d38da43..000000000000 --- a/sound/soc/sh/rcar/rcar_snd.h +++ /dev/null | |||
| @@ -1,117 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Renesas R-Car SRU/SCU/SSIU/SSI support | ||
| 3 | * | ||
| 4 | * Copyright (C) 2013 Renesas Solutions Corp. | ||
| 5 | * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License version 2 as | ||
| 9 | * published by the Free Software Foundation. | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef RCAR_SND_H | ||
| 13 | #define RCAR_SND_H | ||
| 14 | |||
| 15 | |||
| 16 | #define RSND_GEN1_SRU 0 | ||
| 17 | #define RSND_GEN1_ADG 1 | ||
| 18 | #define RSND_GEN1_SSI 2 | ||
| 19 | |||
| 20 | #define RSND_GEN2_SCU 0 | ||
| 21 | #define RSND_GEN2_ADG 1 | ||
| 22 | #define RSND_GEN2_SSIU 2 | ||
| 23 | #define RSND_GEN2_SSI 3 | ||
| 24 | |||
| 25 | #define RSND_BASE_MAX 4 | ||
| 26 | |||
| 27 | /* | ||
| 28 | * flags | ||
| 29 | * | ||
| 30 | * 0xAB000000 | ||
| 31 | * | ||
| 32 | * A : clock sharing settings | ||
| 33 | * B : SSI direction | ||
| 34 | */ | ||
| 35 | #define RSND_SSI_CLK_PIN_SHARE (1 << 31) | ||
| 36 | #define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */ | ||
| 37 | |||
| 38 | #define RSND_SSI(_dma_id, _irq, _flags) \ | ||
| 39 | { .dma_id = _dma_id, .irq = _irq, .flags = _flags } | ||
| 40 | #define RSND_SSI_UNUSED \ | ||
| 41 | { .dma_id = -1, .irq = -1, .flags = 0 } | ||
| 42 | |||
| 43 | struct rsnd_ssi_platform_info { | ||
| 44 | int dma_id; | ||
| 45 | int irq; | ||
| 46 | u32 flags; | ||
| 47 | }; | ||
| 48 | |||
| 49 | #define RSND_SRC(rate, _dma_id) \ | ||
| 50 | { .convert_rate = rate, .dma_id = _dma_id, } | ||
| 51 | #define RSND_SRC_UNUSED \ | ||
| 52 | { .convert_rate = 0, .dma_id = -1, } | ||
| 53 | |||
| 54 | struct rsnd_src_platform_info { | ||
| 55 | u32 convert_rate; /* sampling rate convert */ | ||
| 56 | int dma_id; /* for Gen2 SCU */ | ||
| 57 | int irq; | ||
| 58 | }; | ||
| 59 | |||
| 60 | /* | ||
| 61 | * flags | ||
| 62 | */ | ||
| 63 | struct rsnd_ctu_platform_info { | ||
| 64 | u32 flags; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct rsnd_mix_platform_info { | ||
| 68 | u32 flags; | ||
| 69 | }; | ||
| 70 | |||
| 71 | struct rsnd_dvc_platform_info { | ||
| 72 | u32 flags; | ||
| 73 | }; | ||
| 74 | |||
| 75 | struct rsnd_dai_path_info { | ||
| 76 | struct rsnd_ssi_platform_info *ssi; | ||
| 77 | struct rsnd_src_platform_info *src; | ||
| 78 | struct rsnd_ctu_platform_info *ctu; | ||
| 79 | struct rsnd_mix_platform_info *mix; | ||
| 80 | struct rsnd_dvc_platform_info *dvc; | ||
| 81 | }; | ||
| 82 | |||
| 83 | struct rsnd_dai_platform_info { | ||
| 84 | struct rsnd_dai_path_info playback; | ||
| 85 | struct rsnd_dai_path_info capture; | ||
| 86 | }; | ||
| 87 | |||
| 88 | /* | ||
| 89 | * flags | ||
| 90 | * | ||
| 91 | * 0x0000000A | ||
| 92 | * | ||
| 93 | * A : generation | ||
| 94 | */ | ||
| 95 | #define RSND_GEN_MASK (0xF << 0) | ||
| 96 | #define RSND_GEN1 (1 << 0) /* fixme */ | ||
| 97 | #define RSND_GEN2 (2 << 0) /* fixme */ | ||
| 98 | |||
| 99 | struct rcar_snd_info { | ||
| 100 | u32 flags; | ||
| 101 | struct rsnd_ssi_platform_info *ssi_info; | ||
| 102 | int ssi_info_nr; | ||
| 103 | struct rsnd_src_platform_info *src_info; | ||
| 104 | int src_info_nr; | ||
| 105 | struct rsnd_ctu_platform_info *ctu_info; | ||
| 106 | int ctu_info_nr; | ||
| 107 | struct rsnd_mix_platform_info *mix_info; | ||
| 108 | int mix_info_nr; | ||
| 109 | struct rsnd_dvc_platform_info *dvc_info; | ||
| 110 | int dvc_info_nr; | ||
| 111 | struct rsnd_dai_platform_info *dai_info; | ||
| 112 | int dai_info_nr; | ||
| 113 | int (*start)(int id); | ||
| 114 | int (*stop)(int id); | ||
| 115 | }; | ||
| 116 | |||
| 117 | #endif | ||
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h index 085329878525..317dd793149a 100644 --- a/sound/soc/sh/rcar/rsnd.h +++ b/sound/soc/sh/rcar/rsnd.h | |||
| @@ -24,7 +24,16 @@ | |||
| 24 | #include <sound/soc.h> | 24 | #include <sound/soc.h> |
| 25 | #include <sound/pcm_params.h> | 25 | #include <sound/pcm_params.h> |
| 26 | 26 | ||
| 27 | #include "rcar_snd.h" | 27 | #define RSND_GEN1_SRU 0 |
| 28 | #define RSND_GEN1_ADG 1 | ||
| 29 | #define RSND_GEN1_SSI 2 | ||
| 30 | |||
| 31 | #define RSND_GEN2_SCU 0 | ||
| 32 | #define RSND_GEN2_ADG 1 | ||
| 33 | #define RSND_GEN2_SSIU 2 | ||
| 34 | #define RSND_GEN2_SSI 3 | ||
| 35 | |||
| 36 | #define RSND_BASE_MAX 4 | ||
| 28 | 37 | ||
| 29 | /* | 38 | /* |
| 30 | * pseudo register | 39 | * pseudo register |
| @@ -34,10 +43,19 @@ | |||
| 34 | * see gen1/gen2 for detail | 43 | * see gen1/gen2 for detail |
| 35 | */ | 44 | */ |
| 36 | enum rsnd_reg { | 45 | enum rsnd_reg { |
| 37 | /* SRU/SCU/SSIU */ | 46 | /* SCU (SRC/SSIU/MIX/CTU/DVC) */ |
| 47 | RSND_REG_SSI_MODE, /* Gen2 only */ | ||
| 38 | RSND_REG_SSI_MODE0, | 48 | RSND_REG_SSI_MODE0, |
| 39 | RSND_REG_SSI_MODE1, | 49 | RSND_REG_SSI_MODE1, |
| 40 | RSND_REG_SRC_BUSIF_MODE, | 50 | RSND_REG_SSI_MODE2, |
| 51 | RSND_REG_SSI_CONTROL, | ||
| 52 | RSND_REG_SSI_CTRL, /* Gen2 only */ | ||
| 53 | RSND_REG_SSI_BUSIF_MODE, /* Gen2 only */ | ||
| 54 | RSND_REG_SSI_BUSIF_ADINR, /* Gen2 only */ | ||
| 55 | RSND_REG_SSI_BUSIF_DALIGN, /* Gen2 only */ | ||
| 56 | RSND_REG_SSI_INT_ENABLE, /* Gen2 only */ | ||
| 57 | RSND_REG_SRC_I_BUSIF_MODE, | ||
| 58 | RSND_REG_SRC_O_BUSIF_MODE, | ||
| 41 | RSND_REG_SRC_ROUTE_MODE0, | 59 | RSND_REG_SRC_ROUTE_MODE0, |
| 42 | RSND_REG_SRC_SWRSR, | 60 | RSND_REG_SRC_SWRSR, |
| 43 | RSND_REG_SRC_SRCIR, | 61 | RSND_REG_SRC_SRCIR, |
| @@ -45,9 +63,29 @@ enum rsnd_reg { | |||
| 45 | RSND_REG_SRC_IFSCR, | 63 | RSND_REG_SRC_IFSCR, |
| 46 | RSND_REG_SRC_IFSVR, | 64 | RSND_REG_SRC_IFSVR, |
| 47 | RSND_REG_SRC_SRCCR, | 65 | RSND_REG_SRC_SRCCR, |
| 66 | RSND_REG_SRC_CTRL, /* Gen2 only */ | ||
| 67 | RSND_REG_SRC_BSDSR, /* Gen2 only */ | ||
| 68 | RSND_REG_SRC_BSISR, /* Gen2 only */ | ||
| 69 | RSND_REG_SRC_INT_ENABLE0, /* Gen2 only */ | ||
| 70 | RSND_REG_SRC_BUSIF_DALIGN, /* Gen2 only */ | ||
| 71 | RSND_REG_SRCIN_TIMSEL0, /* Gen2 only */ | ||
| 72 | RSND_REG_SRCIN_TIMSEL1, /* Gen2 only */ | ||
| 73 | RSND_REG_SRCIN_TIMSEL2, /* Gen2 only */ | ||
| 74 | RSND_REG_SRCIN_TIMSEL3, /* Gen2 only */ | ||
| 75 | RSND_REG_SRCIN_TIMSEL4, /* Gen2 only */ | ||
| 76 | RSND_REG_SRCOUT_TIMSEL0, /* Gen2 only */ | ||
| 77 | RSND_REG_SRCOUT_TIMSEL1, /* Gen2 only */ | ||
| 78 | RSND_REG_SRCOUT_TIMSEL2, /* Gen2 only */ | ||
| 79 | RSND_REG_SRCOUT_TIMSEL3, /* Gen2 only */ | ||
| 80 | RSND_REG_SRCOUT_TIMSEL4, /* Gen2 only */ | ||
| 48 | RSND_REG_SCU_SYS_STATUS0, | 81 | RSND_REG_SCU_SYS_STATUS0, |
| 82 | RSND_REG_SCU_SYS_STATUS1, /* Gen2 only */ | ||
| 49 | RSND_REG_SCU_SYS_INT_EN0, | 83 | RSND_REG_SCU_SYS_INT_EN0, |
| 84 | RSND_REG_SCU_SYS_INT_EN1, /* Gen2 only */ | ||
| 85 | RSND_REG_CMD_CTRL, /* Gen2 only */ | ||
| 86 | RSND_REG_CMD_BUSIF_DALIGN, /* Gen2 only */ | ||
| 50 | RSND_REG_CMD_ROUTE_SLCT, | 87 | RSND_REG_CMD_ROUTE_SLCT, |
| 88 | RSND_REG_CMDOUT_TIMSEL, /* Gen2 only */ | ||
| 51 | RSND_REG_CTU_CTUIR, | 89 | RSND_REG_CTU_CTUIR, |
| 52 | RSND_REG_CTU_ADINR, | 90 | RSND_REG_CTU_ADINR, |
| 53 | RSND_REG_MIX_SWRSR, | 91 | RSND_REG_MIX_SWRSR, |
| @@ -67,14 +105,25 @@ enum rsnd_reg { | |||
| 67 | RSND_REG_DVC_ZCMCR, | 105 | RSND_REG_DVC_ZCMCR, |
| 68 | RSND_REG_DVC_VOL0R, | 106 | RSND_REG_DVC_VOL0R, |
| 69 | RSND_REG_DVC_VOL1R, | 107 | RSND_REG_DVC_VOL1R, |
| 108 | RSND_REG_DVC_VOL2R, | ||
| 109 | RSND_REG_DVC_VOL3R, | ||
| 110 | RSND_REG_DVC_VOL4R, | ||
| 111 | RSND_REG_DVC_VOL5R, | ||
| 112 | RSND_REG_DVC_VOL6R, | ||
| 113 | RSND_REG_DVC_VOL7R, | ||
| 70 | RSND_REG_DVC_DVUER, | 114 | RSND_REG_DVC_DVUER, |
| 115 | RSND_REG_DVC_VRCTR, /* Gen2 only */ | ||
| 116 | RSND_REG_DVC_VRPDR, /* Gen2 only */ | ||
| 117 | RSND_REG_DVC_VRDBR, /* Gen2 only */ | ||
| 71 | 118 | ||
| 72 | /* ADG */ | 119 | /* ADG */ |
| 73 | RSND_REG_BRRA, | 120 | RSND_REG_BRRA, |
| 74 | RSND_REG_BRRB, | 121 | RSND_REG_BRRB, |
| 75 | RSND_REG_SSICKR, | 122 | RSND_REG_SSICKR, |
| 123 | RSND_REG_DIV_EN, /* Gen2 only */ | ||
| 76 | RSND_REG_AUDIO_CLK_SEL0, | 124 | RSND_REG_AUDIO_CLK_SEL0, |
| 77 | RSND_REG_AUDIO_CLK_SEL1, | 125 | RSND_REG_AUDIO_CLK_SEL1, |
| 126 | RSND_REG_AUDIO_CLK_SEL2, /* Gen2 only */ | ||
| 78 | 127 | ||
| 79 | /* SSI */ | 128 | /* SSI */ |
| 80 | RSND_REG_SSICR, | 129 | RSND_REG_SSICR, |
| @@ -83,83 +132,9 @@ enum rsnd_reg { | |||
| 83 | RSND_REG_SSIRDR, | 132 | RSND_REG_SSIRDR, |
| 84 | RSND_REG_SSIWSR, | 133 | RSND_REG_SSIWSR, |
| 85 | 134 | ||
| 86 | /* SHARE see below */ | ||
| 87 | RSND_REG_SHARE01, | ||
| 88 | RSND_REG_SHARE02, | ||
| 89 | RSND_REG_SHARE03, | ||
| 90 | RSND_REG_SHARE04, | ||
| 91 | RSND_REG_SHARE05, | ||
| 92 | RSND_REG_SHARE06, | ||
| 93 | RSND_REG_SHARE07, | ||
| 94 | RSND_REG_SHARE08, | ||
| 95 | RSND_REG_SHARE09, | ||
| 96 | RSND_REG_SHARE10, | ||
| 97 | RSND_REG_SHARE11, | ||
| 98 | RSND_REG_SHARE12, | ||
| 99 | RSND_REG_SHARE13, | ||
| 100 | RSND_REG_SHARE14, | ||
| 101 | RSND_REG_SHARE15, | ||
| 102 | RSND_REG_SHARE16, | ||
| 103 | RSND_REG_SHARE17, | ||
| 104 | RSND_REG_SHARE18, | ||
| 105 | RSND_REG_SHARE19, | ||
| 106 | RSND_REG_SHARE20, | ||
| 107 | RSND_REG_SHARE21, | ||
| 108 | RSND_REG_SHARE22, | ||
| 109 | RSND_REG_SHARE23, | ||
| 110 | RSND_REG_SHARE24, | ||
| 111 | RSND_REG_SHARE25, | ||
| 112 | RSND_REG_SHARE26, | ||
| 113 | RSND_REG_SHARE27, | ||
| 114 | RSND_REG_SHARE28, | ||
| 115 | RSND_REG_SHARE29, | ||
| 116 | |||
| 117 | RSND_REG_MAX, | 135 | RSND_REG_MAX, |
| 118 | }; | 136 | }; |
| 119 | 137 | ||
| 120 | /* Gen1 only */ | ||
| 121 | #define RSND_REG_SRC_ROUTE_SEL RSND_REG_SHARE01 | ||
| 122 | #define RSND_REG_SRC_TMG_SEL0 RSND_REG_SHARE02 | ||
| 123 | #define RSND_REG_SRC_TMG_SEL1 RSND_REG_SHARE03 | ||
| 124 | #define RSND_REG_SRC_TMG_SEL2 RSND_REG_SHARE04 | ||
| 125 | #define RSND_REG_SRC_ROUTE_CTRL RSND_REG_SHARE05 | ||
| 126 | #define RSND_REG_SRC_MNFSR RSND_REG_SHARE06 | ||
| 127 | #define RSND_REG_AUDIO_CLK_SEL3 RSND_REG_SHARE07 | ||
| 128 | #define RSND_REG_AUDIO_CLK_SEL4 RSND_REG_SHARE08 | ||
| 129 | #define RSND_REG_AUDIO_CLK_SEL5 RSND_REG_SHARE09 | ||
| 130 | |||
| 131 | /* Gen2 only */ | ||
| 132 | #define RSND_REG_SRC_CTRL RSND_REG_SHARE01 | ||
| 133 | #define RSND_REG_SSI_CTRL RSND_REG_SHARE02 | ||
| 134 | #define RSND_REG_SSI_BUSIF_MODE RSND_REG_SHARE03 | ||
| 135 | #define RSND_REG_SSI_BUSIF_ADINR RSND_REG_SHARE04 | ||
| 136 | #define RSND_REG_SSI_INT_ENABLE RSND_REG_SHARE05 | ||
| 137 | #define RSND_REG_SRC_BSDSR RSND_REG_SHARE06 | ||
| 138 | #define RSND_REG_SRC_BSISR RSND_REG_SHARE07 | ||
| 139 | #define RSND_REG_DIV_EN RSND_REG_SHARE08 | ||
| 140 | #define RSND_REG_SRCIN_TIMSEL0 RSND_REG_SHARE09 | ||
| 141 | #define RSND_REG_SRCIN_TIMSEL1 RSND_REG_SHARE10 | ||
| 142 | #define RSND_REG_SRCIN_TIMSEL2 RSND_REG_SHARE11 | ||
| 143 | #define RSND_REG_SRCIN_TIMSEL3 RSND_REG_SHARE12 | ||
| 144 | #define RSND_REG_SRCIN_TIMSEL4 RSND_REG_SHARE13 | ||
| 145 | #define RSND_REG_SRCOUT_TIMSEL0 RSND_REG_SHARE14 | ||
| 146 | #define RSND_REG_SRCOUT_TIMSEL1 RSND_REG_SHARE15 | ||
| 147 | #define RSND_REG_SRCOUT_TIMSEL2 RSND_REG_SHARE16 | ||
| 148 | #define RSND_REG_SRCOUT_TIMSEL3 RSND_REG_SHARE17 | ||
| 149 | #define RSND_REG_SRCOUT_TIMSEL4 RSND_REG_SHARE18 | ||
| 150 | #define RSND_REG_AUDIO_CLK_SEL2 RSND_REG_SHARE19 | ||
| 151 | #define RSND_REG_CMD_CTRL RSND_REG_SHARE20 | ||
| 152 | #define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21 | ||
| 153 | #define RSND_REG_SSI_BUSIF_DALIGN RSND_REG_SHARE22 | ||
| 154 | #define RSND_REG_DVC_VRCTR RSND_REG_SHARE23 | ||
| 155 | #define RSND_REG_DVC_VRPDR RSND_REG_SHARE24 | ||
| 156 | #define RSND_REG_DVC_VRDBR RSND_REG_SHARE25 | ||
| 157 | #define RSND_REG_SCU_SYS_STATUS1 RSND_REG_SHARE26 | ||
| 158 | #define RSND_REG_SCU_SYS_INT_EN1 RSND_REG_SHARE27 | ||
| 159 | #define RSND_REG_SRC_INT_ENABLE0 RSND_REG_SHARE28 | ||
| 160 | #define RSND_REG_SRC_BUSIF_DALIGN RSND_REG_SHARE29 | ||
| 161 | |||
| 162 | struct rsnd_of_data; | ||
| 163 | struct rsnd_priv; | 138 | struct rsnd_priv; |
| 164 | struct rsnd_mod; | 139 | struct rsnd_mod; |
| 165 | struct rsnd_dai; | 140 | struct rsnd_dai; |
| @@ -187,43 +162,13 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod, enum rsnd_reg reg, | |||
| 187 | u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); | 162 | u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
| 188 | u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); | 163 | u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
| 189 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); | 164 | u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io); |
| 190 | void rsnd_path_parse(struct rsnd_priv *priv, | ||
| 191 | struct rsnd_dai_stream *io); | ||
| 192 | 165 | ||
| 193 | /* | 166 | /* |
| 194 | * R-Car DMA | 167 | * R-Car DMA |
| 195 | */ | 168 | */ |
| 196 | struct rsnd_dma; | 169 | struct rsnd_mod *rsnd_dma_attach(struct rsnd_dai_stream *io, |
| 197 | 170 | struct rsnd_mod *mod, int id); | |
| 198 | struct rsnd_dmaen { | 171 | int rsnd_dma_probe(struct rsnd_priv *priv); |
| 199 | struct dma_chan *chan; | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct rsnd_dmapp { | ||
| 203 | int dmapp_id; | ||
| 204 | u32 chcr; | ||
| 205 | }; | ||
| 206 | |||
| 207 | struct rsnd_dma { | ||
| 208 | struct rsnd_dma_ops *ops; | ||
| 209 | dma_addr_t src_addr; | ||
| 210 | dma_addr_t dst_addr; | ||
| 211 | union { | ||
| 212 | struct rsnd_dmaen en; | ||
| 213 | struct rsnd_dmapp pp; | ||
| 214 | } dma; | ||
| 215 | }; | ||
| 216 | #define rsnd_dma_to_dmaen(dma) (&(dma)->dma.en) | ||
| 217 | #define rsnd_dma_to_dmapp(dma) (&(dma)->dma.pp) | ||
| 218 | #define rsnd_dma_to_mod(_dma) container_of((_dma), struct rsnd_mod, dma) | ||
| 219 | |||
| 220 | void rsnd_dma_start(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 221 | void rsnd_dma_stop(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 222 | int rsnd_dma_init(struct rsnd_dai_stream *io, struct rsnd_dma *dma, int id); | ||
| 223 | void rsnd_dma_quit(struct rsnd_dai_stream *io, struct rsnd_dma *dma); | ||
| 224 | int rsnd_dma_probe(struct platform_device *pdev, | ||
| 225 | const struct rsnd_of_data *of_data, | ||
| 226 | struct rsnd_priv *priv); | ||
| 227 | struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, | 172 | struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, |
| 228 | struct rsnd_mod *mod, char *name); | 173 | struct rsnd_mod *mod, char *name); |
| 229 | 174 | ||
| @@ -231,11 +176,19 @@ struct dma_chan *rsnd_dma_request_channel(struct device_node *of_node, | |||
| 231 | * R-Car sound mod | 176 | * R-Car sound mod |
| 232 | */ | 177 | */ |
| 233 | enum rsnd_mod_type { | 178 | enum rsnd_mod_type { |
| 234 | RSND_MOD_DVC = 0, | 179 | RSND_MOD_AUDMAPP, |
| 180 | RSND_MOD_AUDMA, | ||
| 181 | RSND_MOD_DVC, | ||
| 235 | RSND_MOD_MIX, | 182 | RSND_MOD_MIX, |
| 236 | RSND_MOD_CTU, | 183 | RSND_MOD_CTU, |
| 184 | RSND_MOD_CMD, | ||
| 237 | RSND_MOD_SRC, | 185 | RSND_MOD_SRC, |
| 186 | RSND_MOD_SSIM3, /* SSI multi 3 */ | ||
| 187 | RSND_MOD_SSIM2, /* SSI multi 2 */ | ||
| 188 | RSND_MOD_SSIM1, /* SSI multi 1 */ | ||
| 189 | RSND_MOD_SSIP, /* SSI parent */ | ||
| 238 | RSND_MOD_SSI, | 190 | RSND_MOD_SSI, |
| 191 | RSND_MOD_SSIU, | ||
| 239 | RSND_MOD_MAX, | 192 | RSND_MOD_MAX, |
| 240 | }; | 193 | }; |
| 241 | 194 | ||
| @@ -278,10 +231,8 @@ struct rsnd_mod { | |||
| 278 | int id; | 231 | int id; |
| 279 | enum rsnd_mod_type type; | 232 | enum rsnd_mod_type type; |
| 280 | struct rsnd_mod_ops *ops; | 233 | struct rsnd_mod_ops *ops; |
| 281 | struct rsnd_dma dma; | ||
| 282 | struct rsnd_priv *priv; | 234 | struct rsnd_priv *priv; |
| 283 | struct clk *clk; | 235 | struct clk *clk; |
| 284 | u32 status; | ||
| 285 | }; | 236 | }; |
| 286 | /* | 237 | /* |
| 287 | * status | 238 | * status |
| @@ -328,7 +279,6 @@ struct rsnd_mod { | |||
| 328 | #define __rsnd_mod_call_hw_params 0 | 279 | #define __rsnd_mod_call_hw_params 0 |
| 329 | 280 | ||
| 330 | #define rsnd_mod_to_priv(mod) ((mod)->priv) | 281 | #define rsnd_mod_to_priv(mod) ((mod)->priv) |
| 331 | #define rsnd_mod_to_dma(mod) (&(mod)->dma) | ||
| 332 | #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) | 282 | #define rsnd_mod_id(mod) ((mod) ? (mod)->id : -1) |
| 333 | #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) | 283 | #define rsnd_mod_power_on(mod) clk_enable((mod)->clk) |
| 334 | #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) | 284 | #define rsnd_mod_power_off(mod) clk_disable((mod)->clk) |
| @@ -347,6 +297,17 @@ struct dma_chan *rsnd_mod_dma_req(struct rsnd_dai_stream *io, | |||
| 347 | void rsnd_mod_interrupt(struct rsnd_mod *mod, | 297 | void rsnd_mod_interrupt(struct rsnd_mod *mod, |
| 348 | void (*callback)(struct rsnd_mod *mod, | 298 | void (*callback)(struct rsnd_mod *mod, |
| 349 | struct rsnd_dai_stream *io)); | 299 | struct rsnd_dai_stream *io)); |
| 300 | void rsnd_parse_connect_common(struct rsnd_dai *rdai, | ||
| 301 | struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id), | ||
| 302 | struct device_node *node, | ||
| 303 | struct device_node *playback, | ||
| 304 | struct device_node *capture); | ||
| 305 | |||
| 306 | void rsnd_set_slot(struct rsnd_dai *rdai, | ||
| 307 | int slots, int slots_total); | ||
| 308 | int rsnd_get_slot(struct rsnd_dai_stream *io); | ||
| 309 | int rsnd_get_slot_width(struct rsnd_dai_stream *io); | ||
| 310 | int rsnd_get_slot_num(struct rsnd_dai_stream *io); | ||
| 350 | 311 | ||
| 351 | /* | 312 | /* |
| 352 | * R-Car sound DAI | 313 | * R-Car sound DAI |
| @@ -358,6 +319,7 @@ struct rsnd_dai_stream { | |||
| 358 | struct rsnd_mod *mod[RSND_MOD_MAX]; | 319 | struct rsnd_mod *mod[RSND_MOD_MAX]; |
| 359 | struct rsnd_dai_path_info *info; /* rcar_snd.h */ | 320 | struct rsnd_dai_path_info *info; /* rcar_snd.h */ |
| 360 | struct rsnd_dai *rdai; | 321 | struct rsnd_dai *rdai; |
| 322 | u32 mod_status[RSND_MOD_MAX]; | ||
| 361 | int byte_pos; | 323 | int byte_pos; |
| 362 | int period_pos; | 324 | int period_pos; |
| 363 | int byte_per_period; | 325 | int byte_per_period; |
| @@ -365,10 +327,12 @@ struct rsnd_dai_stream { | |||
| 365 | }; | 327 | }; |
| 366 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) | 328 | #define rsnd_io_to_mod(io, i) ((i) < RSND_MOD_MAX ? (io)->mod[(i)] : NULL) |
| 367 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) | 329 | #define rsnd_io_to_mod_ssi(io) rsnd_io_to_mod((io), RSND_MOD_SSI) |
| 330 | #define rsnd_io_to_mod_ssip(io) rsnd_io_to_mod((io), RSND_MOD_SSIP) | ||
| 368 | #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) | 331 | #define rsnd_io_to_mod_src(io) rsnd_io_to_mod((io), RSND_MOD_SRC) |
| 369 | #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) | 332 | #define rsnd_io_to_mod_ctu(io) rsnd_io_to_mod((io), RSND_MOD_CTU) |
| 370 | #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) | 333 | #define rsnd_io_to_mod_mix(io) rsnd_io_to_mod((io), RSND_MOD_MIX) |
| 371 | #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) | 334 | #define rsnd_io_to_mod_dvc(io) rsnd_io_to_mod((io), RSND_MOD_DVC) |
| 335 | #define rsnd_io_to_mod_cmd(io) rsnd_io_to_mod((io), RSND_MOD_CMD) | ||
| 372 | #define rsnd_io_to_rdai(io) ((io)->rdai) | 336 | #define rsnd_io_to_rdai(io) ((io)->rdai) |
| 373 | #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) | 337 | #define rsnd_io_to_priv(io) (rsnd_rdai_to_priv(rsnd_io_to_rdai(io))) |
| 374 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) | 338 | #define rsnd_io_is_play(io) (&rsnd_io_to_rdai(io)->playback == io) |
| @@ -382,6 +346,9 @@ struct rsnd_dai { | |||
| 382 | struct rsnd_dai_stream capture; | 346 | struct rsnd_dai_stream capture; |
| 383 | struct rsnd_priv *priv; | 347 | struct rsnd_priv *priv; |
| 384 | 348 | ||
| 349 | int slots; | ||
| 350 | int slots_num; | ||
| 351 | |||
| 385 | unsigned int clk_master:1; | 352 | unsigned int clk_master:1; |
| 386 | unsigned int bit_clk_inv:1; | 353 | unsigned int bit_clk_inv:1; |
| 387 | unsigned int frm_clk_inv:1; | 354 | unsigned int frm_clk_inv:1; |
| @@ -403,33 +370,28 @@ struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id); | |||
| 403 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); | 370 | bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt); |
| 404 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); | 371 | void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); |
| 405 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); | 372 | int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional); |
| 373 | int rsnd_dai_connect(struct rsnd_mod *mod, | ||
| 374 | struct rsnd_dai_stream *io, | ||
| 375 | enum rsnd_mod_type type); | ||
| 376 | #define rsnd_dai_of_node(priv) \ | ||
| 377 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dai") | ||
| 406 | 378 | ||
| 407 | /* | 379 | /* |
| 408 | * R-Car Gen1/Gen2 | 380 | * R-Car Gen1/Gen2 |
| 409 | */ | 381 | */ |
| 410 | int rsnd_gen_probe(struct platform_device *pdev, | 382 | int rsnd_gen_probe(struct rsnd_priv *priv); |
| 411 | const struct rsnd_of_data *of_data, | ||
| 412 | struct rsnd_priv *priv); | ||
| 413 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, | 383 | void __iomem *rsnd_gen_reg_get(struct rsnd_priv *priv, |
| 414 | struct rsnd_mod *mod, | 384 | struct rsnd_mod *mod, |
| 415 | enum rsnd_reg reg); | 385 | enum rsnd_reg reg); |
| 416 | phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); | 386 | phys_addr_t rsnd_gen_get_phy_addr(struct rsnd_priv *priv, int reg_id); |
| 417 | 387 | ||
| 418 | #define rsnd_is_gen1(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN1) | ||
| 419 | #define rsnd_is_gen2(s) (((s)->info->flags & RSND_GEN_MASK) == RSND_GEN2) | ||
| 420 | |||
| 421 | /* | 388 | /* |
| 422 | * R-Car ADG | 389 | * R-Car ADG |
| 423 | */ | 390 | */ |
| 424 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); | 391 | int rsnd_adg_ssi_clk_stop(struct rsnd_mod *mod); |
| 425 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); | 392 | int rsnd_adg_ssi_clk_try_start(struct rsnd_mod *mod, unsigned int rate); |
| 426 | int rsnd_adg_probe(struct platform_device *pdev, | 393 | int rsnd_adg_probe(struct rsnd_priv *priv); |
| 427 | const struct rsnd_of_data *of_data, | 394 | void rsnd_adg_remove(struct rsnd_priv *priv); |
| 428 | struct rsnd_priv *priv); | ||
| 429 | int rsnd_adg_set_convert_clk_gen1(struct rsnd_priv *priv, | ||
| 430 | struct rsnd_mod *mod, | ||
| 431 | unsigned int src_rate, | ||
| 432 | unsigned int dst_rate); | ||
| 433 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, | 395 | int rsnd_adg_set_convert_clk_gen2(struct rsnd_mod *mod, |
| 434 | struct rsnd_dai_stream *io, | 396 | struct rsnd_dai_stream *io, |
| 435 | unsigned int src_rate, | 397 | unsigned int src_rate, |
| @@ -442,15 +404,14 @@ int rsnd_adg_set_cmd_timsel_gen2(struct rsnd_mod *mod, | |||
| 442 | /* | 404 | /* |
| 443 | * R-Car sound priv | 405 | * R-Car sound priv |
| 444 | */ | 406 | */ |
| 445 | struct rsnd_of_data { | ||
| 446 | u32 flags; | ||
| 447 | }; | ||
| 448 | |||
| 449 | struct rsnd_priv { | 407 | struct rsnd_priv { |
| 450 | 408 | ||
| 451 | struct platform_device *pdev; | 409 | struct platform_device *pdev; |
| 452 | struct rcar_snd_info *info; | ||
| 453 | spinlock_t lock; | 410 | spinlock_t lock; |
| 411 | unsigned long flags; | ||
| 412 | #define RSND_GEN_MASK (0xF << 0) | ||
| 413 | #define RSND_GEN1 (1 << 0) | ||
| 414 | #define RSND_GEN2 (2 << 0) | ||
| 454 | 415 | ||
| 455 | /* | 416 | /* |
| 456 | * below value will be filled on rsnd_gen_probe() | 417 | * below value will be filled on rsnd_gen_probe() |
| @@ -474,6 +435,12 @@ struct rsnd_priv { | |||
| 474 | int ssi_nr; | 435 | int ssi_nr; |
| 475 | 436 | ||
| 476 | /* | 437 | /* |
| 438 | * below value will be filled on rsnd_ssiu_probe() | ||
| 439 | */ | ||
| 440 | void *ssiu; | ||
| 441 | int ssiu_nr; | ||
| 442 | |||
| 443 | /* | ||
| 477 | * below value will be filled on rsnd_src_probe() | 444 | * below value will be filled on rsnd_src_probe() |
| 478 | */ | 445 | */ |
| 479 | void *src; | 446 | void *src; |
| @@ -498,6 +465,12 @@ struct rsnd_priv { | |||
| 498 | int dvc_nr; | 465 | int dvc_nr; |
| 499 | 466 | ||
| 500 | /* | 467 | /* |
| 468 | * below value will be filled on rsnd_cmd_probe() | ||
| 469 | */ | ||
| 470 | void *cmd; | ||
| 471 | int cmd_nr; | ||
| 472 | |||
| 473 | /* | ||
| 501 | * below value will be filled on rsnd_dai_probe() | 474 | * below value will be filled on rsnd_dai_probe() |
| 502 | */ | 475 | */ |
| 503 | struct snd_soc_dai_driver *daidrv; | 476 | struct snd_soc_dai_driver *daidrv; |
| @@ -507,7 +480,9 @@ struct rsnd_priv { | |||
| 507 | 480 | ||
| 508 | #define rsnd_priv_to_pdev(priv) ((priv)->pdev) | 481 | #define rsnd_priv_to_pdev(priv) ((priv)->pdev) |
| 509 | #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) | 482 | #define rsnd_priv_to_dev(priv) (&(rsnd_priv_to_pdev(priv)->dev)) |
| 510 | #define rsnd_priv_to_info(priv) ((priv)->info) | 483 | |
| 484 | #define rsnd_is_gen1(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN1) | ||
| 485 | #define rsnd_is_gen2(priv) (((priv)->flags & RSND_GEN_MASK) == RSND_GEN2) | ||
| 511 | 486 | ||
| 512 | /* | 487 | /* |
| 513 | * rsnd_kctrl | 488 | * rsnd_kctrl |
| @@ -523,7 +498,7 @@ struct rsnd_kctrl_cfg { | |||
| 523 | struct snd_kcontrol *kctrl; | 498 | struct snd_kcontrol *kctrl; |
| 524 | }; | 499 | }; |
| 525 | 500 | ||
| 526 | #define RSND_DVC_CHANNELS 2 | 501 | #define RSND_DVC_CHANNELS 8 |
| 527 | struct rsnd_kctrl_cfg_m { | 502 | struct rsnd_kctrl_cfg_m { |
| 528 | struct rsnd_kctrl_cfg cfg; | 503 | struct rsnd_kctrl_cfg cfg; |
| 529 | u32 val[RSND_DVC_CHANNELS]; | 504 | u32 val[RSND_DVC_CHANNELS]; |
| @@ -544,6 +519,7 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod, | |||
| 544 | void (*update)(struct rsnd_dai_stream *io, | 519 | void (*update)(struct rsnd_dai_stream *io, |
| 545 | struct rsnd_mod *mod), | 520 | struct rsnd_mod *mod), |
| 546 | struct rsnd_kctrl_cfg_m *_cfg, | 521 | struct rsnd_kctrl_cfg_m *_cfg, |
| 522 | int ch_size, | ||
| 547 | u32 max); | 523 | u32 max); |
| 548 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, | 524 | int rsnd_kctrl_new_s(struct rsnd_mod *mod, |
| 549 | struct rsnd_dai_stream *io, | 525 | struct rsnd_dai_stream *io, |
| @@ -566,70 +542,93 @@ int rsnd_kctrl_new_e(struct rsnd_mod *mod, | |||
| 566 | /* | 542 | /* |
| 567 | * R-Car SSI | 543 | * R-Car SSI |
| 568 | */ | 544 | */ |
| 569 | int rsnd_ssi_probe(struct platform_device *pdev, | 545 | int rsnd_ssi_probe(struct rsnd_priv *priv); |
| 570 | const struct rsnd_of_data *of_data, | 546 | void rsnd_ssi_remove(struct rsnd_priv *priv); |
| 571 | struct rsnd_priv *priv); | ||
| 572 | void rsnd_ssi_remove(struct platform_device *pdev, | ||
| 573 | struct rsnd_priv *priv); | ||
| 574 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); | 547 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id); |
| 575 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); | 548 | int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod); |
| 576 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); | 549 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io); |
| 550 | u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io); | ||
| 577 | 551 | ||
| 578 | #define rsnd_ssi_is_pin_sharing(io) \ | 552 | #define rsnd_ssi_is_pin_sharing(io) \ |
| 579 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) | 553 | __rsnd_ssi_is_pin_sharing(rsnd_io_to_mod_ssi(io)) |
| 580 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); | 554 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); |
| 581 | 555 | ||
| 556 | #define rsnd_ssi_of_node(priv) \ | ||
| 557 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") | ||
| 558 | void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, | ||
| 559 | struct device_node *playback, | ||
| 560 | struct device_node *capture); | ||
| 561 | |||
| 562 | /* | ||
| 563 | * R-Car SSIU | ||
| 564 | */ | ||
| 565 | int rsnd_ssiu_attach(struct rsnd_dai_stream *io, | ||
| 566 | struct rsnd_mod *mod); | ||
| 567 | int rsnd_ssiu_probe(struct rsnd_priv *priv); | ||
| 568 | void rsnd_ssiu_remove(struct rsnd_priv *priv); | ||
| 569 | |||
| 582 | /* | 570 | /* |
| 583 | * R-Car SRC | 571 | * R-Car SRC |
| 584 | */ | 572 | */ |
| 585 | int rsnd_src_probe(struct platform_device *pdev, | 573 | int rsnd_src_probe(struct rsnd_priv *priv); |
| 586 | const struct rsnd_of_data *of_data, | 574 | void rsnd_src_remove(struct rsnd_priv *priv); |
| 587 | struct rsnd_priv *priv); | ||
| 588 | void rsnd_src_remove(struct platform_device *pdev, | ||
| 589 | struct rsnd_priv *priv); | ||
| 590 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); | 575 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id); |
| 591 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | 576 | unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, |
| 592 | struct rsnd_dai_stream *io, | 577 | struct rsnd_dai_stream *io, |
| 593 | struct snd_pcm_runtime *runtime); | 578 | struct snd_pcm_runtime *runtime); |
| 594 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | 579 | #define rsnd_src_of_node(priv) \ |
| 595 | struct rsnd_dai_stream *io, | 580 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") |
| 596 | int use_busif); | 581 | #define rsnd_parse_connect_src(rdai, playback, capture) \ |
| 597 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | 582 | rsnd_parse_connect_common(rdai, rsnd_src_mod_get, \ |
| 598 | struct rsnd_dai_stream *io); | 583 | rsnd_src_of_node(rsnd_rdai_to_priv(rdai)), \ |
| 599 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod); | 584 | playback, capture) |
| 600 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod); | ||
| 601 | 585 | ||
| 602 | /* | 586 | /* |
| 603 | * R-Car CTU | 587 | * R-Car CTU |
| 604 | */ | 588 | */ |
| 605 | int rsnd_ctu_probe(struct platform_device *pdev, | 589 | int rsnd_ctu_probe(struct rsnd_priv *priv); |
| 606 | const struct rsnd_of_data *of_data, | 590 | void rsnd_ctu_remove(struct rsnd_priv *priv); |
| 607 | struct rsnd_priv *priv); | ||
| 608 | |||
| 609 | void rsnd_ctu_remove(struct platform_device *pdev, | ||
| 610 | struct rsnd_priv *priv); | ||
| 611 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); | 591 | struct rsnd_mod *rsnd_ctu_mod_get(struct rsnd_priv *priv, int id); |
| 592 | #define rsnd_ctu_of_node(priv) \ | ||
| 593 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ctu") | ||
| 594 | #define rsnd_parse_connect_ctu(rdai, playback, capture) \ | ||
| 595 | rsnd_parse_connect_common(rdai, rsnd_ctu_mod_get, \ | ||
| 596 | rsnd_ctu_of_node(rsnd_rdai_to_priv(rdai)), \ | ||
| 597 | playback, capture) | ||
| 612 | 598 | ||
| 613 | /* | 599 | /* |
| 614 | * R-Car MIX | 600 | * R-Car MIX |
| 615 | */ | 601 | */ |
| 616 | int rsnd_mix_probe(struct platform_device *pdev, | 602 | int rsnd_mix_probe(struct rsnd_priv *priv); |
| 617 | const struct rsnd_of_data *of_data, | 603 | void rsnd_mix_remove(struct rsnd_priv *priv); |
| 618 | struct rsnd_priv *priv); | ||
| 619 | |||
| 620 | void rsnd_mix_remove(struct platform_device *pdev, | ||
| 621 | struct rsnd_priv *priv); | ||
| 622 | struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); | 604 | struct rsnd_mod *rsnd_mix_mod_get(struct rsnd_priv *priv, int id); |
| 605 | #define rsnd_mix_of_node(priv) \ | ||
| 606 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,mix") | ||
| 607 | #define rsnd_parse_connect_mix(rdai, playback, capture) \ | ||
| 608 | rsnd_parse_connect_common(rdai, rsnd_mix_mod_get, \ | ||
| 609 | rsnd_mix_of_node(rsnd_rdai_to_priv(rdai)), \ | ||
| 610 | playback, capture) | ||
| 623 | 611 | ||
| 624 | /* | 612 | /* |
| 625 | * R-Car DVC | 613 | * R-Car DVC |
| 626 | */ | 614 | */ |
| 627 | int rsnd_dvc_probe(struct platform_device *pdev, | 615 | int rsnd_dvc_probe(struct rsnd_priv *priv); |
| 628 | const struct rsnd_of_data *of_data, | 616 | void rsnd_dvc_remove(struct rsnd_priv *priv); |
| 629 | struct rsnd_priv *priv); | ||
| 630 | void rsnd_dvc_remove(struct platform_device *pdev, | ||
| 631 | struct rsnd_priv *priv); | ||
| 632 | struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); | 617 | struct rsnd_mod *rsnd_dvc_mod_get(struct rsnd_priv *priv, int id); |
| 618 | #define rsnd_dvc_of_node(priv) \ | ||
| 619 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,dvc") | ||
| 620 | #define rsnd_parse_connect_dvc(rdai, playback, capture) \ | ||
| 621 | rsnd_parse_connect_common(rdai, rsnd_dvc_mod_get, \ | ||
| 622 | rsnd_dvc_of_node(rsnd_rdai_to_priv(rdai)), \ | ||
| 623 | playback, capture) | ||
| 624 | |||
| 625 | /* | ||
| 626 | * R-Car CMD | ||
| 627 | */ | ||
| 628 | int rsnd_cmd_probe(struct rsnd_priv *priv); | ||
| 629 | void rsnd_cmd_remove(struct rsnd_priv *priv); | ||
| 630 | int rsnd_cmd_attach(struct rsnd_dai_stream *io, int id); | ||
| 631 | struct rsnd_mod *rsnd_cmd_mod_get(struct rsnd_priv *priv, int id); | ||
| 633 | 632 | ||
| 634 | #ifdef DEBUG | 633 | #ifdef DEBUG |
| 635 | void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); | 634 | void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type); |
diff --git a/sound/soc/sh/rcar/rsrc-card.c b/sound/soc/sh/rcar/rsrc-card.c index 94d23d8f2869..8a357fdf1077 100644 --- a/sound/soc/sh/rcar/rsrc-card.c +++ b/sound/soc/sh/rcar/rsrc-card.c | |||
| @@ -48,8 +48,11 @@ MODULE_DEVICE_TABLE(of, rsrc_card_of_match); | |||
| 48 | 48 | ||
| 49 | #define DAI_NAME_NUM 32 | 49 | #define DAI_NAME_NUM 32 |
| 50 | struct rsrc_card_dai { | 50 | struct rsrc_card_dai { |
| 51 | unsigned int fmt; | ||
| 52 | unsigned int sysclk; | 51 | unsigned int sysclk; |
| 52 | unsigned int tx_slot_mask; | ||
| 53 | unsigned int rx_slot_mask; | ||
| 54 | int slots; | ||
| 55 | int slot_width; | ||
| 53 | struct clk *clk; | 56 | struct clk *clk; |
| 54 | char dai_name[DAI_NAME_NUM]; | 57 | char dai_name[DAI_NAME_NUM]; |
| 55 | }; | 58 | }; |
| @@ -110,18 +113,22 @@ static int rsrc_card_dai_init(struct snd_soc_pcm_runtime *rtd) | |||
| 110 | rtd->cpu_dai : | 113 | rtd->cpu_dai : |
| 111 | rtd->codec_dai; | 114 | rtd->codec_dai; |
| 112 | 115 | ||
| 113 | if (dai_props->fmt) { | 116 | if (dai_props->sysclk) { |
| 114 | ret = snd_soc_dai_set_fmt(dai, dai_props->fmt); | 117 | ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); |
| 115 | if (ret && ret != -ENOTSUPP) { | 118 | if (ret && ret != -ENOTSUPP) { |
| 116 | dev_err(dai->dev, "set_fmt error\n"); | 119 | dev_err(dai->dev, "set_sysclk error\n"); |
| 117 | goto err; | 120 | goto err; |
| 118 | } | 121 | } |
| 119 | } | 122 | } |
| 120 | 123 | ||
| 121 | if (dai_props->sysclk) { | 124 | if (dai_props->slots) { |
| 122 | ret = snd_soc_dai_set_sysclk(dai, 0, dai_props->sysclk, 0); | 125 | ret = snd_soc_dai_set_tdm_slot(dai, |
| 126 | dai_props->tx_slot_mask, | ||
| 127 | dai_props->rx_slot_mask, | ||
| 128 | dai_props->slots, | ||
| 129 | dai_props->slot_width); | ||
| 123 | if (ret && ret != -ENOTSUPP) { | 130 | if (ret && ret != -ENOTSUPP) { |
| 124 | dev_err(dai->dev, "set_sysclk error\n"); | 131 | dev_err(dai->dev, "set_tdm_slot error\n"); |
| 125 | goto err; | 132 | goto err; |
| 126 | } | 133 | } |
| 127 | } | 134 | } |
| @@ -148,14 +155,13 @@ static int rsrc_card_be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, | |||
| 148 | } | 155 | } |
| 149 | 156 | ||
| 150 | static int rsrc_card_parse_daifmt(struct device_node *node, | 157 | static int rsrc_card_parse_daifmt(struct device_node *node, |
| 151 | struct device_node *np, | 158 | struct device_node *codec, |
| 152 | struct rsrc_card_priv *priv, | 159 | struct rsrc_card_priv *priv, |
| 153 | int idx, bool is_fe) | 160 | struct snd_soc_dai_link *dai_link, |
| 161 | unsigned int *retfmt) | ||
| 154 | { | 162 | { |
| 155 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | ||
| 156 | struct device_node *bitclkmaster = NULL; | 163 | struct device_node *bitclkmaster = NULL; |
| 157 | struct device_node *framemaster = NULL; | 164 | struct device_node *framemaster = NULL; |
| 158 | struct device_node *codec = is_fe ? NULL : np; | ||
| 159 | unsigned int daifmt; | 165 | unsigned int daifmt; |
| 160 | 166 | ||
| 161 | daifmt = snd_soc_of_parse_daifmt(node, NULL, | 167 | daifmt = snd_soc_of_parse_daifmt(node, NULL, |
| @@ -172,11 +178,11 @@ static int rsrc_card_parse_daifmt(struct device_node *node, | |||
| 172 | daifmt |= (codec == framemaster) ? | 178 | daifmt |= (codec == framemaster) ? |
| 173 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; | 179 | SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS; |
| 174 | 180 | ||
| 175 | dai_props->fmt = daifmt; | ||
| 176 | |||
| 177 | of_node_put(bitclkmaster); | 181 | of_node_put(bitclkmaster); |
| 178 | of_node_put(framemaster); | 182 | of_node_put(framemaster); |
| 179 | 183 | ||
| 184 | *retfmt = daifmt; | ||
| 185 | |||
| 180 | return 0; | 186 | return 0; |
| 181 | } | 187 | } |
| 182 | 188 | ||
| @@ -198,6 +204,15 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
| 198 | if (ret) | 204 | if (ret) |
| 199 | return ret; | 205 | return ret; |
| 200 | 206 | ||
| 207 | /* Parse TDM slot */ | ||
| 208 | ret = snd_soc_of_parse_tdm_slot(np, | ||
| 209 | &dai_props->tx_slot_mask, | ||
| 210 | &dai_props->rx_slot_mask, | ||
| 211 | &dai_props->slots, | ||
| 212 | &dai_props->slot_width); | ||
| 213 | if (ret) | ||
| 214 | return ret; | ||
| 215 | |||
| 201 | if (is_fe) { | 216 | if (is_fe) { |
| 202 | /* BE is dummy */ | 217 | /* BE is dummy */ |
| 203 | dai_link->codec_of_node = NULL; | 218 | dai_link->codec_of_node = NULL; |
| @@ -208,7 +223,9 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
| 208 | dai_link->dynamic = 1; | 223 | dai_link->dynamic = 1; |
| 209 | dai_link->dpcm_merged_format = 1; | 224 | dai_link->dpcm_merged_format = 1; |
| 210 | dai_link->cpu_of_node = args.np; | 225 | dai_link->cpu_of_node = args.np; |
| 211 | snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); | 226 | ret = snd_soc_of_get_dai_name(np, &dai_link->cpu_dai_name); |
| 227 | if (ret < 0) | ||
| 228 | return ret; | ||
| 212 | 229 | ||
| 213 | /* set dai_name */ | 230 | /* set dai_name */ |
| 214 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", | 231 | snprintf(dai_props->dai_name, DAI_NAME_NUM, "fe.%s", |
| @@ -240,7 +257,9 @@ static int rsrc_card_parse_links(struct device_node *np, | |||
| 240 | dai_link->no_pcm = 1; | 257 | dai_link->no_pcm = 1; |
| 241 | dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; | 258 | dai_link->be_hw_params_fixup = rsrc_card_be_hw_params_fixup; |
| 242 | dai_link->codec_of_node = args.np; | 259 | dai_link->codec_of_node = args.np; |
| 243 | snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); | 260 | ret = snd_soc_of_get_dai_name(np, &dai_link->codec_dai_name); |
| 261 | if (ret < 0) | ||
| 262 | return ret; | ||
| 244 | 263 | ||
| 245 | /* additional name prefix */ | 264 | /* additional name prefix */ |
| 246 | if (of_data) { | 265 | if (of_data) { |
| @@ -305,23 +324,16 @@ static int rsrc_card_parse_clk(struct device_node *np, | |||
| 305 | return 0; | 324 | return 0; |
| 306 | } | 325 | } |
| 307 | 326 | ||
| 308 | static int rsrc_card_dai_link_of(struct device_node *node, | 327 | static int rsrc_card_dai_sub_link_of(struct device_node *node, |
| 309 | struct device_node *np, | 328 | struct device_node *np, |
| 310 | struct rsrc_card_priv *priv, | 329 | struct rsrc_card_priv *priv, |
| 311 | int idx) | 330 | int idx, bool is_fe) |
| 312 | { | 331 | { |
| 313 | struct device *dev = rsrc_priv_to_dev(priv); | 332 | struct device *dev = rsrc_priv_to_dev(priv); |
| 333 | struct snd_soc_dai_link *dai_link = rsrc_priv_to_link(priv, idx); | ||
| 314 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); | 334 | struct rsrc_card_dai *dai_props = rsrc_priv_to_props(priv, idx); |
| 315 | bool is_fe = false; | ||
| 316 | int ret; | 335 | int ret; |
| 317 | 336 | ||
| 318 | if (0 == strcmp(np->name, "cpu")) | ||
| 319 | is_fe = true; | ||
| 320 | |||
| 321 | ret = rsrc_card_parse_daifmt(node, np, priv, idx, is_fe); | ||
| 322 | if (ret < 0) | ||
| 323 | return ret; | ||
| 324 | |||
| 325 | ret = rsrc_card_parse_links(np, priv, idx, is_fe); | 337 | ret = rsrc_card_parse_links(np, priv, idx, is_fe); |
| 326 | if (ret < 0) | 338 | if (ret < 0) |
| 327 | return ret; | 339 | return ret; |
| @@ -332,12 +344,54 @@ static int rsrc_card_dai_link_of(struct device_node *node, | |||
| 332 | 344 | ||
| 333 | dev_dbg(dev, "\t%s / %04x / %d\n", | 345 | dev_dbg(dev, "\t%s / %04x / %d\n", |
| 334 | dai_props->dai_name, | 346 | dai_props->dai_name, |
| 335 | dai_props->fmt, | 347 | dai_link->dai_fmt, |
| 336 | dai_props->sysclk); | 348 | dai_props->sysclk); |
| 337 | 349 | ||
| 338 | return ret; | 350 | return ret; |
| 339 | } | 351 | } |
| 340 | 352 | ||
| 353 | static int rsrc_card_dai_link_of(struct device_node *node, | ||
| 354 | struct rsrc_card_priv *priv) | ||
| 355 | { | ||
| 356 | struct snd_soc_dai_link *dai_link; | ||
| 357 | struct device_node *np; | ||
| 358 | unsigned int daifmt = 0; | ||
| 359 | int ret, i; | ||
| 360 | bool is_fe; | ||
| 361 | |||
| 362 | /* find 1st codec */ | ||
| 363 | i = 0; | ||
| 364 | for_each_child_of_node(node, np) { | ||
| 365 | dai_link = rsrc_priv_to_link(priv, i); | ||
| 366 | |||
| 367 | if (strcmp(np->name, "codec") == 0) { | ||
| 368 | ret = rsrc_card_parse_daifmt(node, np, priv, | ||
| 369 | dai_link, &daifmt); | ||
| 370 | if (ret < 0) | ||
| 371 | return ret; | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | i++; | ||
| 375 | } | ||
| 376 | |||
| 377 | i = 0; | ||
| 378 | for_each_child_of_node(node, np) { | ||
| 379 | dai_link = rsrc_priv_to_link(priv, i); | ||
| 380 | dai_link->dai_fmt = daifmt; | ||
| 381 | |||
| 382 | is_fe = false; | ||
| 383 | if (strcmp(np->name, "cpu") == 0) | ||
| 384 | is_fe = true; | ||
| 385 | |||
| 386 | ret = rsrc_card_dai_sub_link_of(node, np, priv, i, is_fe); | ||
| 387 | if (ret < 0) | ||
| 388 | return ret; | ||
| 389 | i++; | ||
| 390 | } | ||
| 391 | |||
| 392 | return 0; | ||
| 393 | } | ||
| 394 | |||
| 341 | static int rsrc_card_parse_of(struct device_node *node, | 395 | static int rsrc_card_parse_of(struct device_node *node, |
| 342 | struct rsrc_card_priv *priv, | 396 | struct rsrc_card_priv *priv, |
| 343 | struct device *dev) | 397 | struct device *dev) |
| @@ -345,9 +399,8 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
| 345 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); | 399 | const struct rsrc_card_of_data *of_data = rsrc_dev_to_of_data(dev); |
| 346 | struct rsrc_card_dai *props; | 400 | struct rsrc_card_dai *props; |
| 347 | struct snd_soc_dai_link *links; | 401 | struct snd_soc_dai_link *links; |
| 348 | struct device_node *np; | ||
| 349 | int ret; | 402 | int ret; |
| 350 | int i, num; | 403 | int num; |
| 351 | 404 | ||
| 352 | if (!node) | 405 | if (!node) |
| 353 | return -EINVAL; | 406 | return -EINVAL; |
| @@ -388,13 +441,9 @@ static int rsrc_card_parse_of(struct device_node *node, | |||
| 388 | priv->snd_card.name ? priv->snd_card.name : "", | 441 | priv->snd_card.name ? priv->snd_card.name : "", |
| 389 | priv->convert_rate); | 442 | priv->convert_rate); |
| 390 | 443 | ||
| 391 | i = 0; | 444 | ret = rsrc_card_dai_link_of(node, priv); |
| 392 | for_each_child_of_node(node, np) { | 445 | if (ret < 0) |
| 393 | ret = rsrc_card_dai_link_of(node, np, priv, i); | 446 | return ret; |
| 394 | if (ret < 0) | ||
| 395 | return ret; | ||
| 396 | i++; | ||
| 397 | } | ||
| 398 | 447 | ||
| 399 | if (!priv->snd_card.name) | 448 | if (!priv->snd_card.name) |
| 400 | priv->snd_card.name = priv->snd_card.dai_link->name; | 449 | priv->snd_card.name = priv->snd_card.dai_link->name; |
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c index 68b439ed22d7..5eda056d9f20 100644 --- a/sound/soc/sh/rcar/src.c +++ b/sound/soc/sh/rcar/src.c | |||
| @@ -20,20 +20,21 @@ | |||
| 20 | #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) | 20 | #define OUF_SRC(id) ((1 << (id + 16)) | (1 << id)) |
| 21 | 21 | ||
| 22 | struct rsnd_src { | 22 | struct rsnd_src { |
| 23 | struct rsnd_src_platform_info *info; /* rcar_snd.h */ | ||
| 24 | struct rsnd_mod mod; | 23 | struct rsnd_mod mod; |
| 24 | struct rsnd_mod *dma; | ||
| 25 | struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ | 25 | struct rsnd_kctrl_cfg_s sen; /* sync convert enable */ |
| 26 | struct rsnd_kctrl_cfg_s sync; /* sync convert */ | 26 | struct rsnd_kctrl_cfg_s sync; /* sync convert */ |
| 27 | u32 convert_rate; /* sampling rate convert */ | 27 | u32 convert_rate; /* sampling rate convert */ |
| 28 | int err; | 28 | int err; |
| 29 | int irq; | ||
| 29 | }; | 30 | }; |
| 30 | 31 | ||
| 31 | #define RSND_SRC_NAME_SIZE 16 | 32 | #define RSND_SRC_NAME_SIZE 16 |
| 32 | 33 | ||
| 34 | #define rsnd_src_get(priv, id) ((struct rsnd_src *)(priv->src) + id) | ||
| 35 | #define rsnd_src_to_dma(src) ((src)->dma) | ||
| 33 | #define rsnd_src_nr(priv) ((priv)->src_nr) | 36 | #define rsnd_src_nr(priv) ((priv)->src_nr) |
| 34 | #define rsnd_enable_sync_convert(src) ((src)->sen.val) | 37 | #define rsnd_enable_sync_convert(src) ((src)->sen.val) |
| 35 | #define rsnd_src_of_node(priv) \ | ||
| 36 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,src") | ||
| 37 | 38 | ||
| 38 | #define rsnd_mod_to_src(_mod) \ | 39 | #define rsnd_mod_to_src(_mod) \ |
| 39 | container_of((_mod), struct rsnd_src, mod) | 40 | container_of((_mod), struct rsnd_src, mod) |
| @@ -69,67 +70,16 @@ struct rsnd_src { | |||
| 69 | * |-----------------| | 70 | * |-----------------| |
| 70 | */ | 71 | */ |
| 71 | 72 | ||
| 72 | /* | 73 | static void rsnd_src_activation(struct rsnd_mod *mod) |
| 73 | * How to use SRC bypass mode for debugging | ||
| 74 | * | ||
| 75 | * SRC has bypass mode, and it is useful for debugging. | ||
| 76 | * In Gen2 case, | ||
| 77 | * SRCm_MODE controls whether SRC is used or not | ||
| 78 | * SSI_MODE0 controls whether SSIU which receives SRC data | ||
| 79 | * is used or not. | ||
| 80 | * Both SRCm_MODE/SSI_MODE0 settings are needed if you use SRC, | ||
| 81 | * but SRC bypass mode needs SSI_MODE0 only. | ||
| 82 | * | ||
| 83 | * This driver request | ||
| 84 | * struct rsnd_src_platform_info { | ||
| 85 | * u32 convert_rate; | ||
| 86 | * int dma_id; | ||
| 87 | * } | ||
| 88 | * | ||
| 89 | * rsnd_src_convert_rate() indicates | ||
| 90 | * above convert_rate, and it controls | ||
| 91 | * whether SRC is used or not. | ||
| 92 | * | ||
| 93 | * ex) doesn't use SRC | ||
| 94 | * static struct rsnd_dai_platform_info rsnd_dai = { | ||
| 95 | * .playback = { .ssi = &rsnd_ssi[0], }, | ||
| 96 | * }; | ||
| 97 | * | ||
| 98 | * ex) uses SRC | ||
| 99 | * static struct rsnd_src_platform_info rsnd_src[] = { | ||
| 100 | * RSND_SCU(48000, 0), | ||
| 101 | * ... | ||
| 102 | * }; | ||
| 103 | * static struct rsnd_dai_platform_info rsnd_dai = { | ||
| 104 | * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, | ||
| 105 | * }; | ||
| 106 | * | ||
| 107 | * ex) uses SRC bypass mode | ||
| 108 | * static struct rsnd_src_platform_info rsnd_src[] = { | ||
| 109 | * RSND_SCU(0, 0), | ||
| 110 | * ... | ||
| 111 | * }; | ||
| 112 | * static struct rsnd_dai_platform_info rsnd_dai = { | ||
| 113 | * .playback = { .ssi = &rsnd_ssi[0], .src = &rsnd_src[0] }, | ||
| 114 | * }; | ||
| 115 | * | ||
| 116 | */ | ||
| 117 | |||
| 118 | /* | ||
| 119 | * Gen1/Gen2 common functions | ||
| 120 | */ | ||
| 121 | static void rsnd_src_soft_reset(struct rsnd_mod *mod) | ||
| 122 | { | 74 | { |
| 123 | rsnd_mod_write(mod, SRC_SWRSR, 0); | 75 | rsnd_mod_write(mod, SRC_SWRSR, 0); |
| 124 | rsnd_mod_write(mod, SRC_SWRSR, 1); | 76 | rsnd_mod_write(mod, SRC_SWRSR, 1); |
| 125 | } | 77 | } |
| 126 | 78 | ||
| 127 | 79 | static void rsnd_src_halt(struct rsnd_mod *mod) | |
| 128 | #define rsnd_src_initialize_lock(mod) __rsnd_src_initialize_lock(mod, 1) | ||
| 129 | #define rsnd_src_initialize_unlock(mod) __rsnd_src_initialize_lock(mod, 0) | ||
| 130 | static void __rsnd_src_initialize_lock(struct rsnd_mod *mod, u32 enable) | ||
| 131 | { | 80 | { |
| 132 | rsnd_mod_write(mod, SRC_SRCIR, enable); | 81 | rsnd_mod_write(mod, SRC_SRCIR, 1); |
| 82 | rsnd_mod_write(mod, SRC_SWRSR, 0); | ||
| 133 | } | 83 | } |
| 134 | 84 | ||
| 135 | static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, | 85 | static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, |
| @@ -143,99 +93,6 @@ static struct dma_chan *rsnd_src_dma_req(struct rsnd_dai_stream *io, | |||
| 143 | is_play ? "rx" : "tx"); | 93 | is_play ? "rx" : "tx"); |
| 144 | } | 94 | } |
| 145 | 95 | ||
| 146 | int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod, | ||
| 147 | struct rsnd_dai_stream *io, | ||
| 148 | int use_busif) | ||
| 149 | { | ||
| 150 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 151 | int ssi_id = rsnd_mod_id(ssi_mod); | ||
| 152 | |||
| 153 | /* | ||
| 154 | * SSI_MODE0 | ||
| 155 | */ | ||
| 156 | rsnd_mod_bset(ssi_mod, SSI_MODE0, (1 << ssi_id), | ||
| 157 | !use_busif << ssi_id); | ||
| 158 | |||
| 159 | /* | ||
| 160 | * SSI_MODE1 | ||
| 161 | */ | ||
| 162 | if (rsnd_ssi_is_pin_sharing(io)) { | ||
| 163 | int shift = -1; | ||
| 164 | switch (ssi_id) { | ||
| 165 | case 1: | ||
| 166 | shift = 0; | ||
| 167 | break; | ||
| 168 | case 2: | ||
| 169 | shift = 2; | ||
| 170 | break; | ||
| 171 | case 4: | ||
| 172 | shift = 16; | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | |||
| 176 | if (shift >= 0) | ||
| 177 | rsnd_mod_bset(ssi_mod, SSI_MODE1, | ||
| 178 | 0x3 << shift, | ||
| 179 | rsnd_rdai_is_clk_master(rdai) ? | ||
| 180 | 0x2 << shift : 0x1 << shift); | ||
| 181 | } | ||
| 182 | |||
| 183 | /* | ||
| 184 | * DMA settings for SSIU | ||
| 185 | */ | ||
| 186 | if (use_busif) { | ||
| 187 | u32 val = rsnd_get_dalign(ssi_mod, io); | ||
| 188 | |||
| 189 | rsnd_mod_write(ssi_mod, SSI_BUSIF_ADINR, | ||
| 190 | rsnd_get_adinr_bit(ssi_mod, io)); | ||
| 191 | rsnd_mod_write(ssi_mod, SSI_BUSIF_MODE, 1); | ||
| 192 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0x1); | ||
| 193 | |||
| 194 | rsnd_mod_write(ssi_mod, SSI_BUSIF_DALIGN, val); | ||
| 195 | } | ||
| 196 | |||
| 197 | return 0; | ||
| 198 | } | ||
| 199 | |||
| 200 | int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod, | ||
| 201 | struct rsnd_dai_stream *io) | ||
| 202 | { | ||
| 203 | /* | ||
| 204 | * DMA settings for SSIU | ||
| 205 | */ | ||
| 206 | rsnd_mod_write(ssi_mod, SSI_CTRL, 0); | ||
| 207 | |||
| 208 | return 0; | ||
| 209 | } | ||
| 210 | |||
| 211 | int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod) | ||
| 212 | { | ||
| 213 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 214 | |||
| 215 | if (rsnd_is_gen1(priv)) | ||
| 216 | return 0; | ||
| 217 | |||
| 218 | /* enable SSI interrupt if Gen2 */ | ||
| 219 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, | ||
| 220 | rsnd_ssi_is_dma_mode(ssi_mod) ? | ||
| 221 | 0x0e000000 : 0x0f000000); | ||
| 222 | |||
| 223 | return 0; | ||
| 224 | } | ||
| 225 | |||
| 226 | int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod) | ||
| 227 | { | ||
| 228 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 229 | |||
| 230 | if (rsnd_is_gen1(priv)) | ||
| 231 | return 0; | ||
| 232 | |||
| 233 | /* disable SSI interrupt if Gen2 */ | ||
| 234 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); | ||
| 235 | |||
| 236 | return 0; | ||
| 237 | } | ||
| 238 | |||
| 239 | static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, | 96 | static u32 rsnd_src_convert_rate(struct rsnd_dai_stream *io, |
| 240 | struct rsnd_src *src) | 97 | struct rsnd_src *src) |
| 241 | { | 98 | { |
| @@ -283,34 +140,6 @@ unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv, | |||
| 283 | return rate; | 140 | return rate; |
| 284 | } | 141 | } |
| 285 | 142 | ||
| 286 | static int rsnd_src_set_convert_rate(struct rsnd_mod *mod, | ||
| 287 | struct rsnd_dai_stream *io) | ||
| 288 | { | ||
| 289 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 290 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 291 | u32 convert_rate = rsnd_src_convert_rate(io, src); | ||
| 292 | u32 fsrate = 0; | ||
| 293 | |||
| 294 | if (convert_rate) | ||
| 295 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
| 296 | |||
| 297 | /* Set channel number and output bit length */ | ||
| 298 | rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr_bit(mod, io)); | ||
| 299 | |||
| 300 | /* Enable the initial value of IFS */ | ||
| 301 | if (fsrate) { | ||
| 302 | rsnd_mod_write(mod, SRC_IFSCR, 1); | ||
| 303 | |||
| 304 | /* Set initial value of IFS */ | ||
| 305 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
| 306 | } | ||
| 307 | |||
| 308 | /* use DMA transfer */ | ||
| 309 | rsnd_mod_write(mod, SRC_BUSIF_MODE, 1); | ||
| 310 | |||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static int rsnd_src_hw_params(struct rsnd_mod *mod, | 143 | static int rsnd_src_hw_params(struct rsnd_mod *mod, |
| 315 | struct rsnd_dai_stream *io, | 144 | struct rsnd_dai_stream *io, |
| 316 | struct snd_pcm_substream *substream, | 145 | struct snd_pcm_substream *substream, |
| @@ -319,9 +148,6 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, | |||
| 319 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 148 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 320 | struct snd_soc_pcm_runtime *fe = substream->private_data; | 149 | struct snd_soc_pcm_runtime *fe = substream->private_data; |
| 321 | 150 | ||
| 322 | /* default value (mainly for non-DT) */ | ||
| 323 | src->convert_rate = src->info->convert_rate; | ||
| 324 | |||
| 325 | /* | 151 | /* |
| 326 | * SRC assumes that it is used under DPCM if user want to use | 152 | * SRC assumes that it is used under DPCM if user want to use |
| 327 | * sampling rate convert. Then, SRC should be FE. | 153 | * sampling rate convert. Then, SRC should be FE. |
| @@ -347,250 +173,112 @@ static int rsnd_src_hw_params(struct rsnd_mod *mod, | |||
| 347 | return 0; | 173 | return 0; |
| 348 | } | 174 | } |
| 349 | 175 | ||
| 350 | static int rsnd_src_init(struct rsnd_mod *mod, | 176 | static void rsnd_src_set_convert_rate(struct rsnd_dai_stream *io, |
| 351 | struct rsnd_priv *priv) | 177 | struct rsnd_mod *mod) |
| 352 | { | ||
| 353 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 354 | |||
| 355 | rsnd_mod_power_on(mod); | ||
| 356 | |||
| 357 | rsnd_src_soft_reset(mod); | ||
| 358 | |||
| 359 | rsnd_src_initialize_lock(mod); | ||
| 360 | |||
| 361 | src->err = 0; | ||
| 362 | |||
| 363 | /* reset sync convert_rate */ | ||
| 364 | src->sync.val = 0; | ||
| 365 | |||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | static int rsnd_src_quit(struct rsnd_mod *mod, | ||
| 370 | struct rsnd_dai_stream *io, | ||
| 371 | struct rsnd_priv *priv) | ||
| 372 | { | 178 | { |
| 373 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 179 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 374 | struct device *dev = rsnd_priv_to_dev(priv); | 180 | struct device *dev = rsnd_priv_to_dev(priv); |
| 181 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 182 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 183 | u32 convert_rate = rsnd_src_convert_rate(io, src); | ||
| 184 | u32 ifscr, fsrate, adinr; | ||
| 185 | u32 cr, route; | ||
| 186 | u32 bsdsr, bsisr; | ||
| 187 | uint ratio; | ||
| 375 | 188 | ||
| 376 | rsnd_mod_power_off(mod); | 189 | if (!runtime) |
| 377 | 190 | return; | |
| 378 | if (src->err) | ||
| 379 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", | ||
| 380 | rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); | ||
| 381 | |||
| 382 | src->convert_rate = 0; | ||
| 383 | |||
| 384 | /* reset sync convert_rate */ | ||
| 385 | src->sync.val = 0; | ||
| 386 | |||
| 387 | return 0; | ||
| 388 | } | ||
| 389 | |||
| 390 | static int rsnd_src_start(struct rsnd_mod *mod) | ||
| 391 | { | ||
| 392 | rsnd_src_initialize_unlock(mod); | ||
| 393 | |||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | static int rsnd_src_stop(struct rsnd_mod *mod) | ||
| 398 | { | ||
| 399 | /* nothing to do */ | ||
| 400 | return 0; | ||
| 401 | } | ||
| 402 | 191 | ||
| 403 | /* | 192 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ |
| 404 | * Gen1 functions | 193 | if (!convert_rate) |
| 405 | */ | 194 | ratio = 0; |
| 406 | static int rsnd_src_set_route_gen1(struct rsnd_dai_stream *io, | 195 | else if (convert_rate > runtime->rate) |
| 407 | struct rsnd_mod *mod) | 196 | ratio = 100 * convert_rate / runtime->rate; |
| 408 | { | 197 | else |
| 409 | struct src_route_config { | 198 | ratio = 100 * runtime->rate / convert_rate; |
| 410 | u32 mask; | ||
| 411 | int shift; | ||
| 412 | } routes[] = { | ||
| 413 | { 0xF, 0, }, /* 0 */ | ||
| 414 | { 0xF, 4, }, /* 1 */ | ||
| 415 | { 0xF, 8, }, /* 2 */ | ||
| 416 | { 0x7, 12, }, /* 3 */ | ||
| 417 | { 0x7, 16, }, /* 4 */ | ||
| 418 | { 0x7, 20, }, /* 5 */ | ||
| 419 | { 0x7, 24, }, /* 6 */ | ||
| 420 | { 0x3, 28, }, /* 7 */ | ||
| 421 | { 0x3, 30, }, /* 8 */ | ||
| 422 | }; | ||
| 423 | u32 mask; | ||
| 424 | u32 val; | ||
| 425 | int id; | ||
| 426 | 199 | ||
| 427 | id = rsnd_mod_id(mod); | 200 | if (ratio > 600) { |
| 428 | if (id < 0 || id >= ARRAY_SIZE(routes)) | 201 | dev_err(dev, "FSO/FSI ratio error\n"); |
| 429 | return -EIO; | 202 | return; |
| 203 | } | ||
| 430 | 204 | ||
| 431 | /* | 205 | /* |
| 432 | * SRC_ROUTE_SELECT | 206 | * SRC_ADINR |
| 433 | */ | 207 | */ |
| 434 | val = rsnd_io_is_play(io) ? 0x1 : 0x2; | 208 | adinr = rsnd_get_adinr_bit(mod, io) | |
| 435 | val = val << routes[id].shift; | 209 | rsnd_get_adinr_chan(mod, io); |
| 436 | mask = routes[id].mask << routes[id].shift; | ||
| 437 | |||
| 438 | rsnd_mod_bset(mod, SRC_ROUTE_SEL, mask, val); | ||
| 439 | |||
| 440 | return 0; | ||
| 441 | } | ||
| 442 | |||
| 443 | static int rsnd_src_set_convert_timing_gen1(struct rsnd_dai_stream *io, | ||
| 444 | struct rsnd_mod *mod) | ||
| 445 | { | ||
| 446 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 447 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 448 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 449 | u32 convert_rate = rsnd_src_convert_rate(io, src); | ||
| 450 | u32 mask; | ||
| 451 | u32 val; | ||
| 452 | int shift; | ||
| 453 | int id = rsnd_mod_id(mod); | ||
| 454 | int ret; | ||
| 455 | 210 | ||
| 456 | /* | 211 | /* |
| 457 | * SRC_TIMING_SELECT | 212 | * SRC_IFSCR / SRC_IFSVR |
| 458 | */ | 213 | */ |
| 459 | shift = (id % 4) * 8; | 214 | ifscr = 0; |
| 460 | mask = 0x1F << shift; | 215 | fsrate = 0; |
| 216 | if (convert_rate) { | ||
| 217 | ifscr = 1; | ||
| 218 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
| 219 | } | ||
| 461 | 220 | ||
| 462 | /* | 221 | /* |
| 463 | * ADG is used as source clock if SRC was used, | 222 | * SRC_SRCCR / SRC_ROUTE_MODE0 |
| 464 | * then, SSI WS is used as destination clock. | ||
| 465 | * SSI WS is used as source clock if SRC is not used | ||
| 466 | * (when playback, source/destination become reverse when capture) | ||
| 467 | */ | 223 | */ |
| 468 | ret = 0; | 224 | cr = 0x00011110; |
| 225 | route = 0x0; | ||
| 469 | if (convert_rate) { | 226 | if (convert_rate) { |
| 470 | /* use ADG */ | 227 | route = 0x1; |
| 471 | val = 0; | ||
| 472 | ret = rsnd_adg_set_convert_clk_gen1(priv, mod, | ||
| 473 | runtime->rate, | ||
| 474 | convert_rate); | ||
| 475 | } else if (8 == id) { | ||
| 476 | /* use SSI WS, but SRU8 is special */ | ||
| 477 | val = id << shift; | ||
| 478 | } else { | ||
| 479 | /* use SSI WS */ | ||
| 480 | val = (id + 1) << shift; | ||
| 481 | } | ||
| 482 | 228 | ||
| 483 | if (ret < 0) | 229 | if (rsnd_enable_sync_convert(src)) { |
| 484 | return ret; | 230 | cr |= 0x1; |
| 231 | route |= rsnd_io_is_play(io) ? | ||
| 232 | (0x1 << 24) : (0x1 << 25); | ||
| 233 | } | ||
| 234 | } | ||
| 485 | 235 | ||
| 486 | switch (id / 4) { | 236 | /* |
| 487 | case 0: | 237 | * SRC_BSDSR / SRC_BSISR |
| 488 | rsnd_mod_bset(mod, SRC_TMG_SEL0, mask, val); | 238 | */ |
| 489 | break; | 239 | switch (rsnd_mod_id(mod)) { |
| 490 | case 1: | 240 | case 5: |
| 491 | rsnd_mod_bset(mod, SRC_TMG_SEL1, mask, val); | 241 | case 6: |
| 242 | case 7: | ||
| 243 | case 8: | ||
| 244 | bsdsr = 0x02400000; /* 6 - 1/6 */ | ||
| 245 | bsisr = 0x00100060; /* 6 - 1/6 */ | ||
| 492 | break; | 246 | break; |
| 493 | case 2: | 247 | default: |
| 494 | rsnd_mod_bset(mod, SRC_TMG_SEL2, mask, val); | 248 | bsdsr = 0x01800000; /* 6 - 1/6 */ |
| 249 | bsisr = 0x00100060 ;/* 6 - 1/6 */ | ||
| 495 | break; | 250 | break; |
| 496 | } | 251 | } |
| 497 | 252 | ||
| 498 | return 0; | 253 | rsnd_mod_write(mod, SRC_SRCIR, 1); /* initialize */ |
| 499 | } | 254 | rsnd_mod_write(mod, SRC_ADINR, adinr); |
| 500 | 255 | rsnd_mod_write(mod, SRC_IFSCR, ifscr); | |
| 501 | static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod, | 256 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); |
| 502 | struct rsnd_dai_stream *io) | 257 | rsnd_mod_write(mod, SRC_SRCCR, cr); |
| 503 | { | 258 | rsnd_mod_write(mod, SRC_BSDSR, bsdsr); |
| 504 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 259 | rsnd_mod_write(mod, SRC_BSISR, bsisr); |
| 505 | int ret; | 260 | rsnd_mod_write(mod, SRC_SRCIR, 0); /* cancel initialize */ |
| 506 | |||
| 507 | ret = rsnd_src_set_convert_rate(mod, io); | ||
| 508 | if (ret < 0) | ||
| 509 | return ret; | ||
| 510 | |||
| 511 | /* Select SRC mode (fixed value) */ | ||
| 512 | rsnd_mod_write(mod, SRC_SRCCR, 0x00010110); | ||
| 513 | |||
| 514 | /* Set the restriction value of the FS ratio (98%) */ | ||
| 515 | rsnd_mod_write(mod, SRC_MNFSR, | ||
| 516 | rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98); | ||
| 517 | |||
| 518 | /* Gen1/Gen2 are not compatible */ | ||
| 519 | if (rsnd_src_convert_rate(io, src)) | ||
| 520 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1); | ||
| 521 | |||
| 522 | /* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */ | ||
| 523 | |||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | static int rsnd_src_init_gen1(struct rsnd_mod *mod, | ||
| 528 | struct rsnd_dai_stream *io, | ||
| 529 | struct rsnd_priv *priv) | ||
| 530 | { | ||
| 531 | int ret; | ||
| 532 | |||
| 533 | ret = rsnd_src_init(mod, priv); | ||
| 534 | if (ret < 0) | ||
| 535 | return ret; | ||
| 536 | |||
| 537 | ret = rsnd_src_set_route_gen1(io, mod); | ||
| 538 | if (ret < 0) | ||
| 539 | return ret; | ||
| 540 | |||
| 541 | ret = rsnd_src_set_convert_rate_gen1(mod, io); | ||
| 542 | if (ret < 0) | ||
| 543 | return ret; | ||
| 544 | |||
| 545 | ret = rsnd_src_set_convert_timing_gen1(io, mod); | ||
| 546 | if (ret < 0) | ||
| 547 | return ret; | ||
| 548 | |||
| 549 | return 0; | ||
| 550 | } | ||
| 551 | |||
| 552 | static int rsnd_src_start_gen1(struct rsnd_mod *mod, | ||
| 553 | struct rsnd_dai_stream *io, | ||
| 554 | struct rsnd_priv *priv) | ||
| 555 | { | ||
| 556 | int id = rsnd_mod_id(mod); | ||
| 557 | |||
| 558 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id)); | ||
| 559 | |||
| 560 | return rsnd_src_start(mod); | ||
| 561 | } | ||
| 562 | |||
| 563 | static int rsnd_src_stop_gen1(struct rsnd_mod *mod, | ||
| 564 | struct rsnd_dai_stream *io, | ||
| 565 | struct rsnd_priv *priv) | ||
| 566 | { | ||
| 567 | int id = rsnd_mod_id(mod); | ||
| 568 | 261 | ||
| 569 | rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0); | 262 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); |
| 263 | rsnd_mod_write(mod, SRC_I_BUSIF_MODE, 1); | ||
| 264 | rsnd_mod_write(mod, SRC_O_BUSIF_MODE, 1); | ||
| 265 | rsnd_mod_write(mod, SRC_BUSIF_DALIGN, rsnd_get_dalign(mod, io)); | ||
| 570 | 266 | ||
| 571 | return rsnd_src_stop(mod); | 267 | if (convert_rate) |
| 268 | rsnd_adg_set_convert_clk_gen2(mod, io, | ||
| 269 | runtime->rate, | ||
| 270 | convert_rate); | ||
| 271 | else | ||
| 272 | rsnd_adg_set_convert_timing_gen2(mod, io); | ||
| 572 | } | 273 | } |
| 573 | 274 | ||
| 574 | static struct rsnd_mod_ops rsnd_src_gen1_ops = { | 275 | #define rsnd_src_irq_enable(mod) rsnd_src_irq_ctrol(mod, 1) |
| 575 | .name = SRC_NAME, | 276 | #define rsnd_src_irq_disable(mod) rsnd_src_irq_ctrol(mod, 0) |
| 576 | .dma_req = rsnd_src_dma_req, | 277 | static void rsnd_src_irq_ctrol(struct rsnd_mod *mod, int enable) |
| 577 | .init = rsnd_src_init_gen1, | ||
| 578 | .quit = rsnd_src_quit, | ||
| 579 | .start = rsnd_src_start_gen1, | ||
| 580 | .stop = rsnd_src_stop_gen1, | ||
| 581 | .hw_params = rsnd_src_hw_params, | ||
| 582 | }; | ||
| 583 | |||
| 584 | /* | ||
| 585 | * Gen2 functions | ||
| 586 | */ | ||
| 587 | #define rsnd_src_irq_enable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 1) | ||
| 588 | #define rsnd_src_irq_disable_gen2(mod) rsnd_src_irq_ctrol_gen2(mod, 0) | ||
| 589 | static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) | ||
| 590 | { | 278 | { |
| 591 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 279 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 592 | u32 sys_int_val, int_val, sys_int_mask; | 280 | u32 sys_int_val, int_val, sys_int_mask; |
| 593 | int irq = src->info->irq; | 281 | int irq = src->irq; |
| 594 | int id = rsnd_mod_id(mod); | 282 | int id = rsnd_mod_id(mod); |
| 595 | 283 | ||
| 596 | sys_int_val = | 284 | sys_int_val = |
| @@ -600,7 +288,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) | |||
| 600 | /* | 288 | /* |
| 601 | * IRQ is not supported on non-DT | 289 | * IRQ is not supported on non-DT |
| 602 | * see | 290 | * see |
| 603 | * rsnd_src_probe_gen2() | 291 | * rsnd_src_probe_() |
| 604 | */ | 292 | */ |
| 605 | if ((irq <= 0) || !enable) { | 293 | if ((irq <= 0) || !enable) { |
| 606 | sys_int_val = 0; | 294 | sys_int_val = 0; |
| @@ -620,7 +308,7 @@ static void rsnd_src_irq_ctrol_gen2(struct rsnd_mod *mod, int enable) | |||
| 620 | rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); | 308 | rsnd_mod_bset(mod, SCU_SYS_INT_EN1, sys_int_mask, sys_int_val); |
| 621 | } | 309 | } |
| 622 | 310 | ||
| 623 | static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) | 311 | static void rsnd_src_status_clear(struct rsnd_mod *mod) |
| 624 | { | 312 | { |
| 625 | u32 val = OUF_SRC(rsnd_mod_id(mod)); | 313 | u32 val = OUF_SRC(rsnd_mod_id(mod)); |
| 626 | 314 | ||
| @@ -628,7 +316,7 @@ static void rsnd_src_error_clear_gen2(struct rsnd_mod *mod) | |||
| 628 | rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); | 316 | rsnd_mod_bset(mod, SCU_SYS_STATUS1, val, val); |
| 629 | } | 317 | } |
| 630 | 318 | ||
| 631 | static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) | 319 | static bool rsnd_src_record_error(struct rsnd_mod *mod) |
| 632 | { | 320 | { |
| 633 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 321 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 634 | u32 val0, val1; | 322 | u32 val0, val1; |
| @@ -652,22 +340,16 @@ static bool rsnd_src_error_record_gen2(struct rsnd_mod *mod) | |||
| 652 | ret = true; | 340 | ret = true; |
| 653 | } | 341 | } |
| 654 | 342 | ||
| 655 | /* clear error static */ | ||
| 656 | rsnd_src_error_clear_gen2(mod); | ||
| 657 | |||
| 658 | return ret; | 343 | return ret; |
| 659 | } | 344 | } |
| 660 | 345 | ||
| 661 | static int _rsnd_src_start_gen2(struct rsnd_mod *mod, | 346 | static int rsnd_src_start(struct rsnd_mod *mod, |
| 662 | struct rsnd_dai_stream *io) | 347 | struct rsnd_dai_stream *io, |
| 348 | struct rsnd_priv *priv) | ||
| 663 | { | 349 | { |
| 664 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 350 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 665 | u32 val; | 351 | u32 val; |
| 666 | 352 | ||
| 667 | val = rsnd_get_dalign(mod, io); | ||
| 668 | |||
| 669 | rsnd_mod_write(mod, SRC_BUSIF_DALIGN, val); | ||
| 670 | |||
| 671 | /* | 353 | /* |
| 672 | * WORKAROUND | 354 | * WORKAROUND |
| 673 | * | 355 | * |
| @@ -678,247 +360,149 @@ static int _rsnd_src_start_gen2(struct rsnd_mod *mod, | |||
| 678 | 360 | ||
| 679 | rsnd_mod_write(mod, SRC_CTRL, val); | 361 | rsnd_mod_write(mod, SRC_CTRL, val); |
| 680 | 362 | ||
| 681 | rsnd_src_error_clear_gen2(mod); | 363 | return 0; |
| 682 | 364 | } | |
| 683 | rsnd_src_start(mod); | ||
| 684 | 365 | ||
| 685 | rsnd_src_irq_enable_gen2(mod); | 366 | static int rsnd_src_stop(struct rsnd_mod *mod, |
| 367 | struct rsnd_dai_stream *io, | ||
| 368 | struct rsnd_priv *priv) | ||
| 369 | { | ||
| 370 | /* | ||
| 371 | * stop SRC output only | ||
| 372 | * see rsnd_src_quit | ||
| 373 | */ | ||
| 374 | rsnd_mod_write(mod, SRC_CTRL, 0x01); | ||
| 686 | 375 | ||
| 687 | return 0; | 376 | return 0; |
| 688 | } | 377 | } |
| 689 | 378 | ||
| 690 | static int _rsnd_src_stop_gen2(struct rsnd_mod *mod) | 379 | static int rsnd_src_init(struct rsnd_mod *mod, |
| 380 | struct rsnd_dai_stream *io, | ||
| 381 | struct rsnd_priv *priv) | ||
| 691 | { | 382 | { |
| 692 | rsnd_src_irq_disable_gen2(mod); | 383 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 693 | 384 | ||
| 694 | rsnd_mod_write(mod, SRC_CTRL, 0); | 385 | rsnd_mod_power_on(mod); |
| 386 | |||
| 387 | rsnd_src_activation(mod); | ||
| 388 | |||
| 389 | rsnd_src_set_convert_rate(io, mod); | ||
| 695 | 390 | ||
| 696 | rsnd_src_error_record_gen2(mod); | 391 | rsnd_src_status_clear(mod); |
| 392 | |||
| 393 | rsnd_src_irq_enable(mod); | ||
| 394 | |||
| 395 | src->err = 0; | ||
| 697 | 396 | ||
| 698 | return rsnd_src_stop(mod); | 397 | /* reset sync convert_rate */ |
| 398 | src->sync.val = 0; | ||
| 399 | |||
| 400 | return 0; | ||
| 699 | } | 401 | } |
| 700 | 402 | ||
| 701 | static void __rsnd_src_interrupt_gen2(struct rsnd_mod *mod, | 403 | static int rsnd_src_quit(struct rsnd_mod *mod, |
| 702 | struct rsnd_dai_stream *io) | 404 | struct rsnd_dai_stream *io, |
| 405 | struct rsnd_priv *priv) | ||
| 703 | { | 406 | { |
| 704 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 407 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 705 | 408 | struct device *dev = rsnd_priv_to_dev(priv); | |
| 706 | spin_lock(&priv->lock); | ||
| 707 | 409 | ||
| 708 | /* ignore all cases if not working */ | 410 | rsnd_src_irq_disable(mod); |
| 709 | if (!rsnd_io_is_working(io)) | ||
| 710 | goto rsnd_src_interrupt_gen2_out; | ||
| 711 | 411 | ||
| 712 | if (rsnd_src_error_record_gen2(mod)) { | 412 | /* stop both out/in */ |
| 713 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 413 | rsnd_mod_write(mod, SRC_CTRL, 0); |
| 714 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 715 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 716 | 414 | ||
| 717 | dev_dbg(dev, "%s[%d] restart\n", | 415 | rsnd_src_halt(mod); |
| 718 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 719 | 416 | ||
| 720 | _rsnd_src_stop_gen2(mod); | 417 | rsnd_mod_power_off(mod); |
| 721 | if (src->err < 1024) | ||
| 722 | _rsnd_src_start_gen2(mod, io); | ||
| 723 | else | ||
| 724 | dev_warn(dev, "no more SRC restart\n"); | ||
| 725 | } | ||
| 726 | 418 | ||
| 727 | rsnd_src_interrupt_gen2_out: | 419 | if (src->err) |
| 728 | spin_unlock(&priv->lock); | 420 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", |
| 729 | } | 421 | rsnd_mod_name(mod), rsnd_mod_id(mod), src->err); |
| 730 | 422 | ||
| 731 | static irqreturn_t rsnd_src_interrupt_gen2(int irq, void *data) | 423 | src->convert_rate = 0; |
| 732 | { | ||
| 733 | struct rsnd_mod *mod = data; | ||
| 734 | 424 | ||
| 735 | rsnd_mod_interrupt(mod, __rsnd_src_interrupt_gen2); | 425 | /* reset sync convert_rate */ |
| 426 | src->sync.val = 0; | ||
| 736 | 427 | ||
| 737 | return IRQ_HANDLED; | 428 | return 0; |
| 738 | } | 429 | } |
| 739 | 430 | ||
| 740 | static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod, | 431 | static void __rsnd_src_interrupt(struct rsnd_mod *mod, |
| 741 | struct rsnd_dai_stream *io) | 432 | struct rsnd_dai_stream *io) |
| 742 | { | 433 | { |
| 743 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 434 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 744 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 745 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 746 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 435 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 747 | u32 convert_rate = rsnd_src_convert_rate(io, src); | 436 | struct device *dev = rsnd_priv_to_dev(priv); |
| 748 | u32 cr, route; | ||
| 749 | uint ratio; | ||
| 750 | int ret; | ||
| 751 | 437 | ||
| 752 | /* 6 - 1/6 are very enough ratio for SRC_BSDSR */ | 438 | spin_lock(&priv->lock); |
| 753 | if (!convert_rate) | ||
| 754 | ratio = 0; | ||
| 755 | else if (convert_rate > runtime->rate) | ||
| 756 | ratio = 100 * convert_rate / runtime->rate; | ||
| 757 | else | ||
| 758 | ratio = 100 * runtime->rate / convert_rate; | ||
| 759 | 439 | ||
| 760 | if (ratio > 600) { | 440 | /* ignore all cases if not working */ |
| 761 | dev_err(dev, "FSO/FSI ratio error\n"); | 441 | if (!rsnd_io_is_working(io)) |
| 762 | return -EINVAL; | 442 | goto rsnd_src_interrupt_out; |
| 763 | } | ||
| 764 | 443 | ||
| 765 | ret = rsnd_src_set_convert_rate(mod, io); | 444 | if (rsnd_src_record_error(mod)) { |
| 766 | if (ret < 0) | ||
| 767 | return ret; | ||
| 768 | 445 | ||
| 769 | cr = 0x00011110; | 446 | dev_dbg(dev, "%s[%d] restart\n", |
| 770 | route = 0x0; | 447 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
| 771 | if (convert_rate) { | ||
| 772 | route = 0x1; | ||
| 773 | 448 | ||
| 774 | if (rsnd_enable_sync_convert(src)) { | 449 | rsnd_src_stop(mod, io, priv); |
| 775 | cr |= 0x1; | 450 | rsnd_src_start(mod, io, priv); |
| 776 | route |= rsnd_io_is_play(io) ? | ||
| 777 | (0x1 << 24) : (0x1 << 25); | ||
| 778 | } | ||
| 779 | } | 451 | } |
| 780 | 452 | ||
| 781 | rsnd_mod_write(mod, SRC_SRCCR, cr); | 453 | if (src->err > 1024) { |
| 782 | rsnd_mod_write(mod, SRC_ROUTE_MODE0, route); | 454 | rsnd_src_irq_disable(mod); |
| 783 | 455 | ||
| 784 | switch (rsnd_mod_id(mod)) { | 456 | dev_warn(dev, "no more %s[%d] restart\n", |
| 785 | case 5: | 457 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
| 786 | case 6: | ||
| 787 | case 7: | ||
| 788 | case 8: | ||
| 789 | rsnd_mod_write(mod, SRC_BSDSR, 0x02400000); | ||
| 790 | break; | ||
| 791 | default: | ||
| 792 | rsnd_mod_write(mod, SRC_BSDSR, 0x01800000); | ||
| 793 | break; | ||
| 794 | } | 458 | } |
| 795 | 459 | ||
| 796 | rsnd_mod_write(mod, SRC_BSISR, 0x00100060); | 460 | rsnd_src_status_clear(mod); |
| 461 | rsnd_src_interrupt_out: | ||
| 797 | 462 | ||
| 798 | return 0; | 463 | spin_unlock(&priv->lock); |
| 799 | } | 464 | } |
| 800 | 465 | ||
| 801 | static int rsnd_src_set_convert_timing_gen2(struct rsnd_dai_stream *io, | 466 | static irqreturn_t rsnd_src_interrupt(int irq, void *data) |
| 802 | struct rsnd_mod *mod) | ||
| 803 | { | 467 | { |
| 804 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 468 | struct rsnd_mod *mod = data; |
| 805 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 806 | u32 convert_rate = rsnd_src_convert_rate(io, src); | ||
| 807 | int ret; | ||
| 808 | 469 | ||
| 809 | if (convert_rate) | 470 | rsnd_mod_interrupt(mod, __rsnd_src_interrupt); |
| 810 | ret = rsnd_adg_set_convert_clk_gen2(mod, io, | ||
| 811 | runtime->rate, | ||
| 812 | convert_rate); | ||
| 813 | else | ||
| 814 | ret = rsnd_adg_set_convert_timing_gen2(mod, io); | ||
| 815 | 471 | ||
| 816 | return ret; | 472 | return IRQ_HANDLED; |
| 817 | } | 473 | } |
| 818 | 474 | ||
| 819 | static int rsnd_src_probe_gen2(struct rsnd_mod *mod, | 475 | static int rsnd_src_probe_(struct rsnd_mod *mod, |
| 820 | struct rsnd_dai_stream *io, | 476 | struct rsnd_dai_stream *io, |
| 821 | struct rsnd_priv *priv) | 477 | struct rsnd_priv *priv) |
| 822 | { | 478 | { |
| 823 | struct rsnd_src *src = rsnd_mod_to_src(mod); | 479 | struct rsnd_src *src = rsnd_mod_to_src(mod); |
| 824 | struct device *dev = rsnd_priv_to_dev(priv); | 480 | struct device *dev = rsnd_priv_to_dev(priv); |
| 825 | int irq = src->info->irq; | 481 | int irq = src->irq; |
| 826 | int ret; | 482 | int ret; |
| 827 | 483 | ||
| 828 | if (irq > 0) { | 484 | if (irq > 0) { |
| 829 | /* | 485 | /* |
| 830 | * IRQ is not supported on non-DT | 486 | * IRQ is not supported on non-DT |
| 831 | * see | 487 | * see |
| 832 | * rsnd_src_irq_enable_gen2() | 488 | * rsnd_src_irq_enable() |
| 833 | */ | 489 | */ |
| 834 | ret = devm_request_irq(dev, irq, | 490 | ret = devm_request_irq(dev, irq, |
| 835 | rsnd_src_interrupt_gen2, | 491 | rsnd_src_interrupt, |
| 836 | IRQF_SHARED, | 492 | IRQF_SHARED, |
| 837 | dev_name(dev), mod); | 493 | dev_name(dev), mod); |
| 838 | if (ret) | 494 | if (ret) |
| 839 | return ret; | 495 | return ret; |
| 840 | } | 496 | } |
| 841 | 497 | ||
| 842 | ret = rsnd_dma_init(io, | 498 | src->dma = rsnd_dma_attach(io, mod, 0); |
| 843 | rsnd_mod_to_dma(mod), | 499 | if (IS_ERR(src->dma)) |
| 844 | src->info->dma_id); | 500 | return PTR_ERR(src->dma); |
| 845 | 501 | ||
| 846 | return ret; | 502 | return ret; |
| 847 | } | 503 | } |
| 848 | 504 | ||
| 849 | static int rsnd_src_remove_gen2(struct rsnd_mod *mod, | 505 | static int rsnd_src_pcm_new(struct rsnd_mod *mod, |
| 850 | struct rsnd_dai_stream *io, | ||
| 851 | struct rsnd_priv *priv) | ||
| 852 | { | ||
| 853 | rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); | ||
| 854 | |||
| 855 | return 0; | ||
| 856 | } | ||
| 857 | |||
| 858 | static int rsnd_src_init_gen2(struct rsnd_mod *mod, | ||
| 859 | struct rsnd_dai_stream *io, | ||
| 860 | struct rsnd_priv *priv) | ||
| 861 | { | ||
| 862 | int ret; | ||
| 863 | |||
| 864 | ret = rsnd_src_init(mod, priv); | ||
| 865 | if (ret < 0) | ||
| 866 | return ret; | ||
| 867 | |||
| 868 | ret = rsnd_src_set_convert_rate_gen2(mod, io); | ||
| 869 | if (ret < 0) | ||
| 870 | return ret; | ||
| 871 | |||
| 872 | ret = rsnd_src_set_convert_timing_gen2(io, mod); | ||
| 873 | if (ret < 0) | ||
| 874 | return ret; | ||
| 875 | |||
| 876 | return 0; | ||
| 877 | } | ||
| 878 | |||
| 879 | static int rsnd_src_start_gen2(struct rsnd_mod *mod, | ||
| 880 | struct rsnd_dai_stream *io, | ||
| 881 | struct rsnd_priv *priv) | ||
| 882 | { | ||
| 883 | rsnd_dma_start(io, rsnd_mod_to_dma(mod)); | ||
| 884 | |||
| 885 | return _rsnd_src_start_gen2(mod, io); | ||
| 886 | } | ||
| 887 | |||
| 888 | static int rsnd_src_stop_gen2(struct rsnd_mod *mod, | ||
| 889 | struct rsnd_dai_stream *io, | ||
| 890 | struct rsnd_priv *priv) | ||
| 891 | { | ||
| 892 | int ret; | ||
| 893 | |||
| 894 | ret = _rsnd_src_stop_gen2(mod); | ||
| 895 | |||
| 896 | rsnd_dma_stop(io, rsnd_mod_to_dma(mod)); | ||
| 897 | |||
| 898 | return ret; | ||
| 899 | } | ||
| 900 | |||
| 901 | static void rsnd_src_reconvert_update(struct rsnd_dai_stream *io, | ||
| 902 | struct rsnd_mod *mod) | ||
| 903 | { | ||
| 904 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 905 | struct rsnd_src *src = rsnd_mod_to_src(mod); | ||
| 906 | u32 convert_rate = rsnd_src_convert_rate(io, src); | ||
| 907 | u32 fsrate; | ||
| 908 | |||
| 909 | if (!runtime) | ||
| 910 | return; | ||
| 911 | |||
| 912 | if (!convert_rate) | ||
| 913 | convert_rate = runtime->rate; | ||
| 914 | |||
| 915 | fsrate = 0x0400000 / convert_rate * runtime->rate; | ||
| 916 | |||
| 917 | /* update IFS */ | ||
| 918 | rsnd_mod_write(mod, SRC_IFSVR, fsrate); | ||
| 919 | } | ||
| 920 | |||
| 921 | static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, | ||
| 922 | struct rsnd_dai_stream *io, | 506 | struct rsnd_dai_stream *io, |
| 923 | struct snd_soc_pcm_runtime *rtd) | 507 | struct snd_soc_pcm_runtime *rtd) |
| 924 | { | 508 | { |
| @@ -950,7 +534,7 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, | |||
| 950 | rsnd_io_is_play(io) ? | 534 | rsnd_io_is_play(io) ? |
| 951 | "SRC Out Rate Switch" : | 535 | "SRC Out Rate Switch" : |
| 952 | "SRC In Rate Switch", | 536 | "SRC In Rate Switch", |
| 953 | rsnd_src_reconvert_update, | 537 | rsnd_src_set_convert_rate, |
| 954 | &src->sen, 1); | 538 | &src->sen, 1); |
| 955 | if (ret < 0) | 539 | if (ret < 0) |
| 956 | return ret; | 540 | return ret; |
| @@ -959,23 +543,22 @@ static int rsnd_src_pcm_new_gen2(struct rsnd_mod *mod, | |||
| 959 | rsnd_io_is_play(io) ? | 543 | rsnd_io_is_play(io) ? |
| 960 | "SRC Out Rate" : | 544 | "SRC Out Rate" : |
| 961 | "SRC In Rate", | 545 | "SRC In Rate", |
| 962 | rsnd_src_reconvert_update, | 546 | rsnd_src_set_convert_rate, |
| 963 | &src->sync, 192000); | 547 | &src->sync, 192000); |
| 964 | 548 | ||
| 965 | return ret; | 549 | return ret; |
| 966 | } | 550 | } |
| 967 | 551 | ||
| 968 | static struct rsnd_mod_ops rsnd_src_gen2_ops = { | 552 | static struct rsnd_mod_ops rsnd_src_ops = { |
| 969 | .name = SRC_NAME, | 553 | .name = SRC_NAME, |
| 970 | .dma_req = rsnd_src_dma_req, | 554 | .dma_req = rsnd_src_dma_req, |
| 971 | .probe = rsnd_src_probe_gen2, | 555 | .probe = rsnd_src_probe_, |
| 972 | .remove = rsnd_src_remove_gen2, | 556 | .init = rsnd_src_init, |
| 973 | .init = rsnd_src_init_gen2, | ||
| 974 | .quit = rsnd_src_quit, | 557 | .quit = rsnd_src_quit, |
| 975 | .start = rsnd_src_start_gen2, | 558 | .start = rsnd_src_start, |
| 976 | .stop = rsnd_src_stop_gen2, | 559 | .stop = rsnd_src_stop, |
| 977 | .hw_params = rsnd_src_hw_params, | 560 | .hw_params = rsnd_src_hw_params, |
| 978 | .pcm_new = rsnd_src_pcm_new_gen2, | 561 | .pcm_new = rsnd_src_pcm_new, |
| 979 | }; | 562 | }; |
| 980 | 563 | ||
| 981 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | 564 | struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) |
| @@ -983,113 +566,78 @@ struct rsnd_mod *rsnd_src_mod_get(struct rsnd_priv *priv, int id) | |||
| 983 | if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) | 566 | if (WARN_ON(id < 0 || id >= rsnd_src_nr(priv))) |
| 984 | id = 0; | 567 | id = 0; |
| 985 | 568 | ||
| 986 | return rsnd_mod_get((struct rsnd_src *)(priv->src) + id); | 569 | return rsnd_mod_get(rsnd_src_get(priv, id)); |
| 987 | } | 570 | } |
| 988 | 571 | ||
| 989 | static void rsnd_of_parse_src(struct platform_device *pdev, | 572 | int rsnd_src_probe(struct rsnd_priv *priv) |
| 990 | const struct rsnd_of_data *of_data, | ||
| 991 | struct rsnd_priv *priv) | ||
| 992 | { | 573 | { |
| 993 | struct device_node *src_node; | 574 | struct device_node *node; |
| 994 | struct device_node *np; | 575 | struct device_node *np; |
| 995 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 996 | struct rsnd_src_platform_info *src_info; | ||
| 997 | struct device *dev = &pdev->dev; | ||
| 998 | int nr, i; | ||
| 999 | |||
| 1000 | if (!of_data) | ||
| 1001 | return; | ||
| 1002 | |||
| 1003 | src_node = rsnd_src_of_node(priv); | ||
| 1004 | if (!src_node) | ||
| 1005 | return; | ||
| 1006 | |||
| 1007 | nr = of_get_child_count(src_node); | ||
| 1008 | if (!nr) | ||
| 1009 | goto rsnd_of_parse_src_end; | ||
| 1010 | |||
| 1011 | src_info = devm_kzalloc(dev, | ||
| 1012 | sizeof(struct rsnd_src_platform_info) * nr, | ||
| 1013 | GFP_KERNEL); | ||
| 1014 | if (!src_info) { | ||
| 1015 | dev_err(dev, "src info allocation error\n"); | ||
| 1016 | goto rsnd_of_parse_src_end; | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | info->src_info = src_info; | ||
| 1020 | info->src_info_nr = nr; | ||
| 1021 | |||
| 1022 | i = 0; | ||
| 1023 | for_each_child_of_node(src_node, np) { | ||
| 1024 | src_info[i].irq = irq_of_parse_and_map(np, 0); | ||
| 1025 | |||
| 1026 | i++; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | rsnd_of_parse_src_end: | ||
| 1030 | of_node_put(src_node); | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | int rsnd_src_probe(struct platform_device *pdev, | ||
| 1034 | const struct rsnd_of_data *of_data, | ||
| 1035 | struct rsnd_priv *priv) | ||
| 1036 | { | ||
| 1037 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | ||
| 1038 | struct device *dev = rsnd_priv_to_dev(priv); | 576 | struct device *dev = rsnd_priv_to_dev(priv); |
| 1039 | struct rsnd_src *src; | 577 | struct rsnd_src *src; |
| 1040 | struct rsnd_mod_ops *ops; | ||
| 1041 | struct clk *clk; | 578 | struct clk *clk; |
| 1042 | char name[RSND_SRC_NAME_SIZE]; | 579 | char name[RSND_SRC_NAME_SIZE]; |
| 1043 | int i, nr, ret; | 580 | int i, nr, ret; |
| 1044 | 581 | ||
| 1045 | ops = NULL; | 582 | /* This driver doesn't support Gen1 at this point */ |
| 1046 | if (rsnd_is_gen1(priv)) { | 583 | if (rsnd_is_gen1(priv)) |
| 1047 | ops = &rsnd_src_gen1_ops; | 584 | return 0; |
| 1048 | dev_warn(dev, "Gen1 support will be removed soon\n"); | ||
| 1049 | } | ||
| 1050 | if (rsnd_is_gen2(priv)) | ||
| 1051 | ops = &rsnd_src_gen2_ops; | ||
| 1052 | if (!ops) { | ||
| 1053 | dev_err(dev, "unknown Generation\n"); | ||
| 1054 | return -EIO; | ||
| 1055 | } | ||
| 1056 | 585 | ||
| 1057 | rsnd_of_parse_src(pdev, of_data, priv); | 586 | node = rsnd_src_of_node(priv); |
| 587 | if (!node) | ||
| 588 | return 0; /* not used is not error */ | ||
| 1058 | 589 | ||
| 1059 | /* | 590 | nr = of_get_child_count(node); |
| 1060 | * init SRC | 591 | if (!nr) { |
| 1061 | */ | 592 | ret = -EINVAL; |
| 1062 | nr = info->src_info_nr; | 593 | goto rsnd_src_probe_done; |
| 1063 | if (!nr) | 594 | } |
| 1064 | return 0; | ||
| 1065 | 595 | ||
| 1066 | src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); | 596 | src = devm_kzalloc(dev, sizeof(*src) * nr, GFP_KERNEL); |
| 1067 | if (!src) | 597 | if (!src) { |
| 1068 | return -ENOMEM; | 598 | ret = -ENOMEM; |
| 599 | goto rsnd_src_probe_done; | ||
| 600 | } | ||
| 1069 | 601 | ||
| 1070 | priv->src_nr = nr; | 602 | priv->src_nr = nr; |
| 1071 | priv->src = src; | 603 | priv->src = src; |
| 1072 | 604 | ||
| 1073 | for_each_rsnd_src(src, priv, i) { | 605 | i = 0; |
| 606 | for_each_child_of_node(node, np) { | ||
| 607 | src = rsnd_src_get(priv, i); | ||
| 608 | |||
| 1074 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", | 609 | snprintf(name, RSND_SRC_NAME_SIZE, "%s.%d", |
| 1075 | SRC_NAME, i); | 610 | SRC_NAME, i); |
| 1076 | 611 | ||
| 1077 | clk = devm_clk_get(dev, name); | 612 | src->irq = irq_of_parse_and_map(np, 0); |
| 1078 | if (IS_ERR(clk)) | 613 | if (!src->irq) { |
| 1079 | return PTR_ERR(clk); | 614 | ret = -EINVAL; |
| 615 | goto rsnd_src_probe_done; | ||
| 616 | } | ||
| 1080 | 617 | ||
| 1081 | src->info = &info->src_info[i]; | 618 | clk = devm_clk_get(dev, name); |
| 619 | if (IS_ERR(clk)) { | ||
| 620 | ret = PTR_ERR(clk); | ||
| 621 | goto rsnd_src_probe_done; | ||
| 622 | } | ||
| 1082 | 623 | ||
| 1083 | ret = rsnd_mod_init(priv, rsnd_mod_get(src), ops, clk, RSND_MOD_SRC, i); | 624 | ret = rsnd_mod_init(priv, rsnd_mod_get(src), |
| 625 | &rsnd_src_ops, clk, RSND_MOD_SRC, i); | ||
| 1084 | if (ret) | 626 | if (ret) |
| 1085 | return ret; | 627 | goto rsnd_src_probe_done; |
| 628 | |||
| 629 | i++; | ||
| 1086 | } | 630 | } |
| 1087 | 631 | ||
| 1088 | return 0; | 632 | ret = 0; |
| 633 | |||
| 634 | rsnd_src_probe_done: | ||
| 635 | of_node_put(node); | ||
| 636 | |||
| 637 | return ret; | ||
| 1089 | } | 638 | } |
| 1090 | 639 | ||
| 1091 | void rsnd_src_remove(struct platform_device *pdev, | 640 | void rsnd_src_remove(struct rsnd_priv *priv) |
| 1092 | struct rsnd_priv *priv) | ||
| 1093 | { | 641 | { |
| 1094 | struct rsnd_src *src; | 642 | struct rsnd_src *src; |
| 1095 | int i; | 643 | int i; |
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c index 1427ec21bd7e..7db05fdfb656 100644 --- a/sound/soc/sh/rcar/ssi.c +++ b/sound/soc/sh/rcar/ssi.c | |||
| @@ -24,7 +24,9 @@ | |||
| 24 | #define OIEN (1 << 26) /* Overflow Interrupt Enable */ | 24 | #define OIEN (1 << 26) /* Overflow Interrupt Enable */ |
| 25 | #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ | 25 | #define IIEN (1 << 25) /* Idle Mode Interrupt Enable */ |
| 26 | #define DIEN (1 << 24) /* Data Interrupt Enable */ | 26 | #define DIEN (1 << 24) /* Data Interrupt Enable */ |
| 27 | 27 | #define CHNL_4 (1 << 22) /* Channels */ | |
| 28 | #define CHNL_6 (2 << 22) /* Channels */ | ||
| 29 | #define CHNL_8 (3 << 22) /* Channels */ | ||
| 28 | #define DWL_8 (0 << 19) /* Data Word Length */ | 30 | #define DWL_8 (0 << 19) /* Data Word Length */ |
| 29 | #define DWL_16 (1 << 19) /* Data Word Length */ | 31 | #define DWL_16 (1 << 19) /* Data Word Length */ |
| 30 | #define DWL_18 (2 << 19) /* Data Word Length */ | 32 | #define DWL_18 (2 << 19) /* Data Word Length */ |
| @@ -39,6 +41,7 @@ | |||
| 39 | #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ | 41 | #define SCKP (1 << 13) /* Serial Bit Clock Polarity */ |
| 40 | #define SWSP (1 << 12) /* Serial WS Polarity */ | 42 | #define SWSP (1 << 12) /* Serial WS Polarity */ |
| 41 | #define SDTA (1 << 10) /* Serial Data Alignment */ | 43 | #define SDTA (1 << 10) /* Serial Data Alignment */ |
| 44 | #define PDTA (1 << 9) /* Parallel Data Alignment */ | ||
| 42 | #define DEL (1 << 8) /* Serial Data Delay */ | 45 | #define DEL (1 << 8) /* Serial Data Delay */ |
| 43 | #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ | 46 | #define CKDV(v) (v << 4) /* Serial Clock Division Ratio */ |
| 44 | #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ | 47 | #define TRMD (1 << 1) /* Transmit/Receive Mode Select */ |
| @@ -56,35 +59,44 @@ | |||
| 56 | * SSIWSR | 59 | * SSIWSR |
| 57 | */ | 60 | */ |
| 58 | #define CONT (1 << 8) /* WS Continue Function */ | 61 | #define CONT (1 << 8) /* WS Continue Function */ |
| 62 | #define WS_MODE (1 << 0) /* WS Mode */ | ||
| 59 | 63 | ||
| 60 | #define SSI_NAME "ssi" | 64 | #define SSI_NAME "ssi" |
| 61 | 65 | ||
| 62 | struct rsnd_ssi { | 66 | struct rsnd_ssi { |
| 63 | struct rsnd_ssi_platform_info *info; /* rcar_snd.h */ | ||
| 64 | struct rsnd_ssi *parent; | 67 | struct rsnd_ssi *parent; |
| 65 | struct rsnd_mod mod; | 68 | struct rsnd_mod mod; |
| 69 | struct rsnd_mod *dma; | ||
| 66 | 70 | ||
| 71 | u32 flags; | ||
| 67 | u32 cr_own; | 72 | u32 cr_own; |
| 68 | u32 cr_clk; | 73 | u32 cr_clk; |
| 74 | u32 cr_mode; | ||
| 75 | u32 wsr; | ||
| 69 | int chan; | 76 | int chan; |
| 77 | int rate; | ||
| 70 | int err; | 78 | int err; |
| 79 | int irq; | ||
| 71 | unsigned int usrcnt; | 80 | unsigned int usrcnt; |
| 72 | }; | 81 | }; |
| 73 | 82 | ||
| 83 | /* flags */ | ||
| 84 | #define RSND_SSI_CLK_PIN_SHARE (1 << 0) | ||
| 85 | #define RSND_SSI_NO_BUSIF (1 << 1) /* SSI+DMA without BUSIF */ | ||
| 86 | |||
| 74 | #define for_each_rsnd_ssi(pos, priv, i) \ | 87 | #define for_each_rsnd_ssi(pos, priv, i) \ |
| 75 | for (i = 0; \ | 88 | for (i = 0; \ |
| 76 | (i < rsnd_ssi_nr(priv)) && \ | 89 | (i < rsnd_ssi_nr(priv)) && \ |
| 77 | ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ | 90 | ((pos) = ((struct rsnd_ssi *)(priv)->ssi + i)); \ |
| 78 | i++) | 91 | i++) |
| 79 | 92 | ||
| 93 | #define rsnd_ssi_get(priv, id) ((struct rsnd_ssi *)(priv->ssi) + id) | ||
| 94 | #define rsnd_ssi_to_dma(mod) ((ssi)->dma) | ||
| 80 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) | 95 | #define rsnd_ssi_nr(priv) ((priv)->ssi_nr) |
| 81 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) | 96 | #define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod) |
| 82 | #define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0) | 97 | #define rsnd_ssi_mode_flags(p) ((p)->flags) |
| 83 | #define rsnd_ssi_parent(ssi) ((ssi)->parent) | 98 | #define rsnd_ssi_is_parent(ssi, io) ((ssi) == rsnd_io_to_mod_ssip(io)) |
| 84 | #define rsnd_ssi_mode_flags(p) ((p)->info->flags) | 99 | #define rsnd_ssi_is_multi_slave(ssi, io) ((mod) != rsnd_io_to_mod_ssi(io)) |
| 85 | #define rsnd_ssi_dai_id(ssi) ((ssi)->info->dai_id) | ||
| 86 | #define rsnd_ssi_of_node(priv) \ | ||
| 87 | of_get_child_by_name(rsnd_priv_to_dev(priv)->of_node, "rcar_sound,ssi") | ||
| 88 | 100 | ||
| 89 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | 101 | int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) |
| 90 | { | 102 | { |
| @@ -103,6 +115,16 @@ int rsnd_ssi_use_busif(struct rsnd_dai_stream *io) | |||
| 103 | return use_busif; | 115 | return use_busif; |
| 104 | } | 116 | } |
| 105 | 117 | ||
| 118 | static void rsnd_ssi_status_clear(struct rsnd_mod *mod) | ||
| 119 | { | ||
| 120 | rsnd_mod_write(mod, SSISR, 0); | ||
| 121 | } | ||
| 122 | |||
| 123 | static u32 rsnd_ssi_status_get(struct rsnd_mod *mod) | ||
| 124 | { | ||
| 125 | return rsnd_mod_read(mod, SSISR); | ||
| 126 | } | ||
| 127 | |||
| 106 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, | 128 | static void rsnd_ssi_status_check(struct rsnd_mod *mod, |
| 107 | u32 bit) | 129 | u32 bit) |
| 108 | { | 130 | { |
| @@ -112,7 +134,7 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, | |||
| 112 | int i; | 134 | int i; |
| 113 | 135 | ||
| 114 | for (i = 0; i < 1024; i++) { | 136 | for (i = 0; i < 1024; i++) { |
| 115 | status = rsnd_mod_read(mod, SSISR); | 137 | status = rsnd_ssi_status_get(mod); |
| 116 | if (status & bit) | 138 | if (status & bit) |
| 117 | return; | 139 | return; |
| 118 | 140 | ||
| @@ -122,13 +144,79 @@ static void rsnd_ssi_status_check(struct rsnd_mod *mod, | |||
| 122 | dev_warn(dev, "status check failed\n"); | 144 | dev_warn(dev, "status check failed\n"); |
| 123 | } | 145 | } |
| 124 | 146 | ||
| 147 | static int rsnd_ssi_irq_enable(struct rsnd_mod *ssi_mod) | ||
| 148 | { | ||
| 149 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 150 | |||
| 151 | if (rsnd_is_gen1(priv)) | ||
| 152 | return 0; | ||
| 153 | |||
| 154 | /* enable SSI interrupt if Gen2 */ | ||
| 155 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, | ||
| 156 | rsnd_ssi_is_dma_mode(ssi_mod) ? | ||
| 157 | 0x0e000000 : 0x0f000000); | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | static int rsnd_ssi_irq_disable(struct rsnd_mod *ssi_mod) | ||
| 163 | { | ||
| 164 | struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod); | ||
| 165 | |||
| 166 | if (rsnd_is_gen1(priv)) | ||
| 167 | return 0; | ||
| 168 | |||
| 169 | /* disable SSI interrupt if Gen2 */ | ||
| 170 | rsnd_mod_write(ssi_mod, SSI_INT_ENABLE, 0x00000000); | ||
| 171 | |||
| 172 | return 0; | ||
| 173 | } | ||
| 174 | |||
| 175 | u32 rsnd_ssi_multi_slaves(struct rsnd_dai_stream *io) | ||
| 176 | { | ||
| 177 | struct rsnd_mod *mod; | ||
| 178 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 179 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
| 180 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 181 | enum rsnd_mod_type types[] = { | ||
| 182 | RSND_MOD_SSIM1, | ||
| 183 | RSND_MOD_SSIM2, | ||
| 184 | RSND_MOD_SSIM3, | ||
| 185 | }; | ||
| 186 | int i, mask; | ||
| 187 | |||
| 188 | switch (runtime->channels) { | ||
| 189 | case 2: /* Multi channel is not needed for Stereo */ | ||
| 190 | return 0; | ||
| 191 | case 6: | ||
| 192 | break; | ||
| 193 | default: | ||
| 194 | dev_err(dev, "unsupported channel\n"); | ||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | mask = 0; | ||
| 199 | for (i = 0; i < ARRAY_SIZE(types); i++) { | ||
| 200 | mod = rsnd_io_to_mod(io, types[i]); | ||
| 201 | if (!mod) | ||
| 202 | continue; | ||
| 203 | |||
| 204 | mask |= 1 << rsnd_mod_id(mod); | ||
| 205 | } | ||
| 206 | |||
| 207 | return mask; | ||
| 208 | } | ||
| 209 | |||
| 125 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | 210 | static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, |
| 126 | struct rsnd_dai_stream *io) | 211 | struct rsnd_dai_stream *io) |
| 127 | { | 212 | { |
| 128 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | 213 | struct rsnd_priv *priv = rsnd_io_to_priv(io); |
| 129 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | 214 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| 130 | struct device *dev = rsnd_priv_to_dev(priv); | 215 | struct device *dev = rsnd_priv_to_dev(priv); |
| 216 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 131 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 217 | struct rsnd_mod *mod = rsnd_mod_get(ssi); |
| 218 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | ||
| 219 | int slots = rsnd_get_slot_width(io); | ||
| 132 | int j, ret; | 220 | int j, ret; |
| 133 | int ssi_clk_mul_table[] = { | 221 | int ssi_clk_mul_table[] = { |
| 134 | 1, 2, 4, 8, 16, 6, 12, | 222 | 1, 2, 4, 8, 16, 6, 12, |
| @@ -136,6 +224,24 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
| 136 | unsigned int main_rate; | 224 | unsigned int main_rate; |
| 137 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); | 225 | unsigned int rate = rsnd_src_get_ssi_rate(priv, io, runtime); |
| 138 | 226 | ||
| 227 | if (!rsnd_rdai_is_clk_master(rdai)) | ||
| 228 | return 0; | ||
| 229 | |||
| 230 | if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) | ||
| 231 | return 0; | ||
| 232 | |||
| 233 | if (rsnd_ssi_is_multi_slave(mod, io)) | ||
| 234 | return 0; | ||
| 235 | |||
| 236 | if (ssi->usrcnt > 1) { | ||
| 237 | if (ssi->rate != rate) { | ||
| 238 | dev_err(dev, "SSI parent/child should use same rate\n"); | ||
| 239 | return -EINVAL; | ||
| 240 | } | ||
| 241 | |||
| 242 | return 0; | ||
| 243 | } | ||
| 244 | |||
| 139 | /* | 245 | /* |
| 140 | * Find best clock, and try to start ADG | 246 | * Find best clock, and try to start ADG |
| 141 | */ | 247 | */ |
| @@ -143,15 +249,18 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
| 143 | 249 | ||
| 144 | /* | 250 | /* |
| 145 | * this driver is assuming that | 251 | * this driver is assuming that |
| 146 | * system word is 64fs (= 2 x 32bit) | 252 | * system word is 32bit x slots |
| 147 | * see rsnd_ssi_init() | 253 | * see rsnd_ssi_init() |
| 148 | */ | 254 | */ |
| 149 | main_rate = rate * 32 * 2 * ssi_clk_mul_table[j]; | 255 | main_rate = rate * 32 * slots * ssi_clk_mul_table[j]; |
| 150 | 256 | ||
| 151 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); | 257 | ret = rsnd_adg_ssi_clk_try_start(mod, main_rate); |
| 152 | if (0 == ret) { | 258 | if (0 == ret) { |
| 153 | ssi->cr_clk = FORCE | SWL_32 | | 259 | ssi->cr_clk = FORCE | SWL_32 | |
| 154 | SCKD | SWSD | CKDV(j); | 260 | SCKD | SWSD | CKDV(j); |
| 261 | ssi->wsr = CONT; | ||
| 262 | |||
| 263 | ssi->rate = rate; | ||
| 155 | 264 | ||
| 156 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", | 265 | dev_dbg(dev, "%s[%d] outputs %u Hz\n", |
| 157 | rsnd_mod_name(mod), | 266 | rsnd_mod_name(mod), |
| @@ -165,113 +274,91 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi, | |||
| 165 | return -EIO; | 274 | return -EIO; |
| 166 | } | 275 | } |
| 167 | 276 | ||
| 168 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi) | 277 | static void rsnd_ssi_master_clk_stop(struct rsnd_ssi *ssi, |
| 278 | struct rsnd_dai_stream *io) | ||
| 169 | { | 279 | { |
| 280 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 170 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 281 | struct rsnd_mod *mod = rsnd_mod_get(ssi); |
| 282 | struct rsnd_mod *ssi_parent_mod = rsnd_io_to_mod_ssip(io); | ||
| 283 | |||
| 284 | if (!rsnd_rdai_is_clk_master(rdai)) | ||
| 285 | return; | ||
| 286 | |||
| 287 | if (ssi_parent_mod && !rsnd_ssi_is_parent(mod, io)) | ||
| 288 | return; | ||
| 289 | |||
| 290 | if (ssi->usrcnt > 1) | ||
| 291 | return; | ||
| 292 | |||
| 293 | ssi->cr_clk = 0; | ||
| 294 | ssi->rate = 0; | ||
| 171 | 295 | ||
| 172 | ssi->cr_clk = 0; | ||
| 173 | rsnd_adg_ssi_clk_stop(mod); | 296 | rsnd_adg_ssi_clk_stop(mod); |
| 174 | } | 297 | } |
| 175 | 298 | ||
| 176 | static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi, | 299 | static int rsnd_ssi_config_init(struct rsnd_ssi *ssi, |
| 177 | struct rsnd_dai_stream *io) | 300 | struct rsnd_dai_stream *io) |
| 178 | { | 301 | { |
| 179 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
| 180 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 302 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
| 181 | struct device *dev = rsnd_priv_to_dev(priv); | 303 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); |
| 182 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 304 | u32 cr_own; |
| 183 | u32 cr_mode; | 305 | u32 cr_mode; |
| 184 | u32 cr; | 306 | u32 wsr; |
| 307 | int is_tdm; | ||
| 185 | 308 | ||
| 186 | if (0 == ssi->usrcnt) { | 309 | is_tdm = (rsnd_get_slot_width(io) >= 6) ? 1 : 0; |
| 187 | rsnd_mod_power_on(mod); | ||
| 188 | 310 | ||
| 189 | if (rsnd_rdai_is_clk_master(rdai)) { | 311 | /* |
| 190 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); | 312 | * always use 32bit system word. |
| 313 | * see also rsnd_ssi_master_clk_enable() | ||
| 314 | */ | ||
| 315 | cr_own = FORCE | SWL_32 | PDTA; | ||
| 191 | 316 | ||
| 192 | if (ssi_parent) | 317 | if (rdai->bit_clk_inv) |
| 193 | rsnd_ssi_hw_start(ssi_parent, io); | 318 | cr_own |= SCKP; |
| 194 | else | 319 | if (rdai->frm_clk_inv ^ is_tdm) |
| 195 | rsnd_ssi_master_clk_start(ssi, io); | 320 | cr_own |= SWSP; |
| 196 | } | 321 | if (rdai->data_alignment) |
| 322 | cr_own |= SDTA; | ||
| 323 | if (rdai->sys_delay) | ||
| 324 | cr_own |= DEL; | ||
| 325 | if (rsnd_io_is_play(io)) | ||
| 326 | cr_own |= TRMD; | ||
| 327 | |||
| 328 | switch (runtime->sample_bits) { | ||
| 329 | case 16: | ||
| 330 | cr_own |= DWL_16; | ||
| 331 | break; | ||
| 332 | case 32: | ||
| 333 | cr_own |= DWL_24; | ||
| 334 | break; | ||
| 335 | default: | ||
| 336 | return -EINVAL; | ||
| 197 | } | 337 | } |
| 198 | 338 | ||
| 199 | if (rsnd_ssi_is_dma_mode(mod)) { | 339 | if (rsnd_ssi_is_dma_mode(rsnd_mod_get(ssi))) { |
| 200 | cr_mode = UIEN | OIEN | /* over/under run */ | 340 | cr_mode = UIEN | OIEN | /* over/under run */ |
| 201 | DMEN; /* DMA : enable DMA */ | 341 | DMEN; /* DMA : enable DMA */ |
| 202 | } else { | 342 | } else { |
| 203 | cr_mode = DIEN; /* PIO : enable Data interrupt */ | 343 | cr_mode = DIEN; /* PIO : enable Data interrupt */ |
| 204 | } | 344 | } |
| 205 | 345 | ||
| 206 | cr = ssi->cr_own | | 346 | /* |
| 207 | ssi->cr_clk | | 347 | * TDM Extend Mode |
| 208 | cr_mode | | 348 | * see |
| 209 | EN; | 349 | * rsnd_ssiu_init_gen2() |
| 210 | 350 | */ | |
| 211 | rsnd_mod_write(mod, SSICR, cr); | 351 | wsr = ssi->wsr; |
| 212 | 352 | if (is_tdm) { | |
| 213 | /* enable WS continue */ | 353 | wsr |= WS_MODE; |
| 214 | if (rsnd_rdai_is_clk_master(rdai)) | 354 | cr_own |= CHNL_8; |
| 215 | rsnd_mod_write(mod, SSIWSR, CONT); | ||
| 216 | |||
| 217 | /* clear error status */ | ||
| 218 | rsnd_mod_write(mod, SSISR, 0); | ||
| 219 | |||
| 220 | ssi->usrcnt++; | ||
| 221 | |||
| 222 | dev_dbg(dev, "%s[%d] hw started\n", | ||
| 223 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 224 | } | ||
| 225 | |||
| 226 | static void rsnd_ssi_hw_stop(struct rsnd_dai_stream *io, struct rsnd_ssi *ssi) | ||
| 227 | { | ||
| 228 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | ||
| 229 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | ||
| 230 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 231 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 232 | u32 cr; | ||
| 233 | |||
| 234 | if (0 == ssi->usrcnt) { | ||
| 235 | dev_err(dev, "%s called without starting\n", __func__); | ||
| 236 | return; | ||
| 237 | } | 355 | } |
| 238 | 356 | ||
| 239 | ssi->usrcnt--; | 357 | ssi->cr_own = cr_own; |
| 240 | 358 | ssi->cr_mode = cr_mode; | |
| 241 | if (0 == ssi->usrcnt) { | 359 | ssi->wsr = wsr; |
| 242 | /* | ||
| 243 | * disable all IRQ, | ||
| 244 | * and, wait all data was sent | ||
| 245 | */ | ||
| 246 | cr = ssi->cr_own | | ||
| 247 | ssi->cr_clk; | ||
| 248 | |||
| 249 | rsnd_mod_write(mod, SSICR, cr | EN); | ||
| 250 | rsnd_ssi_status_check(mod, DIRQ); | ||
| 251 | |||
| 252 | /* | ||
| 253 | * disable SSI, | ||
| 254 | * and, wait idle state | ||
| 255 | */ | ||
| 256 | rsnd_mod_write(mod, SSICR, cr); /* disabled all */ | ||
| 257 | rsnd_ssi_status_check(mod, IIRQ); | ||
| 258 | |||
| 259 | if (rsnd_rdai_is_clk_master(rdai)) { | ||
| 260 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); | ||
| 261 | 360 | ||
| 262 | if (ssi_parent) | 361 | return 0; |
| 263 | rsnd_ssi_hw_stop(io, ssi_parent); | ||
| 264 | else | ||
| 265 | rsnd_ssi_master_clk_stop(ssi); | ||
| 266 | } | ||
| 267 | |||
| 268 | rsnd_mod_power_off(mod); | ||
| 269 | |||
| 270 | ssi->chan = 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | dev_dbg(dev, "%s[%d] hw stopped\n", | ||
| 274 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 275 | } | 362 | } |
| 276 | 363 | ||
| 277 | /* | 364 | /* |
| @@ -282,49 +369,30 @@ static int rsnd_ssi_init(struct rsnd_mod *mod, | |||
| 282 | struct rsnd_priv *priv) | 369 | struct rsnd_priv *priv) |
| 283 | { | 370 | { |
| 284 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 371 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 285 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | 372 | int ret; |
| 286 | struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); | ||
| 287 | u32 cr; | ||
| 288 | 373 | ||
| 289 | cr = FORCE; | 374 | ssi->usrcnt++; |
| 290 | 375 | ||
| 291 | /* | 376 | rsnd_mod_power_on(mod); |
| 292 | * always use 32bit system word for easy clock calculation. | ||
| 293 | * see also rsnd_ssi_master_clk_enable() | ||
| 294 | */ | ||
| 295 | cr |= SWL_32; | ||
| 296 | 377 | ||
| 297 | /* | 378 | ret = rsnd_ssi_master_clk_start(ssi, io); |
| 298 | * init clock settings for SSICR | 379 | if (ret < 0) |
| 299 | */ | 380 | return ret; |
| 300 | switch (runtime->sample_bits) { | ||
| 301 | case 16: | ||
| 302 | cr |= DWL_16; | ||
| 303 | break; | ||
| 304 | case 32: | ||
| 305 | cr |= DWL_24; | ||
| 306 | break; | ||
| 307 | default: | ||
| 308 | return -EIO; | ||
| 309 | } | ||
| 310 | 381 | ||
| 311 | if (rdai->bit_clk_inv) | 382 | if (rsnd_ssi_is_parent(mod, io)) |
| 312 | cr |= SCKP; | 383 | return 0; |
| 313 | if (rdai->frm_clk_inv) | 384 | |
| 314 | cr |= SWSP; | 385 | ret = rsnd_ssi_config_init(ssi, io); |
| 315 | if (rdai->data_alignment) | 386 | if (ret < 0) |
| 316 | cr |= SDTA; | 387 | return ret; |
| 317 | if (rdai->sys_delay) | ||
| 318 | cr |= DEL; | ||
| 319 | if (rsnd_io_is_play(io)) | ||
| 320 | cr |= TRMD; | ||
| 321 | 388 | ||
| 322 | /* | ||
| 323 | * set ssi parameter | ||
| 324 | */ | ||
| 325 | ssi->cr_own = cr; | ||
| 326 | ssi->err = -1; /* ignore 1st error */ | 389 | ssi->err = -1; /* ignore 1st error */ |
| 327 | 390 | ||
| 391 | /* clear error status */ | ||
| 392 | rsnd_ssi_status_clear(mod); | ||
| 393 | |||
| 394 | rsnd_ssi_irq_enable(mod); | ||
| 395 | |||
| 328 | return 0; | 396 | return 0; |
| 329 | } | 397 | } |
| 330 | 398 | ||
| @@ -335,6 +403,9 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
| 335 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 403 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 336 | struct device *dev = rsnd_priv_to_dev(priv); | 404 | struct device *dev = rsnd_priv_to_dev(priv); |
| 337 | 405 | ||
| 406 | if (rsnd_ssi_is_parent(mod, io)) | ||
| 407 | goto rsnd_ssi_quit_end; | ||
| 408 | |||
| 338 | if (ssi->err > 0) | 409 | if (ssi->err > 0) |
| 339 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", | 410 | dev_warn(dev, "%s[%d] under/over flow err = %d\n", |
| 340 | rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); | 411 | rsnd_mod_name(mod), rsnd_mod_id(mod), ssi->err); |
| @@ -342,6 +413,19 @@ static int rsnd_ssi_quit(struct rsnd_mod *mod, | |||
| 342 | ssi->cr_own = 0; | 413 | ssi->cr_own = 0; |
| 343 | ssi->err = 0; | 414 | ssi->err = 0; |
| 344 | 415 | ||
| 416 | rsnd_ssi_irq_disable(mod); | ||
| 417 | |||
| 418 | rsnd_ssi_quit_end: | ||
| 419 | rsnd_ssi_master_clk_stop(ssi, io); | ||
| 420 | |||
| 421 | rsnd_mod_power_off(mod); | ||
| 422 | |||
| 423 | ssi->usrcnt--; | ||
| 424 | |||
| 425 | if (ssi->usrcnt < 0) | ||
| 426 | dev_err(dev, "%s[%d] usrcnt error\n", | ||
| 427 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 428 | |||
| 345 | return 0; | 429 | return 0; |
| 346 | } | 430 | } |
| 347 | 431 | ||
| @@ -351,14 +435,13 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, | |||
| 351 | struct snd_pcm_hw_params *params) | 435 | struct snd_pcm_hw_params *params) |
| 352 | { | 436 | { |
| 353 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 437 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 354 | struct rsnd_ssi *ssi_parent = rsnd_ssi_parent(ssi); | ||
| 355 | int chan = params_channels(params); | 438 | int chan = params_channels(params); |
| 356 | 439 | ||
| 357 | /* | 440 | /* |
| 358 | * Already working. | 441 | * Already working. |
| 359 | * It will happen if SSI has parent/child connection. | 442 | * It will happen if SSI has parent/child connection. |
| 360 | */ | 443 | */ |
| 361 | if (ssi->usrcnt) { | 444 | if (ssi->usrcnt > 1) { |
| 362 | /* | 445 | /* |
| 363 | * it is error if child <-> parent SSI uses | 446 | * it is error if child <-> parent SSI uses |
| 364 | * different channels. | 447 | * different channels. |
| @@ -367,39 +450,83 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, | |||
| 367 | return -EIO; | 450 | return -EIO; |
| 368 | } | 451 | } |
| 369 | 452 | ||
| 370 | /* It will be removed on rsnd_ssi_hw_stop */ | ||
| 371 | ssi->chan = chan; | 453 | ssi->chan = chan; |
| 372 | if (ssi_parent) | ||
| 373 | return rsnd_ssi_hw_params(rsnd_mod_get(ssi_parent), io, | ||
| 374 | substream, params); | ||
| 375 | 454 | ||
| 376 | return 0; | 455 | return 0; |
| 377 | } | 456 | } |
| 378 | 457 | ||
| 379 | static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status) | 458 | static u32 rsnd_ssi_record_error(struct rsnd_ssi *ssi) |
| 380 | { | 459 | { |
| 381 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | 460 | struct rsnd_mod *mod = rsnd_mod_get(ssi); |
| 461 | u32 status = rsnd_ssi_status_get(mod); | ||
| 382 | 462 | ||
| 383 | /* under/over flow error */ | 463 | /* under/over flow error */ |
| 384 | if (status & (UIRQ | OIRQ)) { | 464 | if (status & (UIRQ | OIRQ)) |
| 385 | ssi->err++; | 465 | ssi->err++; |
| 386 | 466 | ||
| 387 | /* clear error status */ | 467 | return status; |
| 388 | rsnd_mod_write(mod, SSISR, 0); | 468 | } |
| 389 | } | 469 | |
| 470 | static int __rsnd_ssi_start(struct rsnd_mod *mod, | ||
| 471 | struct rsnd_dai_stream *io, | ||
| 472 | struct rsnd_priv *priv) | ||
| 473 | { | ||
| 474 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | ||
| 475 | u32 cr; | ||
| 476 | |||
| 477 | cr = ssi->cr_own | | ||
| 478 | ssi->cr_clk | | ||
| 479 | ssi->cr_mode; | ||
| 480 | |||
| 481 | /* | ||
| 482 | * EN will be set via SSIU :: SSI_CONTROL | ||
| 483 | * if Multi channel mode | ||
| 484 | */ | ||
| 485 | if (!rsnd_ssi_multi_slaves(io)) | ||
| 486 | cr |= EN; | ||
| 487 | |||
| 488 | rsnd_mod_write(mod, SSICR, cr); | ||
| 489 | rsnd_mod_write(mod, SSIWSR, ssi->wsr); | ||
| 490 | |||
| 491 | return 0; | ||
| 390 | } | 492 | } |
| 391 | 493 | ||
| 392 | static int rsnd_ssi_start(struct rsnd_mod *mod, | 494 | static int rsnd_ssi_start(struct rsnd_mod *mod, |
| 393 | struct rsnd_dai_stream *io, | 495 | struct rsnd_dai_stream *io, |
| 394 | struct rsnd_priv *priv) | 496 | struct rsnd_priv *priv) |
| 395 | { | 497 | { |
| 498 | /* | ||
| 499 | * no limit to start | ||
| 500 | * see also | ||
| 501 | * rsnd_ssi_stop | ||
| 502 | * rsnd_ssi_interrupt | ||
| 503 | */ | ||
| 504 | return __rsnd_ssi_start(mod, io, priv); | ||
| 505 | } | ||
| 506 | |||
| 507 | static int __rsnd_ssi_stop(struct rsnd_mod *mod, | ||
| 508 | struct rsnd_dai_stream *io, | ||
| 509 | struct rsnd_priv *priv) | ||
| 510 | { | ||
| 396 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 511 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 512 | u32 cr; | ||
| 397 | 513 | ||
| 398 | rsnd_src_ssiu_start(mod, io, rsnd_ssi_use_busif(io)); | 514 | /* |
| 515 | * disable all IRQ, | ||
| 516 | * and, wait all data was sent | ||
| 517 | */ | ||
| 518 | cr = ssi->cr_own | | ||
| 519 | ssi->cr_clk; | ||
| 399 | 520 | ||
| 400 | rsnd_ssi_hw_start(ssi, io); | 521 | rsnd_mod_write(mod, SSICR, cr | EN); |
| 522 | rsnd_ssi_status_check(mod, DIRQ); | ||
| 401 | 523 | ||
| 402 | rsnd_src_ssi_irq_enable(mod); | 524 | /* |
| 525 | * disable SSI, | ||
| 526 | * and, wait idle state | ||
| 527 | */ | ||
| 528 | rsnd_mod_write(mod, SSICR, cr); /* disabled all */ | ||
| 529 | rsnd_ssi_status_check(mod, IIRQ); | ||
| 403 | 530 | ||
| 404 | return 0; | 531 | return 0; |
| 405 | } | 532 | } |
| @@ -410,15 +537,16 @@ static int rsnd_ssi_stop(struct rsnd_mod *mod, | |||
| 410 | { | 537 | { |
| 411 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 538 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 412 | 539 | ||
| 413 | rsnd_src_ssi_irq_disable(mod); | 540 | /* |
| 414 | 541 | * don't stop if not last user | |
| 415 | rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR)); | 542 | * see also |
| 416 | 543 | * rsnd_ssi_start | |
| 417 | rsnd_ssi_hw_stop(io, ssi); | 544 | * rsnd_ssi_interrupt |
| 418 | 545 | */ | |
| 419 | rsnd_src_ssiu_stop(mod, io); | 546 | if (ssi->usrcnt > 1) |
| 547 | return 0; | ||
| 420 | 548 | ||
| 421 | return 0; | 549 | return __rsnd_ssi_stop(mod, io, priv); |
| 422 | } | 550 | } |
| 423 | 551 | ||
| 424 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | 552 | static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, |
| @@ -426,6 +554,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
| 426 | { | 554 | { |
| 427 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 555 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 428 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); | 556 | struct rsnd_priv *priv = rsnd_mod_to_priv(mod); |
| 557 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 429 | int is_dma = rsnd_ssi_is_dma_mode(mod); | 558 | int is_dma = rsnd_ssi_is_dma_mode(mod); |
| 430 | u32 status; | 559 | u32 status; |
| 431 | bool elapsed = false; | 560 | bool elapsed = false; |
| @@ -436,7 +565,7 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
| 436 | if (!rsnd_io_is_working(io)) | 565 | if (!rsnd_io_is_working(io)) |
| 437 | goto rsnd_ssi_interrupt_out; | 566 | goto rsnd_ssi_interrupt_out; |
| 438 | 567 | ||
| 439 | status = rsnd_mod_read(mod, SSISR); | 568 | status = rsnd_ssi_record_error(ssi); |
| 440 | 569 | ||
| 441 | /* PIO only */ | 570 | /* PIO only */ |
| 442 | if (!is_dma && (status & DIRQ)) { | 571 | if (!is_dma && (status & DIRQ)) { |
| @@ -459,23 +588,24 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod, | |||
| 459 | 588 | ||
| 460 | /* DMA only */ | 589 | /* DMA only */ |
| 461 | if (is_dma && (status & (UIRQ | OIRQ))) { | 590 | if (is_dma && (status & (UIRQ | OIRQ))) { |
| 462 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 463 | |||
| 464 | /* | 591 | /* |
| 465 | * restart SSI | 592 | * restart SSI |
| 466 | */ | 593 | */ |
| 467 | dev_dbg(dev, "%s[%d] restart\n", | 594 | dev_dbg(dev, "%s[%d] restart\n", |
| 468 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | 595 | rsnd_mod_name(mod), rsnd_mod_id(mod)); |
| 469 | 596 | ||
| 470 | rsnd_ssi_stop(mod, io, priv); | 597 | __rsnd_ssi_stop(mod, io, priv); |
| 471 | if (ssi->err < 1024) | 598 | __rsnd_ssi_start(mod, io, priv); |
| 472 | rsnd_ssi_start(mod, io, priv); | ||
| 473 | else | ||
| 474 | dev_warn(dev, "no more SSI restart\n"); | ||
| 475 | } | 599 | } |
| 476 | 600 | ||
| 477 | rsnd_ssi_record_error(ssi, status); | 601 | if (ssi->err > 1024) { |
| 602 | rsnd_ssi_irq_disable(mod); | ||
| 478 | 603 | ||
| 604 | dev_warn(dev, "no more %s[%d] restart\n", | ||
| 605 | rsnd_mod_name(mod), rsnd_mod_id(mod)); | ||
| 606 | } | ||
| 607 | |||
| 608 | rsnd_ssi_status_clear(mod); | ||
| 479 | rsnd_ssi_interrupt_out: | 609 | rsnd_ssi_interrupt_out: |
| 480 | spin_unlock(&priv->lock); | 610 | spin_unlock(&priv->lock); |
| 481 | 611 | ||
| @@ -495,15 +625,49 @@ static irqreturn_t rsnd_ssi_interrupt(int irq, void *data) | |||
| 495 | /* | 625 | /* |
| 496 | * SSI PIO | 626 | * SSI PIO |
| 497 | */ | 627 | */ |
| 498 | static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | 628 | static void rsnd_ssi_parent_attach(struct rsnd_mod *mod, |
| 499 | struct rsnd_dai_stream *io, | 629 | struct rsnd_dai_stream *io, |
| 500 | struct rsnd_priv *priv) | 630 | struct rsnd_priv *priv) |
| 631 | { | ||
| 632 | if (!__rsnd_ssi_is_pin_sharing(mod)) | ||
| 633 | return; | ||
| 634 | |||
| 635 | switch (rsnd_mod_id(mod)) { | ||
| 636 | case 1: | ||
| 637 | case 2: | ||
| 638 | rsnd_dai_connect(rsnd_ssi_mod_get(priv, 0), io, RSND_MOD_SSIP); | ||
| 639 | break; | ||
| 640 | case 4: | ||
| 641 | rsnd_dai_connect(rsnd_ssi_mod_get(priv, 3), io, RSND_MOD_SSIP); | ||
| 642 | break; | ||
| 643 | case 8: | ||
| 644 | rsnd_dai_connect(rsnd_ssi_mod_get(priv, 7), io, RSND_MOD_SSIP); | ||
| 645 | break; | ||
| 646 | } | ||
| 647 | } | ||
| 648 | |||
| 649 | static int rsnd_ssi_common_probe(struct rsnd_mod *mod, | ||
| 650 | struct rsnd_dai_stream *io, | ||
| 651 | struct rsnd_priv *priv) | ||
| 501 | { | 652 | { |
| 502 | struct device *dev = rsnd_priv_to_dev(priv); | 653 | struct device *dev = rsnd_priv_to_dev(priv); |
| 503 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 654 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 504 | int ret; | 655 | int ret; |
| 505 | 656 | ||
| 506 | ret = devm_request_irq(dev, ssi->info->irq, | 657 | /* |
| 658 | * SSIP/SSIU/IRQ are not needed on | ||
| 659 | * SSI Multi slaves | ||
| 660 | */ | ||
| 661 | if (rsnd_ssi_is_multi_slave(mod, io)) | ||
| 662 | return 0; | ||
| 663 | |||
| 664 | rsnd_ssi_parent_attach(mod, io, priv); | ||
| 665 | |||
| 666 | ret = rsnd_ssiu_attach(io, mod); | ||
| 667 | if (ret < 0) | ||
| 668 | return ret; | ||
| 669 | |||
| 670 | ret = devm_request_irq(dev, ssi->irq, | ||
| 507 | rsnd_ssi_interrupt, | 671 | rsnd_ssi_interrupt, |
| 508 | IRQF_SHARED, | 672 | IRQF_SHARED, |
| 509 | dev_name(dev), mod); | 673 | dev_name(dev), mod); |
| @@ -513,7 +677,7 @@ static int rsnd_ssi_pio_probe(struct rsnd_mod *mod, | |||
| 513 | 677 | ||
| 514 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { | 678 | static struct rsnd_mod_ops rsnd_ssi_pio_ops = { |
| 515 | .name = SSI_NAME, | 679 | .name = SSI_NAME, |
| 516 | .probe = rsnd_ssi_pio_probe, | 680 | .probe = rsnd_ssi_common_probe, |
| 517 | .init = rsnd_ssi_init, | 681 | .init = rsnd_ssi_init, |
| 518 | .quit = rsnd_ssi_quit, | 682 | .quit = rsnd_ssi_quit, |
| 519 | .start = rsnd_ssi_start, | 683 | .start = rsnd_ssi_start, |
| @@ -526,20 +690,23 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod, | |||
| 526 | struct rsnd_priv *priv) | 690 | struct rsnd_priv *priv) |
| 527 | { | 691 | { |
| 528 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 692 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 529 | struct device *dev = rsnd_priv_to_dev(priv); | 693 | int dma_id = 0; /* not needed */ |
| 530 | int dma_id = ssi->info->dma_id; | ||
| 531 | int ret; | 694 | int ret; |
| 532 | 695 | ||
| 533 | ret = devm_request_irq(dev, ssi->info->irq, | 696 | /* |
| 534 | rsnd_ssi_interrupt, | 697 | * SSIP/SSIU/IRQ/DMA are not needed on |
| 535 | IRQF_SHARED, | 698 | * SSI Multi slaves |
| 536 | dev_name(dev), mod); | 699 | */ |
| 700 | if (rsnd_ssi_is_multi_slave(mod, io)) | ||
| 701 | return 0; | ||
| 702 | |||
| 703 | ret = rsnd_ssi_common_probe(mod, io, priv); | ||
| 537 | if (ret) | 704 | if (ret) |
| 538 | return ret; | 705 | return ret; |
| 539 | 706 | ||
| 540 | ret = rsnd_dma_init( | 707 | ssi->dma = rsnd_dma_attach(io, mod, dma_id); |
| 541 | io, rsnd_mod_to_dma(mod), | 708 | if (IS_ERR(ssi->dma)) |
| 542 | dma_id); | 709 | return PTR_ERR(ssi->dma); |
| 543 | 710 | ||
| 544 | return ret; | 711 | return ret; |
| 545 | } | 712 | } |
| @@ -550,9 +717,7 @@ static int rsnd_ssi_dma_remove(struct rsnd_mod *mod, | |||
| 550 | { | 717 | { |
| 551 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 718 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 552 | struct device *dev = rsnd_priv_to_dev(priv); | 719 | struct device *dev = rsnd_priv_to_dev(priv); |
| 553 | int irq = ssi->info->irq; | 720 | int irq = ssi->irq; |
| 554 | |||
| 555 | rsnd_dma_quit(io, rsnd_mod_to_dma(mod)); | ||
| 556 | 721 | ||
| 557 | /* PIO will request IRQ again */ | 722 | /* PIO will request IRQ again */ |
| 558 | devm_free_irq(dev, irq, mod); | 723 | devm_free_irq(dev, irq, mod); |
| @@ -581,32 +746,6 @@ static int rsnd_ssi_fallback(struct rsnd_mod *mod, | |||
| 581 | return 0; | 746 | return 0; |
| 582 | } | 747 | } |
| 583 | 748 | ||
| 584 | static int rsnd_ssi_dma_start(struct rsnd_mod *mod, | ||
| 585 | struct rsnd_dai_stream *io, | ||
| 586 | struct rsnd_priv *priv) | ||
| 587 | { | ||
| 588 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 589 | |||
| 590 | rsnd_dma_start(io, dma); | ||
| 591 | |||
| 592 | rsnd_ssi_start(mod, io, priv); | ||
| 593 | |||
| 594 | return 0; | ||
| 595 | } | ||
| 596 | |||
| 597 | static int rsnd_ssi_dma_stop(struct rsnd_mod *mod, | ||
| 598 | struct rsnd_dai_stream *io, | ||
| 599 | struct rsnd_priv *priv) | ||
| 600 | { | ||
| 601 | struct rsnd_dma *dma = rsnd_mod_to_dma(mod); | ||
| 602 | |||
| 603 | rsnd_ssi_stop(mod, io, priv); | ||
| 604 | |||
| 605 | rsnd_dma_stop(io, dma); | ||
| 606 | |||
| 607 | return 0; | ||
| 608 | } | ||
| 609 | |||
| 610 | static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, | 749 | static struct dma_chan *rsnd_ssi_dma_req(struct rsnd_dai_stream *io, |
| 611 | struct rsnd_mod *mod) | 750 | struct rsnd_mod *mod) |
| 612 | { | 751 | { |
| @@ -630,8 +769,8 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = { | |||
| 630 | .remove = rsnd_ssi_dma_remove, | 769 | .remove = rsnd_ssi_dma_remove, |
| 631 | .init = rsnd_ssi_init, | 770 | .init = rsnd_ssi_init, |
| 632 | .quit = rsnd_ssi_quit, | 771 | .quit = rsnd_ssi_quit, |
| 633 | .start = rsnd_ssi_dma_start, | 772 | .start = rsnd_ssi_start, |
| 634 | .stop = rsnd_ssi_dma_stop, | 773 | .stop = rsnd_ssi_stop, |
| 635 | .fallback = rsnd_ssi_fallback, | 774 | .fallback = rsnd_ssi_fallback, |
| 636 | .hw_params = rsnd_ssi_hw_params, | 775 | .hw_params = rsnd_ssi_hw_params, |
| 637 | }; | 776 | }; |
| @@ -652,110 +791,76 @@ static struct rsnd_mod_ops rsnd_ssi_non_ops = { | |||
| 652 | /* | 791 | /* |
| 653 | * ssi mod function | 792 | * ssi mod function |
| 654 | */ | 793 | */ |
| 655 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) | 794 | static void rsnd_ssi_connect(struct rsnd_mod *mod, |
| 795 | struct rsnd_dai_stream *io) | ||
| 656 | { | 796 | { |
| 657 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) | 797 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); |
| 658 | id = 0; | 798 | enum rsnd_mod_type types[] = { |
| 659 | 799 | RSND_MOD_SSI, | |
| 660 | return rsnd_mod_get((struct rsnd_ssi *)(priv->ssi) + id); | 800 | RSND_MOD_SSIM1, |
| 661 | } | 801 | RSND_MOD_SSIM2, |
| 662 | 802 | RSND_MOD_SSIM3, | |
| 663 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) | 803 | }; |
| 664 | { | 804 | enum rsnd_mod_type type; |
| 665 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); | 805 | int i; |
| 666 | |||
| 667 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); | ||
| 668 | } | ||
| 669 | |||
| 670 | static void rsnd_ssi_parent_setup(struct rsnd_priv *priv, struct rsnd_ssi *ssi) | ||
| 671 | { | ||
| 672 | struct rsnd_mod *mod = rsnd_mod_get(ssi); | ||
| 673 | |||
| 674 | if (!__rsnd_ssi_is_pin_sharing(mod)) | ||
| 675 | return; | ||
| 676 | 806 | ||
| 677 | switch (rsnd_mod_id(mod)) { | 807 | /* try SSI -> SSIM1 -> SSIM2 -> SSIM3 */ |
| 678 | case 1: | 808 | for (i = 0; i < ARRAY_SIZE(types); i++) { |
| 679 | case 2: | 809 | type = types[i]; |
| 680 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 0)); | 810 | if (!rsnd_io_to_mod(io, type)) { |
| 681 | break; | 811 | rsnd_dai_connect(mod, io, type); |
| 682 | case 4: | 812 | rsnd_set_slot(rdai, 2 * (i + 1), (i + 1)); |
| 683 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 3)); | 813 | return; |
| 684 | break; | 814 | } |
| 685 | case 8: | ||
| 686 | ssi->parent = rsnd_mod_to_ssi(rsnd_ssi_mod_get(priv, 7)); | ||
| 687 | break; | ||
| 688 | } | 815 | } |
| 689 | } | 816 | } |
| 690 | 817 | ||
| 691 | 818 | void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, | |
| 692 | static void rsnd_of_parse_ssi(struct platform_device *pdev, | 819 | struct device_node *playback, |
| 693 | const struct rsnd_of_data *of_data, | 820 | struct device_node *capture) |
| 694 | struct rsnd_priv *priv) | ||
| 695 | { | 821 | { |
| 822 | struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai); | ||
| 696 | struct device_node *node; | 823 | struct device_node *node; |
| 697 | struct device_node *np; | 824 | struct device_node *np; |
| 698 | struct rsnd_ssi_platform_info *ssi_info; | 825 | struct rsnd_mod *mod; |
| 699 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | 826 | int i; |
| 700 | struct device *dev = &pdev->dev; | ||
| 701 | int nr, i; | ||
| 702 | 827 | ||
| 703 | node = rsnd_ssi_of_node(priv); | 828 | node = rsnd_ssi_of_node(priv); |
| 704 | if (!node) | 829 | if (!node) |
| 705 | return; | 830 | return; |
| 706 | 831 | ||
| 707 | nr = of_get_child_count(node); | 832 | i = 0; |
| 708 | if (!nr) | ||
| 709 | goto rsnd_of_parse_ssi_end; | ||
| 710 | |||
| 711 | ssi_info = devm_kzalloc(dev, | ||
| 712 | sizeof(struct rsnd_ssi_platform_info) * nr, | ||
| 713 | GFP_KERNEL); | ||
| 714 | if (!ssi_info) { | ||
| 715 | dev_err(dev, "ssi info allocation error\n"); | ||
| 716 | goto rsnd_of_parse_ssi_end; | ||
| 717 | } | ||
| 718 | |||
| 719 | info->ssi_info = ssi_info; | ||
| 720 | info->ssi_info_nr = nr; | ||
| 721 | |||
| 722 | i = -1; | ||
| 723 | for_each_child_of_node(node, np) { | 833 | for_each_child_of_node(node, np) { |
| 834 | mod = rsnd_ssi_mod_get(priv, i); | ||
| 835 | if (np == playback) | ||
| 836 | rsnd_ssi_connect(mod, &rdai->playback); | ||
| 837 | if (np == capture) | ||
| 838 | rsnd_ssi_connect(mod, &rdai->capture); | ||
| 724 | i++; | 839 | i++; |
| 840 | } | ||
| 725 | 841 | ||
| 726 | ssi_info = info->ssi_info + i; | 842 | of_node_put(node); |
| 727 | 843 | } | |
| 728 | /* | ||
| 729 | * pin settings | ||
| 730 | */ | ||
| 731 | if (of_get_property(np, "shared-pin", NULL)) | ||
| 732 | ssi_info->flags |= RSND_SSI_CLK_PIN_SHARE; | ||
| 733 | 844 | ||
| 734 | /* | 845 | struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id) |
| 735 | * irq | 846 | { |
| 736 | */ | 847 | if (WARN_ON(id < 0 || id >= rsnd_ssi_nr(priv))) |
| 737 | ssi_info->irq = irq_of_parse_and_map(np, 0); | 848 | id = 0; |
| 738 | 849 | ||
| 739 | /* | 850 | return rsnd_mod_get(rsnd_ssi_get(priv, id)); |
| 740 | * DMA | 851 | } |
| 741 | */ | ||
| 742 | ssi_info->dma_id = of_get_property(np, "pio-transfer", NULL) ? | ||
| 743 | 0 : 1; | ||
| 744 | 852 | ||
| 745 | if (of_get_property(np, "no-busif", NULL)) | 853 | int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod) |
| 746 | ssi_info->flags |= RSND_SSI_NO_BUSIF; | 854 | { |
| 747 | } | 855 | struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); |
| 748 | 856 | ||
| 749 | rsnd_of_parse_ssi_end: | 857 | return !!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_CLK_PIN_SHARE); |
| 750 | of_node_put(node); | ||
| 751 | } | 858 | } |
| 752 | 859 | ||
| 753 | int rsnd_ssi_probe(struct platform_device *pdev, | 860 | int rsnd_ssi_probe(struct rsnd_priv *priv) |
| 754 | const struct rsnd_of_data *of_data, | ||
| 755 | struct rsnd_priv *priv) | ||
| 756 | { | 861 | { |
| 757 | struct rcar_snd_info *info = rsnd_priv_to_info(priv); | 862 | struct device_node *node; |
| 758 | struct rsnd_ssi_platform_info *pinfo; | 863 | struct device_node *np; |
| 759 | struct device *dev = rsnd_priv_to_dev(priv); | 864 | struct device *dev = rsnd_priv_to_dev(priv); |
| 760 | struct rsnd_mod_ops *ops; | 865 | struct rsnd_mod_ops *ops; |
| 761 | struct clk *clk; | 866 | struct clk *clk; |
| @@ -763,50 +868,73 @@ int rsnd_ssi_probe(struct platform_device *pdev, | |||
| 763 | char name[RSND_SSI_NAME_SIZE]; | 868 | char name[RSND_SSI_NAME_SIZE]; |
| 764 | int i, nr, ret; | 869 | int i, nr, ret; |
| 765 | 870 | ||
| 766 | rsnd_of_parse_ssi(pdev, of_data, priv); | 871 | node = rsnd_ssi_of_node(priv); |
| 872 | if (!node) | ||
| 873 | return -EINVAL; | ||
| 874 | |||
| 875 | nr = of_get_child_count(node); | ||
| 876 | if (!nr) { | ||
| 877 | ret = -EINVAL; | ||
| 878 | goto rsnd_ssi_probe_done; | ||
| 879 | } | ||
| 767 | 880 | ||
| 768 | /* | ||
| 769 | * init SSI | ||
| 770 | */ | ||
| 771 | nr = info->ssi_info_nr; | ||
| 772 | ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); | 881 | ssi = devm_kzalloc(dev, sizeof(*ssi) * nr, GFP_KERNEL); |
| 773 | if (!ssi) | 882 | if (!ssi) { |
| 774 | return -ENOMEM; | 883 | ret = -ENOMEM; |
| 884 | goto rsnd_ssi_probe_done; | ||
| 885 | } | ||
| 775 | 886 | ||
| 776 | priv->ssi = ssi; | 887 | priv->ssi = ssi; |
| 777 | priv->ssi_nr = nr; | 888 | priv->ssi_nr = nr; |
| 778 | 889 | ||
| 779 | for_each_rsnd_ssi(ssi, priv, i) { | 890 | i = 0; |
| 780 | pinfo = &info->ssi_info[i]; | 891 | for_each_child_of_node(node, np) { |
| 892 | ssi = rsnd_ssi_get(priv, i); | ||
| 781 | 893 | ||
| 782 | snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", | 894 | snprintf(name, RSND_SSI_NAME_SIZE, "%s.%d", |
| 783 | SSI_NAME, i); | 895 | SSI_NAME, i); |
| 784 | 896 | ||
| 785 | clk = devm_clk_get(dev, name); | 897 | clk = devm_clk_get(dev, name); |
| 786 | if (IS_ERR(clk)) | 898 | if (IS_ERR(clk)) { |
| 787 | return PTR_ERR(clk); | 899 | ret = PTR_ERR(clk); |
| 900 | goto rsnd_ssi_probe_done; | ||
| 901 | } | ||
| 788 | 902 | ||
| 789 | ssi->info = pinfo; | 903 | if (of_get_property(np, "shared-pin", NULL)) |
| 904 | ssi->flags |= RSND_SSI_CLK_PIN_SHARE; | ||
| 905 | |||
| 906 | if (of_get_property(np, "no-busif", NULL)) | ||
| 907 | ssi->flags |= RSND_SSI_NO_BUSIF; | ||
| 908 | |||
| 909 | ssi->irq = irq_of_parse_and_map(np, 0); | ||
| 910 | if (!ssi->irq) { | ||
| 911 | ret = -EINVAL; | ||
| 912 | goto rsnd_ssi_probe_done; | ||
| 913 | } | ||
| 790 | 914 | ||
| 791 | ops = &rsnd_ssi_non_ops; | 915 | ops = &rsnd_ssi_non_ops; |
| 792 | if (pinfo->dma_id > 0) | 916 | if (of_get_property(np, "pio-transfer", NULL)) |
| 793 | ops = &rsnd_ssi_dma_ops; | ||
| 794 | else if (rsnd_ssi_pio_available(ssi)) | ||
| 795 | ops = &rsnd_ssi_pio_ops; | 917 | ops = &rsnd_ssi_pio_ops; |
| 918 | else | ||
| 919 | ops = &rsnd_ssi_dma_ops; | ||
| 796 | 920 | ||
| 797 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, | 921 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssi), ops, clk, |
| 798 | RSND_MOD_SSI, i); | 922 | RSND_MOD_SSI, i); |
| 799 | if (ret) | 923 | if (ret) |
| 800 | return ret; | 924 | goto rsnd_ssi_probe_done; |
| 801 | 925 | ||
| 802 | rsnd_ssi_parent_setup(priv, ssi); | 926 | i++; |
| 803 | } | 927 | } |
| 804 | 928 | ||
| 805 | return 0; | 929 | ret = 0; |
| 930 | |||
| 931 | rsnd_ssi_probe_done: | ||
| 932 | of_node_put(node); | ||
| 933 | |||
| 934 | return ret; | ||
| 806 | } | 935 | } |
| 807 | 936 | ||
| 808 | void rsnd_ssi_remove(struct platform_device *pdev, | 937 | void rsnd_ssi_remove(struct rsnd_priv *priv) |
| 809 | struct rsnd_priv *priv) | ||
| 810 | { | 938 | { |
| 811 | struct rsnd_ssi *ssi; | 939 | struct rsnd_ssi *ssi; |
| 812 | int i; | 940 | int i; |
diff --git a/sound/soc/sh/rcar/ssiu.c b/sound/soc/sh/rcar/ssiu.c new file mode 100644 index 000000000000..3fe9e08e81a3 --- /dev/null +++ b/sound/soc/sh/rcar/ssiu.c | |||
| @@ -0,0 +1,225 @@ | |||
| 1 | /* | ||
| 2 | * Renesas R-Car SSIU support | ||
| 3 | * | ||
| 4 | * Copyright (c) 2015 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License version 2 as | ||
| 8 | * published by the Free Software Foundation. | ||
| 9 | */ | ||
| 10 | #include "rsnd.h" | ||
| 11 | |||
| 12 | #define SSIU_NAME "ssiu" | ||
| 13 | |||
| 14 | struct rsnd_ssiu { | ||
| 15 | struct rsnd_mod mod; | ||
| 16 | }; | ||
| 17 | |||
| 18 | #define rsnd_ssiu_nr(priv) ((priv)->ssiu_nr) | ||
| 19 | #define for_each_rsnd_ssiu(pos, priv, i) \ | ||
| 20 | for (i = 0; \ | ||
| 21 | (i < rsnd_ssiu_nr(priv)) && \ | ||
| 22 | ((pos) = ((struct rsnd_ssiu *)(priv)->ssiu + i)); \ | ||
| 23 | i++) | ||
| 24 | |||
| 25 | static int rsnd_ssiu_init(struct rsnd_mod *mod, | ||
| 26 | struct rsnd_dai_stream *io, | ||
| 27 | struct rsnd_priv *priv) | ||
| 28 | { | ||
| 29 | struct rsnd_dai *rdai = rsnd_io_to_rdai(io); | ||
| 30 | u32 multi_ssi_slaves = rsnd_ssi_multi_slaves(io); | ||
| 31 | int use_busif = rsnd_ssi_use_busif(io); | ||
| 32 | int id = rsnd_mod_id(mod); | ||
| 33 | u32 mask1, val1; | ||
| 34 | u32 mask2, val2; | ||
| 35 | |||
| 36 | /* | ||
| 37 | * SSI_MODE0 | ||
| 38 | */ | ||
| 39 | rsnd_mod_bset(mod, SSI_MODE0, (1 << id), !use_busif << id); | ||
| 40 | |||
| 41 | /* | ||
| 42 | * SSI_MODE1 | ||
| 43 | */ | ||
| 44 | mask1 = (1 << 4) | (1 << 20); /* mask sync bit */ | ||
| 45 | mask2 = (1 << 4); /* mask sync bit */ | ||
| 46 | val1 = val2 = 0; | ||
| 47 | if (rsnd_ssi_is_pin_sharing(io)) { | ||
| 48 | int shift = -1; | ||
| 49 | |||
| 50 | switch (id) { | ||
| 51 | case 1: | ||
| 52 | shift = 0; | ||
| 53 | break; | ||
| 54 | case 2: | ||
| 55 | shift = 2; | ||
| 56 | break; | ||
| 57 | case 4: | ||
| 58 | shift = 16; | ||
| 59 | break; | ||
| 60 | default: | ||
| 61 | return -EINVAL; | ||
| 62 | } | ||
| 63 | |||
| 64 | mask1 |= 0x3 << shift; | ||
| 65 | val1 = rsnd_rdai_is_clk_master(rdai) ? | ||
| 66 | 0x2 << shift : 0x1 << shift; | ||
| 67 | |||
| 68 | } else if (multi_ssi_slaves) { | ||
| 69 | |||
| 70 | mask2 |= 0x00000007; | ||
| 71 | mask1 |= 0x0000000f; | ||
| 72 | |||
| 73 | switch (multi_ssi_slaves) { | ||
| 74 | case 0x0206: /* SSI0/1/2/9 */ | ||
| 75 | val2 = (1 << 4) | /* SSI0129 sync */ | ||
| 76 | rsnd_rdai_is_clk_master(rdai) ? 0x2 : 0x1; | ||
| 77 | /* fall through */ | ||
| 78 | case 0x0006: /* SSI0/1/2 */ | ||
| 79 | val1 = rsnd_rdai_is_clk_master(rdai) ? | ||
| 80 | 0xa : 0x5; | ||
| 81 | |||
| 82 | if (!val2) /* SSI012 sync */ | ||
| 83 | val1 |= (1 << 4); | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | rsnd_mod_bset(mod, SSI_MODE1, mask1, val1); | ||
| 88 | rsnd_mod_bset(mod, SSI_MODE2, mask2, val2); | ||
| 89 | |||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen1 = { | ||
| 94 | .name = SSIU_NAME, | ||
| 95 | .init = rsnd_ssiu_init, | ||
| 96 | }; | ||
| 97 | |||
| 98 | static int rsnd_ssiu_init_gen2(struct rsnd_mod *mod, | ||
| 99 | struct rsnd_dai_stream *io, | ||
| 100 | struct rsnd_priv *priv) | ||
| 101 | { | ||
| 102 | int ret; | ||
| 103 | |||
| 104 | ret = rsnd_ssiu_init(mod, io, priv); | ||
| 105 | if (ret < 0) | ||
| 106 | return ret; | ||
| 107 | |||
| 108 | if (rsnd_get_slot_width(io) >= 6) { | ||
| 109 | /* | ||
| 110 | * TDM Extend Mode | ||
| 111 | * see | ||
| 112 | * rsnd_ssi_config_init() | ||
| 113 | */ | ||
| 114 | rsnd_mod_write(mod, SSI_MODE, 0x1); | ||
| 115 | } | ||
| 116 | |||
| 117 | if (rsnd_ssi_use_busif(io)) { | ||
| 118 | u32 val = rsnd_get_dalign(mod, io); | ||
| 119 | |||
| 120 | rsnd_mod_write(mod, SSI_BUSIF_ADINR, | ||
| 121 | rsnd_get_adinr_bit(mod, io) | | ||
| 122 | rsnd_get_adinr_chan(mod, io)); | ||
| 123 | rsnd_mod_write(mod, SSI_BUSIF_MODE, 1); | ||
| 124 | rsnd_mod_write(mod, SSI_BUSIF_DALIGN, val); | ||
| 125 | } | ||
| 126 | |||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int rsnd_ssiu_start_gen2(struct rsnd_mod *mod, | ||
| 131 | struct rsnd_dai_stream *io, | ||
| 132 | struct rsnd_priv *priv) | ||
| 133 | { | ||
| 134 | if (!rsnd_ssi_use_busif(io)) | ||
| 135 | return 0; | ||
| 136 | |||
| 137 | rsnd_mod_write(mod, SSI_CTRL, 0x1); | ||
| 138 | |||
| 139 | if (rsnd_ssi_multi_slaves(io)) | ||
| 140 | rsnd_mod_write(mod, SSI_CONTROL, 0x1); | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int rsnd_ssiu_stop_gen2(struct rsnd_mod *mod, | ||
| 146 | struct rsnd_dai_stream *io, | ||
| 147 | struct rsnd_priv *priv) | ||
| 148 | { | ||
| 149 | if (!rsnd_ssi_use_busif(io)) | ||
| 150 | return 0; | ||
| 151 | |||
| 152 | rsnd_mod_write(mod, SSI_CTRL, 0); | ||
| 153 | |||
| 154 | if (rsnd_ssi_multi_slaves(io)) | ||
| 155 | rsnd_mod_write(mod, SSI_CONTROL, 0); | ||
| 156 | |||
| 157 | return 0; | ||
| 158 | } | ||
| 159 | |||
| 160 | static struct rsnd_mod_ops rsnd_ssiu_ops_gen2 = { | ||
| 161 | .name = SSIU_NAME, | ||
| 162 | .init = rsnd_ssiu_init_gen2, | ||
| 163 | .start = rsnd_ssiu_start_gen2, | ||
| 164 | .stop = rsnd_ssiu_stop_gen2, | ||
| 165 | }; | ||
| 166 | |||
| 167 | static struct rsnd_mod *rsnd_ssiu_mod_get(struct rsnd_priv *priv, int id) | ||
| 168 | { | ||
| 169 | if (WARN_ON(id < 0 || id >= rsnd_ssiu_nr(priv))) | ||
| 170 | id = 0; | ||
| 171 | |||
| 172 | return rsnd_mod_get((struct rsnd_ssiu *)(priv->ssiu) + id); | ||
| 173 | } | ||
| 174 | |||
| 175 | int rsnd_ssiu_attach(struct rsnd_dai_stream *io, | ||
| 176 | struct rsnd_mod *ssi_mod) | ||
| 177 | { | ||
| 178 | struct rsnd_priv *priv = rsnd_io_to_priv(io); | ||
| 179 | struct rsnd_mod *mod = rsnd_ssiu_mod_get(priv, rsnd_mod_id(ssi_mod)); | ||
| 180 | |||
| 181 | rsnd_mod_confirm_ssi(ssi_mod); | ||
| 182 | |||
| 183 | return rsnd_dai_connect(mod, io, mod->type); | ||
| 184 | } | ||
| 185 | |||
| 186 | int rsnd_ssiu_probe(struct rsnd_priv *priv) | ||
| 187 | { | ||
| 188 | struct device *dev = rsnd_priv_to_dev(priv); | ||
| 189 | struct rsnd_ssiu *ssiu; | ||
| 190 | static struct rsnd_mod_ops *ops; | ||
| 191 | int i, nr, ret; | ||
| 192 | |||
| 193 | /* same number to SSI */ | ||
| 194 | nr = priv->ssi_nr; | ||
| 195 | ssiu = devm_kzalloc(dev, sizeof(*ssiu) * nr, GFP_KERNEL); | ||
| 196 | if (!ssiu) | ||
| 197 | return -ENOMEM; | ||
| 198 | |||
| 199 | priv->ssiu = ssiu; | ||
| 200 | priv->ssiu_nr = nr; | ||
| 201 | |||
| 202 | if (rsnd_is_gen1(priv)) | ||
| 203 | ops = &rsnd_ssiu_ops_gen1; | ||
| 204 | else | ||
| 205 | ops = &rsnd_ssiu_ops_gen2; | ||
| 206 | |||
| 207 | for_each_rsnd_ssiu(ssiu, priv, i) { | ||
| 208 | ret = rsnd_mod_init(priv, rsnd_mod_get(ssiu), | ||
| 209 | ops, NULL, RSND_MOD_SSIU, i); | ||
| 210 | if (ret) | ||
| 211 | return ret; | ||
| 212 | } | ||
| 213 | |||
| 214 | return 0; | ||
| 215 | } | ||
| 216 | |||
| 217 | void rsnd_ssiu_remove(struct rsnd_priv *priv) | ||
| 218 | { | ||
| 219 | struct rsnd_ssiu *ssiu; | ||
| 220 | int i; | ||
| 221 | |||
| 222 | for_each_rsnd_ssiu(ssiu, priv, i) { | ||
| 223 | rsnd_mod_quit(rsnd_mod_get(ssiu)); | ||
| 224 | } | ||
| 225 | } | ||
