Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751786AbdGEQUl (ORCPT ); Wed, 5 Jul 2017 12:20:41 -0400 Received: from mail.free-electrons.com ([62.4.15.54]:59066 "EHLO mail.free-electrons.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751444AbdGEQUk (ORCPT ); Wed, 5 Jul 2017 12:20:40 -0400 Date: Wed, 5 Jul 2017 18:20:28 +0200 From: Maxime Ripard To: codekipper@gmail.com Cc: linux-arm-kernel@lists.infradead.org, linux-sunxi@googlegroups.com, lgirdwood@gmail.com, broonie@kernel.org, linux-kernel@vger.kernel.org, alsa-devel@alsa-project.org, be17068@iperbole.bo.it Subject: Re: [PATCH 3/3] ASoC: sun4i-i2s: Add support for H3 Message-ID: <20170705162028.odqazlzcjndpvkyo@flea> References: <20170705154324.14565-1-codekipper@gmail.com> <20170705154324.14565-4-codekipper@gmail.com> MIME-Version: 1.0 Content-Type: multipart/signed; micalg=pgp-sha1; protocol="application/pgp-signature"; boundary="3qreuba7ktdiuluy" Content-Disposition: inline In-Reply-To: <20170705154324.14565-4-codekipper@gmail.com> User-Agent: NeoMutt/20170609 (1.8.3) Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 18897 Lines: 618 --3qreuba7ktdiuluy Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-Transfer-Encoding: quoted-printable On Wed, Jul 05, 2017 at 05:43:24PM +0200, codekipper@gmail.com wrote: > From: Marcus Cooper >=20 > There are a lot of changes to the sun8i-h3 i2s block but not enough > to warrant to a new driver. >=20 > Signed-off-by: Marcus Cooper > --- > .../devicetree/bindings/sound/sun4i-i2s.txt | 2 + > sound/soc/sunxi/sun4i-i2s.c | 339 +++++++++++++++= +++++- > 2 files changed, 337 insertions(+), 4 deletions(-) >=20 > diff --git a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt b/Docu= mentation/devicetree/bindings/sound/sun4i-i2s.txt > index ee21da865771..fc5da6080759 100644 > --- a/Documentation/devicetree/bindings/sound/sun4i-i2s.txt > +++ b/Documentation/devicetree/bindings/sound/sun4i-i2s.txt > @@ -8,6 +8,7 @@ Required properties: > - compatible: should be one of the following: > - "allwinner,sun4i-a10-i2s" > - "allwinner,sun6i-a31-i2s" > + - "allwinner,sun8i-h3-i2s" > - reg: physical base address of the controller and length of memory mapp= ed > region. > - interrupts: should contain the I2S interrupt. > @@ -22,6 +23,7 @@ Required properties: > =20 > Required properties for the following compatibles: > - "allwinner,sun6i-a31-i2s" > + - "allwinner,sun8i-h3-i2s" > - resets: phandle to the reset line for this codec > =20 > Example: > diff --git a/sound/soc/sunxi/sun4i-i2s.c b/sound/soc/sunxi/sun4i-i2s.c > index bb7affd53002..0b853fe320e0 100644 > --- a/sound/soc/sunxi/sun4i-i2s.c > +++ b/sound/soc/sunxi/sun4i-i2s.c > @@ -26,9 +26,16 @@ > #include > =20 > #define SUN4I_I2S_CTRL_REG 0x00 > +#define SUN4I_I2S_CTRL_BCLK_OUT BIT(18) > +#define SUN4I_I2S_CTRL_LRCK_OUT BIT(17) > +#define SUN4I_I2S_CTRL_LRCKR_OUT BIT(16) > #define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8) > #define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo)) > #define SUN4I_I2S_CTRL_MODE_MASK BIT(5) > +#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) > +#define SUN8I_I2S_CTRL_MODE_RIGHT_J (2 << 4) > +#define SUN8I_I2S_CTRL_MODE_I2S (1 << 4) > +#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) > #define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5) > #define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5) > #define SUN4I_I2S_CTRL_TX_EN BIT(2) > @@ -36,16 +43,27 @@ > #define SUN4I_I2S_CTRL_GL_EN BIT(0) > =20 > #define SUN4I_I2S_FMT0_REG 0x04 > +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) > +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) > +#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) > +#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) > +#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period) << 8) > #define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7) > #define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7) > #define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 7) > +#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) > +#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) > +#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) > #define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK BIT(6) > #define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 6) > #define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 6) > #define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4) > +#define SUN8I_I2S_FMT0_SR_MASK GENMASK(6, 4) > #define SUN4I_I2S_FMT0_SR(sr) ((sr) << 4) > #define SUN4I_I2S_FMT0_WSS_MASK GENMASK(3, 2) > #define SUN4I_I2S_FMT0_WSS(wss) ((wss) << 2) > +#define SUN8I_I2S_FMT0_WSS_MASK GENMASK(2, 0) > +#define SUN8I_I2S_FMT0_WSS(wss) (wss) > #define SUN4I_I2S_FMT0_FMT_MASK GENMASK(1, 0) > #define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) > #define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) > @@ -53,6 +71,7 @@ > =20 > #define SUN4I_I2S_FMT1_REG 0x08 > #define SUN4I_I2S_FIFO_TX_REG 0x0c > +#define SUN8I_I2S_INT_STA_REG 0x0c > #define SUN4I_I2S_FIFO_RX_REG 0x10 > =20 > #define SUN4I_I2S_FIFO_CTRL_REG 0x14 > @@ -70,10 +89,13 @@ > #define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN BIT(3) > =20 > #define SUN4I_I2S_INT_STA_REG 0x20 > +#define SUN8I_I2S_FIFO_TX_REG 0x20 > =20 > #define SUN4I_I2S_CLK_DIV_REG 0x24 > +#define SUN8I_I2S_CLK_DIV_MCLK_EN BIT(8) > #define SUN4I_I2S_CLK_DIV_MCLK_EN BIT(7) > #define SUN4I_I2S_CLK_DIV_BCLK_MASK GENMASK(6, 4) > +#define SUN8I_I2S_CLK_DIV_BCLK_MASK GENMASK(7, 4) > #define SUN4I_I2S_CLK_DIV_BCLK(bclk) ((bclk) << 4) > #define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) > #define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) > @@ -82,14 +104,27 @@ > #define SUN4I_I2S_TX_CNT_REG 0x2c > =20 > #define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 > +#define SUN8I_I2S_TX_CHAN_CFG_REG 0x30 > #define SUN4I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) > =20 > #define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 > #define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2)) > +#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34 > +#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12) > +#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12) > +#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4) > +#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4) > +#define SUN8I_I2S_TX_CHAN_SEL_MASK GENMASK(2, 0) > +#define SUN8I_I2S_TX_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) > =20 > #define SUN4I_I2S_RX_CHAN_SEL_REG 0x38 > #define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c > =20 > +#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44 > + > +#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 > +#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58 > + > struct sun4i_i2s { > struct clk *bus_clk; > struct clk *mod_clk; > @@ -363,6 +398,225 @@ static int sun4i_i2s_set_fmt(struct snd_soc_dai *da= i, unsigned int fmt) > return 0; > } > =20 > +static int sun8i_i2s_set_clk_rate(struct sun4i_i2s *i2s, > + unsigned int rate, > + unsigned int word_size) > +{ > + unsigned int clk_rate; > + int bclk_div, mclk_div; > + int ret, i; > + > + switch (rate) { > + case 176400: > + case 88200: > + case 44100: > + case 22050: > + case 11025: > + clk_rate =3D 22579200; > + break; > + > + case 192000: > + case 128000: > + case 96000: > + case 64000: > + case 48000: > + case 32000: > + case 24000: > + case 16000: > + case 12000: > + case 8000: > + clk_rate =3D 24576000; > + break; > + > + default: > + return -EINVAL; > + } > + > + ret =3D clk_set_rate(i2s->mod_clk, clk_rate); > + if (ret) > + return ret; > + > + /* Always favor the highest oversampling rate */ > + for (i =3D (ARRAY_SIZE(sun4i_i2s_oversample_rates) - 1); i >=3D 0; i--)= { > + unsigned int oversample_rate =3D sun4i_i2s_oversample_rates[i]; > + > + bclk_div =3D sun4i_i2s_get_bclk_div(i2s, oversample_rate, > + word_size); > + mclk_div =3D sun4i_i2s_get_mclk_div(i2s, oversample_rate, > + clk_rate, > + rate); > + > + if ((bclk_div >=3D 0) && (mclk_div >=3D 0)) > + break; > + } > + > + if ((bclk_div < 0) || (mclk_div < 0)) > + return -EINVAL; > + > + regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, > + SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | > + SUN4I_I2S_CLK_DIV_MCLK(mclk_div + 1) | > + SUN8I_I2S_CLK_DIV_MCLK_EN); Duplicating all that code just for a single bit difference doesn't seem very wise. You can handle that bit difference through regmap_fields. > + /* Set sync period */ > + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, > + SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, > + SUN8I_I2S_FMT0_LRCK_PERIOD((2 * word_size)-1)); > + regmap_write(i2s->regmap, SUN4I_I2S_FMT1_REG, 0); It seems to be applicable for the old flavour too, why isn't it there? > + > + return 0; > +} > + > +static int sun8i_i2s_hw_params(struct snd_pcm_substream *substream, > + struct snd_pcm_hw_params *params, > + struct snd_soc_dai *dai) > +{ > + struct sun4i_i2s *i2s =3D snd_soc_dai_get_drvdata(dai); > + int sr, wss; > + u32 width, channels =3D 0; > + > + switch (params_channels(params)) { > + case 2: > + channels |=3D SUN4I_I2S_CTRL_SDO_EN(0); > + break; > + default: > + dev_err(dai->dev, "invalid channel: %d\n", > + params_channels(params)); > + return -EINVAL; > + } > + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, > + SUN4I_I2S_CTRL_SDO_EN_MASK, channels); This seems applicable to the old generation. > + /* Configure the channels */ > + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_CFG_REG, > + SUN4I_I2S_TX_CHAN_SEL(params_channels(params))); This can be handled by regmap_fields. > + /* Select the channels */ > + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, > + SUN8I_I2S_TX_CHAN_EN_MASK | > + SUN8I_I2S_TX_CHAN_SEL_MASK, > + SUN8I_I2S_TX_CHAN_EN(params_channels(params)) | > + SUN8I_I2S_TX_CHAN_SEL(params_channels(params))); Ditto. > > + /* Map the channels for stereo playback */ > + regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, > + SUN4I_I2S_TX_CHAN_MAP(1, 1)); Ditto. > + /* Select the channels */ > + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, > + SUN8I_I2S_TX_CHAN_SEL(params_channels(params))); Ditto. > + /* Map the channels for stereo capture */ > + regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, > + SUN4I_I2S_TX_CHAN_MAP(1, 1)); Ditto. > + switch (params_physical_width(params)) { > + case 16: > + width =3D DMA_SLAVE_BUSWIDTH_2_BYTES; > + break; > + case 24: > + case 32: > + width =3D DMA_SLAVE_BUSWIDTH_4_BYTES; > + break; > + default: > + return -EINVAL; > + } > + i2s->playback_dma_data.addr_width =3D width; This is applicable to the old generation. > + > + switch (params_width(params)) { > + case 16: > + sr =3D 3; > + wss =3D 3; > + break; > + case 20: > + sr =3D 4; > + wss =3D 4; > + break; > + case 24: > + sr =3D 5; > + wss =3D 5; > + break; > + default: > + return -EINVAL; > + } It looks like this changed, maybe we can split it into a separate function? > + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, > + SUN8I_I2S_FMT0_WSS_MASK | SUN8I_I2S_FMT0_SR_MASK, > + SUN8I_I2S_FMT0_WSS(wss) | SUN4I_I2S_FMT0_SR(sr)); > + > + return sun8i_i2s_set_clk_rate(i2s, params_rate(params), > + params_width(params)); > +} > + > +static int sun8i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) > +{ > + struct sun4i_i2s *i2s =3D snd_soc_dai_get_drvdata(dai); > + u32 val =3D SUN8I_I2S_CTRL_MODE_I2S; > + u32 offset =3D 0; > + > + /* DAI Mode */ > + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { > + case SND_SOC_DAIFMT_I2S: > + offset =3D 1; > + break; > + case SND_SOC_DAIFMT_LEFT_J: > + break; > + case SND_SOC_DAIFMT_RIGHT_J: > + val =3D SUN8I_I2S_CTRL_MODE_RIGHT_J; > + break; > + default: > + return -EINVAL; > + } > + > + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, > + SUN8I_I2S_CTRL_MODE_MASK, > + val); > + > + /* blck offset determines whether i2s or LJ */ > + regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, > + SUN8I_I2S_TX_CHAN_OFFSET_MASK, > + SUN8I_I2S_TX_CHAN_OFFSET(offset)); > + > + /* DAI clock polarity */ > + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { > + case SND_SOC_DAIFMT_IB_IF: > + /* Invert both clocks */ > + val =3D SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | > + SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; > + break; > + case SND_SOC_DAIFMT_IB_NF: > + /* Invert bit clock */ > + val =3D SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | > + SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL; > + break; > + case SND_SOC_DAIFMT_NB_IF: > + /* Invert frame clock */ > + val =3D SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED | > + SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL; > + break; > + case SND_SOC_DAIFMT_NB_NF: > + /* Nothing to do for both normal cases */ > + val =3D SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL | > + SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL; > + break; > + default: > + return -EINVAL; > + } > + > + regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, > + SUN8I_I2S_FMT0_BCLK_POLARITY_MASK | > + SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK, > + val); > + > + /* Set significant bits in our FIFOs */ > + regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, > + SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | > + SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, > + SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | > + SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); > + return 0; > +} > + > static void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) > { > /* Flush RX FIFO */ > @@ -471,8 +725,8 @@ static int sun4i_i2s_startup(struct snd_pcm_substream= *substream, > int ret =3D 0; > =20 > /* Enable the whole hardware block */ > - regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, > - SUN4I_I2S_CTRL_GL_EN); > + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, > + SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); Why? This needs to be explained. > =20 > /* Enable the first output line */ > regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, > @@ -500,7 +754,8 @@ static void sun4i_i2s_shutdown(struct snd_pcm_substre= am *substream, > SUN4I_I2S_CTRL_SDO_EN_MASK, 0); > =20 > /* Disable the whole hardware block */ > - regmap_write(i2s->regmap, SUN4I_I2S_CTRL_REG, 0); > + regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, > + SUN4I_I2S_CTRL_GL_EN, 0); Ditto. > } > =20 > static int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, > @@ -525,6 +780,15 @@ static const struct snd_soc_dai_ops sun4i_i2s_dai_op= s =3D { > .trigger =3D sun4i_i2s_trigger, > }; > =20 > +static const struct snd_soc_dai_ops sun8i_i2s_dai_ops =3D { > + .hw_params =3D sun8i_i2s_hw_params, > + .set_fmt =3D sun8i_i2s_set_fmt, > + .set_sysclk =3D sun4i_i2s_set_sysclk, > + .shutdown =3D sun4i_i2s_shutdown, > + .startup =3D sun4i_i2s_startup, > + .trigger =3D sun4i_i2s_trigger, > +}; > + > static int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) > { > struct sun4i_i2s *i2s =3D snd_soc_dai_get_drvdata(dai); > @@ -572,11 +836,11 @@ static bool sun4i_i2s_rd_reg(struct device *dev, un= signed int reg) > } > } > =20 > + This one looks unnecessary > static bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg) > { > switch (reg) { > case SUN4I_I2S_FIFO_RX_REG: > - case SUN4I_I2S_FIFO_STA_REG: This needs to be explained > return false; > =20 > default: > @@ -588,6 +852,7 @@ static bool sun4i_i2s_volatile_reg(struct device *dev= , unsigned int reg) > { > switch (reg) { > case SUN4I_I2S_FIFO_RX_REG: > + case SUN4I_I2S_FIFO_STA_REG: Ditto. > case SUN4I_I2S_INT_STA_REG: > case SUN4I_I2S_RX_CNT_REG: > case SUN4I_I2S_TX_CNT_REG: > @@ -598,6 +863,34 @@ static bool sun4i_i2s_volatile_reg(struct device *de= v, unsigned int reg) > } > } > =20 > +static bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg) > +{ > + switch (reg) { > + case SUN8I_I2S_FIFO_TX_REG: > + return false; > + > + default: > + return true; > + } > +} It also applies to the old generation. > +static bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) > +{ > + switch (reg) { > + case SUN4I_I2S_FIFO_RX_REG: > + case SUN4I_I2S_FIFO_CTRL_REG: > + case SUN4I_I2S_FIFO_STA_REG: > + case SUN8I_I2S_INT_STA_REG: > + case SUN4I_I2S_RX_CNT_REG: > + case SUN4I_I2S_TX_CNT_REG: > + case SUN4I_I2S_TX_CHAN_MAP_REG: > + return true; > + > + default: > + return false; > + } > +} Besides the H3 interrupt status, it looks duplicated. Can't we share both implementations with a condition for that register? > + > static const struct reg_default sun4i_i2s_reg_defaults[] =3D { > { SUN4I_I2S_CTRL_REG, 0x00000000 }, > { SUN4I_I2S_FMT0_REG, 0x0000000c }, > @@ -611,6 +904,20 @@ static const struct reg_default sun4i_i2s_reg_defaul= ts[] =3D { > { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 }, > }; > =20 > +static const struct reg_default sun8i_i2s_reg_defaults[] =3D { > + { SUN4I_I2S_CTRL_REG, 0x00060000 }, > + { SUN4I_I2S_FMT0_REG, 0x00000033 }, > + { SUN4I_I2S_FMT1_REG, 0x00000030 }, > + { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, > + { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, > + { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, > + { SUN8I_I2S_TX_CHAN_CFG_REG, 0x00000000 }, > + { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 }, > + { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 }, > + { SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 }, > + { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 }, > +}; > + > static const struct regmap_config sun4i_i2s_regmap_config =3D { > .reg_bits =3D 32, > .reg_stride =3D 4, > @@ -625,6 +932,19 @@ static const struct regmap_config sun4i_i2s_regmap_c= onfig =3D { > .volatile_reg =3D sun4i_i2s_volatile_reg, > }; > =20 > +static const struct regmap_config sun8i_i2s_regmap_config =3D { > + .reg_bits =3D 32, > + .reg_stride =3D 4, > + .val_bits =3D 32, > + .max_register =3D SUN8I_I2S_RX_CHAN_MAP_REG, > + .cache_type =3D REGCACHE_FLAT, > + .reg_defaults =3D sun8i_i2s_reg_defaults, > + .num_reg_defaults =3D ARRAY_SIZE(sun8i_i2s_reg_defaults), > + .writeable_reg =3D sun4i_i2s_wr_reg, > + .readable_reg =3D sun8i_i2s_rd_reg, > + .volatile_reg =3D sun8i_i2s_volatile_reg, > +}; > + > static int sun4i_i2s_runtime_resume(struct device *dev) > { > struct sun4i_i2s *i2s =3D dev_get_drvdata(dev); > @@ -684,6 +1004,13 @@ static const struct sun4i_i2s_quirks sun6i_a31_i2s_= quirks =3D { > .ops =3D &sun4i_i2s_dai_ops, > }; > =20 > +static const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks =3D { > + .has_reset =3D true, > + .reg_offset_txdata =3D SUN8I_I2S_FIFO_TX_REG, > + .sun4i_i2s_regmap =3D &sun8i_i2s_regmap_config, > + .ops =3D &sun8i_i2s_dai_ops, > +}; > + > static int sun4i_i2s_probe(struct platform_device *pdev) > { > struct sun4i_i2s *i2s; > @@ -823,6 +1150,10 @@ static const struct of_device_id sun4i_i2s_match[] = =3D { > .compatible =3D "allwinner,sun6i-a31-i2s", > .data =3D &sun6i_a31_i2s_quirks, > }, > + { > + .compatible =3D "allwinner,sun8i-h3-i2s", > + .data =3D &sun8i_h3_i2s_quirks, > + }, > {} > }; > MODULE_DEVICE_TABLE(of, sun4i_i2s_match); > --=20 > 2.13.2 >=20 Thanks! Maxime --=20 Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com --3qreuba7ktdiuluy Content-Type: application/pgp-signature; name="signature.asc" -----BEGIN PGP SIGNATURE----- iQIcBAEBAgAGBQJZXRHMAAoJEBx+YmzsjxAgqNMP/RMIm2RRZMQA1eWfkeDNV3Ca wcw13mv59uW3evVcHR1X4txpVqJv9qd1PMLheGgVFgZ0shCPlyU6B+LDjcBPucUG VTLqYgRLEpIOEOpGdW1mp9tptRjwvWQzQNSGe/BIC5QOEFAIq028QOK6McD2xNBf iMX49GyXjMx9j8h+r900cBsxbzmZzO5R+YLQAOTilfvBiR+caMg+acwivoHmq2Tz IrjWyK+za3Yl1CzKQaspnZ+kgET5RZKv0Kyw3WkpuYjjkEfQDCrFEsoUqAeit/Fm H89+hRXaU+E4ZV78y43GCMkfOacILYB0x9WGC3I7mGgYC5Zg/PGNYdOXVrM03yTC 5tH4F01QcjK2hBWm1KlJGGhFRN8LfEJkd5rhdHJz/HBbUg9USWNt5md1Zxj2KFoJ ok9W/XJ5plVaT8u2RH+w9/hI5aqzs7ZzQxOquF3S/jpFrONk21rwI+WXKRph/3Fd L2+oFUA/bfBj0beUK2xS3tBg2IVX8Irl2ugfr0p3pcbJkbqQVHfx0yOSdMKgPVbQ uPiYYU7Fi27kjKhqoTxjE32NIoHfez0/rkFpE406msX2NQQ4j1H9R6Yq/iYzST0J kfdpZOgRFFvlHii5IdS9NmyOSes9dQLmlOZDMq38ha7p6allfuQK6Pv/sqTau6ed Z3CSSKXhYP5g6uj/9+VK =63Px -----END PGP SIGNATURE----- --3qreuba7ktdiuluy--