162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2015 Andrea Venturi 462306a36Sopenharmony_ci * Andrea Venturi <be17068@iperbole.bo.it> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2016 Maxime Ripard 762306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/dmaengine.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of_device.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/regmap.h> 1762306a36Sopenharmony_ci#include <linux/reset.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 2062306a36Sopenharmony_ci#include <sound/pcm_params.h> 2162306a36Sopenharmony_ci#include <sound/soc.h> 2262306a36Sopenharmony_ci#include <sound/soc-dai.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_REG 0x00 2562306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_SDO_EN_MASK GENMASK(11, 8) 2662306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_SDO_EN(sdo) BIT(8 + (sdo)) 2762306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_MODE_MASK BIT(5) 2862306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_MODE_SLAVE (1 << 5) 2962306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_MODE_MASTER (0 << 5) 3062306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_TX_EN BIT(2) 3162306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_RX_EN BIT(1) 3262306a36Sopenharmony_ci#define SUN4I_I2S_CTRL_GL_EN BIT(0) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_REG 0x04 3562306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(7) 3662306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 7) 3762306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 7) 3862306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_BCLK_POLARITY_MASK BIT(6) 3962306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 6) 4062306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 6) 4162306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_SR_MASK GENMASK(5, 4) 4262306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_SR(sr) ((sr) << 4) 4362306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_WSS_MASK GENMASK(3, 2) 4462306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_WSS(wss) ((wss) << 2) 4562306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_FMT_MASK GENMASK(1, 0) 4662306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_FMT_RIGHT_J (2 << 0) 4762306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_FMT_LEFT_J (1 << 0) 4862306a36Sopenharmony_ci#define SUN4I_I2S_FMT0_FMT_I2S (0 << 0) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define SUN4I_I2S_FMT1_REG 0x08 5162306a36Sopenharmony_ci#define SUN4I_I2S_FMT1_REG_SEXT_MASK BIT(8) 5262306a36Sopenharmony_ci#define SUN4I_I2S_FMT1_REG_SEXT(sext) ((sext) << 8) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_TX_REG 0x0c 5562306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_RX_REG 0x10 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_REG 0x14 5862306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_FLUSH_TX BIT(25) 5962306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_FLUSH_RX BIT(24) 6062306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK BIT(2) 6162306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_TX_MODE(mode) ((mode) << 2) 6262306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK GENMASK(1, 0) 6362306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_CTRL_RX_MODE(mode) (mode) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define SUN4I_I2S_FIFO_STA_REG 0x18 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define SUN4I_I2S_DMA_INT_CTRL_REG 0x1c 6862306a36Sopenharmony_ci#define SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN BIT(7) 6962306a36Sopenharmony_ci#define SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN BIT(3) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define SUN4I_I2S_INT_STA_REG 0x20 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_REG 0x24 7462306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_MCLK_EN BIT(7) 7562306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_BCLK_MASK GENMASK(6, 4) 7662306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_BCLK(bclk) ((bclk) << 4) 7762306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_MCLK_MASK GENMASK(3, 0) 7862306a36Sopenharmony_ci#define SUN4I_I2S_CLK_DIV_MCLK(mclk) ((mclk) << 0) 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci#define SUN4I_I2S_TX_CNT_REG 0x28 8162306a36Sopenharmony_ci#define SUN4I_I2S_RX_CNT_REG 0x2c 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define SUN4I_I2S_TX_CHAN_SEL_REG 0x30 8462306a36Sopenharmony_ci#define SUN4I_I2S_CHAN_SEL_MASK GENMASK(2, 0) 8562306a36Sopenharmony_ci#define SUN4I_I2S_CHAN_SEL(num_chan) (((num_chan) - 1) << 0) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci#define SUN4I_I2S_TX_CHAN_MAP_REG 0x34 8862306a36Sopenharmony_ci#define SUN4I_I2S_TX_CHAN_MAP(chan, sample) ((sample) << (chan << 2)) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define SUN4I_I2S_RX_CHAN_SEL_REG 0x38 9162306a36Sopenharmony_ci#define SUN4I_I2S_RX_CHAN_MAP_REG 0x3c 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* Defines required for sun8i-h3 support */ 9462306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_BCLK_OUT BIT(18) 9562306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_LRCK_OUT BIT(17) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_MODE_MASK GENMASK(5, 4) 9862306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_MODE_RIGHT (2 << 4) 9962306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_MODE_LEFT (1 << 4) 10062306a36Sopenharmony_ci#define SUN8I_I2S_CTRL_MODE_PCM (0 << 4) 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK BIT(19) 10362306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED (1 << 19) 10462306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_LRCLK_POLARITY_NORMAL (0 << 19) 10562306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_LRCK_PERIOD_MASK GENMASK(17, 8) 10662306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_LRCK_PERIOD(period) ((period - 1) << 8) 10762306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_BCLK_POLARITY_MASK BIT(7) 10862306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED (1 << 7) 10962306a36Sopenharmony_ci#define SUN8I_I2S_FMT0_BCLK_POLARITY_NORMAL (0 << 7) 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci#define SUN8I_I2S_FMT1_REG_SEXT_MASK GENMASK(5, 4) 11262306a36Sopenharmony_ci#define SUN8I_I2S_FMT1_REG_SEXT(sext) ((sext) << 4) 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#define SUN8I_I2S_INT_STA_REG 0x0c 11562306a36Sopenharmony_ci#define SUN8I_I2S_FIFO_TX_REG 0x20 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define SUN8I_I2S_CHAN_CFG_REG 0x30 11862306a36Sopenharmony_ci#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK GENMASK(7, 4) 11962306a36Sopenharmony_ci#define SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(chan) ((chan - 1) << 4) 12062306a36Sopenharmony_ci#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK GENMASK(3, 0) 12162306a36Sopenharmony_ci#define SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(chan) (chan - 1) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_MAP_REG 0x44 12462306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_SEL_REG 0x34 12562306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_OFFSET_MASK GENMASK(13, 12) 12662306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_OFFSET(offset) (offset << 12) 12762306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_EN_MASK GENMASK(11, 4) 12862306a36Sopenharmony_ci#define SUN8I_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1) << 4) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define SUN8I_I2S_RX_CHAN_SEL_REG 0x54 13162306a36Sopenharmony_ci#define SUN8I_I2S_RX_CHAN_MAP_REG 0x58 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* Defines required for sun50i-h6 support */ 13462306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK GENMASK(21, 20) 13562306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset) ((offset) << 20) 13662306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_SEL_MASK GENMASK(19, 16) 13762306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_SEL(chan) ((chan - 1) << 16) 13862306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_EN_MASK GENMASK(15, 0) 13962306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_EN(num_chan) (((1 << num_chan) - 1)) 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_SEL_REG(pin) (0x34 + 4 * (pin)) 14262306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_MAP0_REG(pin) (0x44 + 8 * (pin)) 14362306a36Sopenharmony_ci#define SUN50I_H6_I2S_TX_CHAN_MAP1_REG(pin) (0x48 + 8 * (pin)) 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#define SUN50I_H6_I2S_RX_CHAN_SEL_REG 0x64 14662306a36Sopenharmony_ci#define SUN50I_H6_I2S_RX_CHAN_MAP0_REG 0x68 14762306a36Sopenharmony_ci#define SUN50I_H6_I2S_RX_CHAN_MAP1_REG 0x6C 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define SUN50I_R329_I2S_RX_CHAN_MAP0_REG 0x68 15062306a36Sopenharmony_ci#define SUN50I_R329_I2S_RX_CHAN_MAP1_REG 0x6c 15162306a36Sopenharmony_ci#define SUN50I_R329_I2S_RX_CHAN_MAP2_REG 0x70 15262306a36Sopenharmony_ci#define SUN50I_R329_I2S_RX_CHAN_MAP3_REG 0x74 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistruct sun4i_i2s; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/** 15762306a36Sopenharmony_ci * struct sun4i_i2s_quirks - Differences between SoC variants. 15862306a36Sopenharmony_ci * @has_reset: SoC needs reset deasserted. 15962306a36Sopenharmony_ci * @reg_offset_txdata: offset of the tx fifo. 16062306a36Sopenharmony_ci * @sun4i_i2s_regmap: regmap config to use. 16162306a36Sopenharmony_ci * @field_clkdiv_mclk_en: regmap field to enable mclk output. 16262306a36Sopenharmony_ci * @field_fmt_wss: regmap field to set word select size. 16362306a36Sopenharmony_ci * @field_fmt_sr: regmap field to set sample resolution. 16462306a36Sopenharmony_ci * @num_din_pins: input pins 16562306a36Sopenharmony_ci * @num_dout_pins: output pins (currently set but unused) 16662306a36Sopenharmony_ci * @bclk_dividers: bit clock dividers array 16762306a36Sopenharmony_ci * @num_bclk_dividers: number of bit clock dividers 16862306a36Sopenharmony_ci * @mclk_dividers: mclk dividers array 16962306a36Sopenharmony_ci * @num_mclk_dividers: number of mclk dividers 17062306a36Sopenharmony_ci * @get_bclk_parent_rate: callback to get bclk parent rate 17162306a36Sopenharmony_ci * @get_sr: callback to get sample resolution 17262306a36Sopenharmony_ci * @get_wss: callback to get word select size 17362306a36Sopenharmony_ci * @set_chan_cfg: callback to set channel configuration 17462306a36Sopenharmony_ci * @set_fmt: callback to set format 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_cistruct sun4i_i2s_quirks { 17762306a36Sopenharmony_ci bool has_reset; 17862306a36Sopenharmony_ci unsigned int reg_offset_txdata; /* TX FIFO */ 17962306a36Sopenharmony_ci const struct regmap_config *sun4i_i2s_regmap; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* Register fields for i2s */ 18262306a36Sopenharmony_ci struct reg_field field_clkdiv_mclk_en; 18362306a36Sopenharmony_ci struct reg_field field_fmt_wss; 18462306a36Sopenharmony_ci struct reg_field field_fmt_sr; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci unsigned int num_din_pins; 18762306a36Sopenharmony_ci unsigned int num_dout_pins; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *bclk_dividers; 19062306a36Sopenharmony_ci unsigned int num_bclk_dividers; 19162306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *mclk_dividers; 19262306a36Sopenharmony_ci unsigned int num_mclk_dividers; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci unsigned long (*get_bclk_parent_rate)(const struct sun4i_i2s *i2s); 19562306a36Sopenharmony_ci int (*get_sr)(unsigned int width); 19662306a36Sopenharmony_ci int (*get_wss)(unsigned int width); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * In the set_chan_cfg() function pointer: 20062306a36Sopenharmony_ci * @slots: channels per frame + padding slots, regardless of format 20162306a36Sopenharmony_ci * @slot_width: bits per sample + padding bits, regardless of format 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci int (*set_chan_cfg)(const struct sun4i_i2s *i2s, 20462306a36Sopenharmony_ci unsigned int channels, unsigned int slots, 20562306a36Sopenharmony_ci unsigned int slot_width); 20662306a36Sopenharmony_ci int (*set_fmt)(const struct sun4i_i2s *i2s, unsigned int fmt); 20762306a36Sopenharmony_ci}; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistruct sun4i_i2s { 21062306a36Sopenharmony_ci struct clk *bus_clk; 21162306a36Sopenharmony_ci struct clk *mod_clk; 21262306a36Sopenharmony_ci struct regmap *regmap; 21362306a36Sopenharmony_ci struct reset_control *rst; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci unsigned int format; 21662306a36Sopenharmony_ci unsigned int mclk_freq; 21762306a36Sopenharmony_ci unsigned int slots; 21862306a36Sopenharmony_ci unsigned int slot_width; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture_dma_data; 22162306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* Register fields for i2s */ 22462306a36Sopenharmony_ci struct regmap_field *field_clkdiv_mclk_en; 22562306a36Sopenharmony_ci struct regmap_field *field_fmt_wss; 22662306a36Sopenharmony_ci struct regmap_field *field_fmt_sr; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci const struct sun4i_i2s_quirks *variant; 22962306a36Sopenharmony_ci}; 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistruct sun4i_i2s_clk_div { 23262306a36Sopenharmony_ci u8 div; 23362306a36Sopenharmony_ci u8 val; 23462306a36Sopenharmony_ci}; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic const struct sun4i_i2s_clk_div sun4i_i2s_bclk_div[] = { 23762306a36Sopenharmony_ci { .div = 2, .val = 0 }, 23862306a36Sopenharmony_ci { .div = 4, .val = 1 }, 23962306a36Sopenharmony_ci { .div = 6, .val = 2 }, 24062306a36Sopenharmony_ci { .div = 8, .val = 3 }, 24162306a36Sopenharmony_ci { .div = 12, .val = 4 }, 24262306a36Sopenharmony_ci { .div = 16, .val = 5 }, 24362306a36Sopenharmony_ci /* TODO - extend divide ratio supported by newer SoCs */ 24462306a36Sopenharmony_ci}; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic const struct sun4i_i2s_clk_div sun4i_i2s_mclk_div[] = { 24762306a36Sopenharmony_ci { .div = 1, .val = 0 }, 24862306a36Sopenharmony_ci { .div = 2, .val = 1 }, 24962306a36Sopenharmony_ci { .div = 4, .val = 2 }, 25062306a36Sopenharmony_ci { .div = 6, .val = 3 }, 25162306a36Sopenharmony_ci { .div = 8, .val = 4 }, 25262306a36Sopenharmony_ci { .div = 12, .val = 5 }, 25362306a36Sopenharmony_ci { .div = 16, .val = 6 }, 25462306a36Sopenharmony_ci { .div = 24, .val = 7 }, 25562306a36Sopenharmony_ci /* TODO - extend divide ratio supported by newer SoCs */ 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_cistatic const struct sun4i_i2s_clk_div sun8i_i2s_clk_div[] = { 25962306a36Sopenharmony_ci { .div = 1, .val = 1 }, 26062306a36Sopenharmony_ci { .div = 2, .val = 2 }, 26162306a36Sopenharmony_ci { .div = 4, .val = 3 }, 26262306a36Sopenharmony_ci { .div = 6, .val = 4 }, 26362306a36Sopenharmony_ci { .div = 8, .val = 5 }, 26462306a36Sopenharmony_ci { .div = 12, .val = 6 }, 26562306a36Sopenharmony_ci { .div = 16, .val = 7 }, 26662306a36Sopenharmony_ci { .div = 24, .val = 8 }, 26762306a36Sopenharmony_ci { .div = 32, .val = 9 }, 26862306a36Sopenharmony_ci { .div = 48, .val = 10 }, 26962306a36Sopenharmony_ci { .div = 64, .val = 11 }, 27062306a36Sopenharmony_ci { .div = 96, .val = 12 }, 27162306a36Sopenharmony_ci { .div = 128, .val = 13 }, 27262306a36Sopenharmony_ci { .div = 176, .val = 14 }, 27362306a36Sopenharmony_ci { .div = 192, .val = 15 }, 27462306a36Sopenharmony_ci}; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic unsigned long sun4i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return i2s->mclk_freq; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic unsigned long sun8i_i2s_get_bclk_parent_rate(const struct sun4i_i2s *i2s) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci return clk_get_rate(i2s->mod_clk); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic int sun4i_i2s_get_bclk_div(struct sun4i_i2s *i2s, 28762306a36Sopenharmony_ci unsigned long parent_rate, 28862306a36Sopenharmony_ci unsigned int sampling_rate, 28962306a36Sopenharmony_ci unsigned int channels, 29062306a36Sopenharmony_ci unsigned int word_size) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *dividers = i2s->variant->bclk_dividers; 29362306a36Sopenharmony_ci int div = parent_rate / sampling_rate / word_size / channels; 29462306a36Sopenharmony_ci int i; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci for (i = 0; i < i2s->variant->num_bclk_dividers; i++) { 29762306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *bdiv = ÷rs[i]; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (bdiv->div == div) 30062306a36Sopenharmony_ci return bdiv->val; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return -EINVAL; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic int sun4i_i2s_get_mclk_div(struct sun4i_i2s *i2s, 30762306a36Sopenharmony_ci unsigned long parent_rate, 30862306a36Sopenharmony_ci unsigned long mclk_rate) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *dividers = i2s->variant->mclk_dividers; 31162306a36Sopenharmony_ci int div = parent_rate / mclk_rate; 31262306a36Sopenharmony_ci int i; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci for (i = 0; i < i2s->variant->num_mclk_dividers; i++) { 31562306a36Sopenharmony_ci const struct sun4i_i2s_clk_div *mdiv = ÷rs[i]; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (mdiv->div == div) 31862306a36Sopenharmony_ci return mdiv->val; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_cistatic int sun4i_i2s_oversample_rates[] = { 128, 192, 256, 384, 512, 768 }; 32562306a36Sopenharmony_cistatic bool sun4i_i2s_oversample_is_valid(unsigned int oversample) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci int i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(sun4i_i2s_oversample_rates); i++) 33062306a36Sopenharmony_ci if (sun4i_i2s_oversample_rates[i] == oversample) 33162306a36Sopenharmony_ci return true; 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return false; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int sun4i_i2s_set_clk_rate(struct snd_soc_dai *dai, 33762306a36Sopenharmony_ci unsigned int rate, 33862306a36Sopenharmony_ci unsigned int slots, 33962306a36Sopenharmony_ci unsigned int slot_width) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 34262306a36Sopenharmony_ci unsigned int oversample_rate, clk_rate, bclk_parent_rate; 34362306a36Sopenharmony_ci int bclk_div, mclk_div; 34462306a36Sopenharmony_ci int ret; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci switch (rate) { 34762306a36Sopenharmony_ci case 176400: 34862306a36Sopenharmony_ci case 88200: 34962306a36Sopenharmony_ci case 44100: 35062306a36Sopenharmony_ci case 22050: 35162306a36Sopenharmony_ci case 11025: 35262306a36Sopenharmony_ci clk_rate = 22579200; 35362306a36Sopenharmony_ci break; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci case 192000: 35662306a36Sopenharmony_ci case 128000: 35762306a36Sopenharmony_ci case 96000: 35862306a36Sopenharmony_ci case 64000: 35962306a36Sopenharmony_ci case 48000: 36062306a36Sopenharmony_ci case 32000: 36162306a36Sopenharmony_ci case 24000: 36262306a36Sopenharmony_ci case 16000: 36362306a36Sopenharmony_ci case 12000: 36462306a36Sopenharmony_ci case 8000: 36562306a36Sopenharmony_ci clk_rate = 24576000; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci default: 36962306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported sample rate: %u\n", rate); 37062306a36Sopenharmony_ci return -EINVAL; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci ret = clk_set_rate(i2s->mod_clk, clk_rate); 37462306a36Sopenharmony_ci if (ret) 37562306a36Sopenharmony_ci return ret; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci oversample_rate = i2s->mclk_freq / rate; 37862306a36Sopenharmony_ci if (!sun4i_i2s_oversample_is_valid(oversample_rate)) { 37962306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported oversample rate: %d\n", 38062306a36Sopenharmony_ci oversample_rate); 38162306a36Sopenharmony_ci return -EINVAL; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci bclk_parent_rate = i2s->variant->get_bclk_parent_rate(i2s); 38562306a36Sopenharmony_ci bclk_div = sun4i_i2s_get_bclk_div(i2s, bclk_parent_rate, 38662306a36Sopenharmony_ci rate, slots, slot_width); 38762306a36Sopenharmony_ci if (bclk_div < 0) { 38862306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported BCLK divider: %d\n", bclk_div); 38962306a36Sopenharmony_ci return -EINVAL; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci mclk_div = sun4i_i2s_get_mclk_div(i2s, clk_rate, i2s->mclk_freq); 39362306a36Sopenharmony_ci if (mclk_div < 0) { 39462306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported MCLK divider: %d\n", mclk_div); 39562306a36Sopenharmony_ci return -EINVAL; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN4I_I2S_CLK_DIV_REG, 39962306a36Sopenharmony_ci SUN4I_I2S_CLK_DIV_BCLK(bclk_div) | 40062306a36Sopenharmony_ci SUN4I_I2S_CLK_DIV_MCLK(mclk_div)); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci regmap_field_write(i2s->field_clkdiv_mclk_en, 1); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci return 0; 40562306a36Sopenharmony_ci} 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic int sun4i_i2s_get_sr(unsigned int width) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci switch (width) { 41062306a36Sopenharmony_ci case 16: 41162306a36Sopenharmony_ci return 0; 41262306a36Sopenharmony_ci case 20: 41362306a36Sopenharmony_ci return 1; 41462306a36Sopenharmony_ci case 24: 41562306a36Sopenharmony_ci return 2; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return -EINVAL; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic int sun4i_i2s_get_wss(unsigned int width) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci switch (width) { 42462306a36Sopenharmony_ci case 16: 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci case 20: 42762306a36Sopenharmony_ci return 1; 42862306a36Sopenharmony_ci case 24: 42962306a36Sopenharmony_ci return 2; 43062306a36Sopenharmony_ci case 32: 43162306a36Sopenharmony_ci return 3; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return -EINVAL; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int sun8i_i2s_get_sr_wss(unsigned int width) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci switch (width) { 44062306a36Sopenharmony_ci case 8: 44162306a36Sopenharmony_ci return 1; 44262306a36Sopenharmony_ci case 12: 44362306a36Sopenharmony_ci return 2; 44462306a36Sopenharmony_ci case 16: 44562306a36Sopenharmony_ci return 3; 44662306a36Sopenharmony_ci case 20: 44762306a36Sopenharmony_ci return 4; 44862306a36Sopenharmony_ci case 24: 44962306a36Sopenharmony_ci return 5; 45062306a36Sopenharmony_ci case 28: 45162306a36Sopenharmony_ci return 6; 45262306a36Sopenharmony_ci case 32: 45362306a36Sopenharmony_ci return 7; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return -EINVAL; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int sun4i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, 46062306a36Sopenharmony_ci unsigned int channels, unsigned int slots, 46162306a36Sopenharmony_ci unsigned int slot_width) 46262306a36Sopenharmony_ci{ 46362306a36Sopenharmony_ci /* Map the channels for playback and capture */ 46462306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210); 46562306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210); 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Configure the channels */ 46862306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_TX_CHAN_SEL_REG, 46962306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL_MASK, 47062306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL(channels)); 47162306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_RX_CHAN_SEL_REG, 47262306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL_MASK, 47362306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL(channels)); 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return 0; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic int sun8i_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, 47962306a36Sopenharmony_ci unsigned int channels, unsigned int slots, 48062306a36Sopenharmony_ci unsigned int slot_width) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci unsigned int lrck_period; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Map the channels for playback and capture */ 48562306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN8I_I2S_TX_CHAN_MAP_REG, 0x76543210); 48662306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN8I_I2S_RX_CHAN_MAP_REG, 0x76543210); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci /* Configure the channels */ 48962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, 49062306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL_MASK, 49162306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL(channels)); 49262306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, 49362306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL_MASK, 49462306a36Sopenharmony_ci SUN4I_I2S_CHAN_SEL(channels)); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 49762306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, 49862306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); 49962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 50062306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, 50162306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { 50462306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 50562306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 50662306a36Sopenharmony_ci lrck_period = slot_width * slots; 50762306a36Sopenharmony_ci break; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 51062306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 51162306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 51262306a36Sopenharmony_ci lrck_period = slot_width; 51362306a36Sopenharmony_ci break; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci default: 51662306a36Sopenharmony_ci return -EINVAL; 51762306a36Sopenharmony_ci } 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 52062306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, 52162306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, 52462306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_EN_MASK, 52562306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_EN(channels)); 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci return 0; 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic int sun50i_h6_i2s_set_chan_cfg(const struct sun4i_i2s *i2s, 53162306a36Sopenharmony_ci unsigned int channels, unsigned int slots, 53262306a36Sopenharmony_ci unsigned int slot_width) 53362306a36Sopenharmony_ci{ 53462306a36Sopenharmony_ci unsigned int lrck_period; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Map the channels for playback and capture */ 53762306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0xFEDCBA98); 53862306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x76543210); 53962306a36Sopenharmony_ci if (i2s->variant->num_din_pins > 1) { 54062306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP0_REG, 0x0F0E0D0C); 54162306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP1_REG, 0x0B0A0908); 54262306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP2_REG, 0x07060504); 54362306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 0x03020100); 54462306a36Sopenharmony_ci } else { 54562306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0xFEDCBA98); 54662306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x76543210); 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* Configure the channels */ 55062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 55162306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_MASK, 55262306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL(channels)); 55362306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, 55462306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_MASK, 55562306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL(channels)); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 55862306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM_MASK, 55962306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_TX_SLOT_NUM(channels)); 56062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_CHAN_CFG_REG, 56162306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM_MASK, 56262306a36Sopenharmony_ci SUN8I_I2S_CHAN_CFG_RX_SLOT_NUM(channels)); 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci switch (i2s->format & SND_SOC_DAIFMT_FORMAT_MASK) { 56562306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 56662306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 56762306a36Sopenharmony_ci lrck_period = slot_width * slots; 56862306a36Sopenharmony_ci break; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 57162306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 57262306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 57362306a36Sopenharmony_ci lrck_period = slot_width; 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci default: 57762306a36Sopenharmony_ci return -EINVAL; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 58162306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCK_PERIOD_MASK, 58262306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCK_PERIOD(lrck_period)); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 58562306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_EN_MASK, 58662306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_EN(channels)); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci return 0; 58962306a36Sopenharmony_ci} 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_cistatic int sun4i_i2s_hw_params(struct snd_pcm_substream *substream, 59262306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 59362306a36Sopenharmony_ci struct snd_soc_dai *dai) 59462306a36Sopenharmony_ci{ 59562306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 59662306a36Sopenharmony_ci unsigned int word_size = params_width(params); 59762306a36Sopenharmony_ci unsigned int slot_width = params_physical_width(params); 59862306a36Sopenharmony_ci unsigned int channels = params_channels(params); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci unsigned int slots = channels; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci int ret, sr, wss; 60362306a36Sopenharmony_ci u32 width; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci if (i2s->slots) 60662306a36Sopenharmony_ci slots = i2s->slots; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (i2s->slot_width) 60962306a36Sopenharmony_ci slot_width = i2s->slot_width; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci ret = i2s->variant->set_chan_cfg(i2s, channels, slots, slot_width); 61262306a36Sopenharmony_ci if (ret < 0) { 61362306a36Sopenharmony_ci dev_err(dai->dev, "Invalid channel configuration\n"); 61462306a36Sopenharmony_ci return ret; 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci /* Set significant bits in our FIFOs */ 61862306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, 61962306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_TX_MODE_MASK | 62062306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_RX_MODE_MASK, 62162306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_TX_MODE(1) | 62262306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_RX_MODE(1)); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci switch (params_physical_width(params)) { 62562306a36Sopenharmony_ci case 16: 62662306a36Sopenharmony_ci width = DMA_SLAVE_BUSWIDTH_2_BYTES; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case 32: 62962306a36Sopenharmony_ci width = DMA_SLAVE_BUSWIDTH_4_BYTES; 63062306a36Sopenharmony_ci break; 63162306a36Sopenharmony_ci default: 63262306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported physical sample width: %d\n", 63362306a36Sopenharmony_ci params_physical_width(params)); 63462306a36Sopenharmony_ci return -EINVAL; 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci i2s->playback_dma_data.addr_width = width; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci sr = i2s->variant->get_sr(word_size); 63962306a36Sopenharmony_ci if (sr < 0) 64062306a36Sopenharmony_ci return -EINVAL; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci wss = i2s->variant->get_wss(slot_width); 64362306a36Sopenharmony_ci if (wss < 0) 64462306a36Sopenharmony_ci return -EINVAL; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci regmap_field_write(i2s->field_fmt_wss, wss); 64762306a36Sopenharmony_ci regmap_field_write(i2s->field_fmt_sr, sr); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return sun4i_i2s_set_clk_rate(dai, params_rate(params), 65062306a36Sopenharmony_ci slots, slot_width); 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_cistatic int sun4i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, 65462306a36Sopenharmony_ci unsigned int fmt) 65562306a36Sopenharmony_ci{ 65662306a36Sopenharmony_ci u32 val; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci /* DAI clock polarity */ 65962306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 66062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 66162306a36Sopenharmony_ci /* Invert both clocks */ 66262306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED | 66362306a36Sopenharmony_ci SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 66662306a36Sopenharmony_ci /* Invert bit clock */ 66762306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_BCLK_POLARITY_INVERTED; 66862306a36Sopenharmony_ci break; 66962306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 67062306a36Sopenharmony_ci /* Invert frame clock */ 67162306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 67462306a36Sopenharmony_ci val = 0; 67562306a36Sopenharmony_ci break; 67662306a36Sopenharmony_ci default: 67762306a36Sopenharmony_ci return -EINVAL; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 68162306a36Sopenharmony_ci SUN4I_I2S_FMT0_LRCLK_POLARITY_MASK | 68262306a36Sopenharmony_ci SUN4I_I2S_FMT0_BCLK_POLARITY_MASK, 68362306a36Sopenharmony_ci val); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* DAI Mode */ 68662306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 68762306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 68862306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_FMT_I2S; 68962306a36Sopenharmony_ci break; 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 69262306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_FMT_LEFT_J; 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 69662306a36Sopenharmony_ci val = SUN4I_I2S_FMT0_FMT_RIGHT_J; 69762306a36Sopenharmony_ci break; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci default: 70062306a36Sopenharmony_ci return -EINVAL; 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 70462306a36Sopenharmony_ci SUN4I_I2S_FMT0_FMT_MASK, val); 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* DAI clock master masks */ 70762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 70862306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 70962306a36Sopenharmony_ci /* BCLK and LRCLK master */ 71062306a36Sopenharmony_ci val = SUN4I_I2S_CTRL_MODE_MASTER; 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 71462306a36Sopenharmony_ci /* BCLK and LRCLK slave */ 71562306a36Sopenharmony_ci val = SUN4I_I2S_CTRL_MODE_SLAVE; 71662306a36Sopenharmony_ci break; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci default: 71962306a36Sopenharmony_ci return -EINVAL; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 72262306a36Sopenharmony_ci SUN4I_I2S_CTRL_MODE_MASK, val); 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci return 0; 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_cistatic int sun8i_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, 72862306a36Sopenharmony_ci unsigned int fmt) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci u32 mode, val; 73162306a36Sopenharmony_ci u8 offset; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci /* 73462306a36Sopenharmony_ci * DAI clock polarity 73562306a36Sopenharmony_ci * 73662306a36Sopenharmony_ci * The setup for LRCK contradicts the datasheet, but under a 73762306a36Sopenharmony_ci * scope it's clear that the LRCK polarity is reversed 73862306a36Sopenharmony_ci * compared to the expected polarity on the bus. 73962306a36Sopenharmony_ci */ 74062306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 74162306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 74262306a36Sopenharmony_ci /* Invert both clocks */ 74362306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 74662306a36Sopenharmony_ci /* Invert bit clock */ 74762306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | 74862306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 74962306a36Sopenharmony_ci break; 75062306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 75162306a36Sopenharmony_ci /* Invert frame clock */ 75262306a36Sopenharmony_ci val = 0; 75362306a36Sopenharmony_ci break; 75462306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 75562306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci default: 75862306a36Sopenharmony_ci return -EINVAL; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 76262306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | 76362306a36Sopenharmony_ci SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, 76462306a36Sopenharmony_ci val); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* DAI Mode */ 76762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 76862306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 76962306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_PCM; 77062306a36Sopenharmony_ci offset = 1; 77162306a36Sopenharmony_ci break; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 77462306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_PCM; 77562306a36Sopenharmony_ci offset = 0; 77662306a36Sopenharmony_ci break; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 77962306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_LEFT; 78062306a36Sopenharmony_ci offset = 1; 78162306a36Sopenharmony_ci break; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 78462306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_LEFT; 78562306a36Sopenharmony_ci offset = 0; 78662306a36Sopenharmony_ci break; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 78962306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_RIGHT; 79062306a36Sopenharmony_ci offset = 0; 79162306a36Sopenharmony_ci break; 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci default: 79462306a36Sopenharmony_ci return -EINVAL; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 79862306a36Sopenharmony_ci SUN8I_I2S_CTRL_MODE_MASK, mode); 79962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, 80062306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_OFFSET_MASK, 80162306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_OFFSET(offset)); 80262306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_RX_CHAN_SEL_REG, 80362306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_OFFSET_MASK, 80462306a36Sopenharmony_ci SUN8I_I2S_TX_CHAN_OFFSET(offset)); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* DAI clock master masks */ 80762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 80862306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 80962306a36Sopenharmony_ci /* BCLK and LRCLK master */ 81062306a36Sopenharmony_ci val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 81462306a36Sopenharmony_ci /* BCLK and LRCLK slave */ 81562306a36Sopenharmony_ci val = 0; 81662306a36Sopenharmony_ci break; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci default: 81962306a36Sopenharmony_ci return -EINVAL; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 82362306a36Sopenharmony_ci SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, 82462306a36Sopenharmony_ci val); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* Set sign extension to pad out LSB with 0 */ 82762306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, 82862306a36Sopenharmony_ci SUN8I_I2S_FMT1_REG_SEXT_MASK, 82962306a36Sopenharmony_ci SUN8I_I2S_FMT1_REG_SEXT(0)); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return 0; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int sun50i_h6_i2s_set_soc_fmt(const struct sun4i_i2s *i2s, 83562306a36Sopenharmony_ci unsigned int fmt) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci u32 mode, val; 83862306a36Sopenharmony_ci u8 offset; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* 84162306a36Sopenharmony_ci * DAI clock polarity 84262306a36Sopenharmony_ci * 84362306a36Sopenharmony_ci * The setup for LRCK contradicts the datasheet, but under a 84462306a36Sopenharmony_ci * scope it's clear that the LRCK polarity is reversed 84562306a36Sopenharmony_ci * compared to the expected polarity on the bus. 84662306a36Sopenharmony_ci */ 84762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 84862306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 84962306a36Sopenharmony_ci /* Invert both clocks */ 85062306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED; 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 85362306a36Sopenharmony_ci /* Invert bit clock */ 85462306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_BCLK_POLARITY_INVERTED | 85562306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 85662306a36Sopenharmony_ci break; 85762306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 85862306a36Sopenharmony_ci /* Invert frame clock */ 85962306a36Sopenharmony_ci val = 0; 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 86262306a36Sopenharmony_ci val = SUN8I_I2S_FMT0_LRCLK_POLARITY_INVERTED; 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci default: 86562306a36Sopenharmony_ci return -EINVAL; 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT0_REG, 86962306a36Sopenharmony_ci SUN8I_I2S_FMT0_LRCLK_POLARITY_MASK | 87062306a36Sopenharmony_ci SUN8I_I2S_FMT0_BCLK_POLARITY_MASK, 87162306a36Sopenharmony_ci val); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci /* DAI Mode */ 87462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 87562306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 87662306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_PCM; 87762306a36Sopenharmony_ci offset = 1; 87862306a36Sopenharmony_ci break; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 88162306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_PCM; 88262306a36Sopenharmony_ci offset = 0; 88362306a36Sopenharmony_ci break; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 88662306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_LEFT; 88762306a36Sopenharmony_ci offset = 1; 88862306a36Sopenharmony_ci break; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 89162306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_LEFT; 89262306a36Sopenharmony_ci offset = 0; 89362306a36Sopenharmony_ci break; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 89662306a36Sopenharmony_ci mode = SUN8I_I2S_CTRL_MODE_RIGHT; 89762306a36Sopenharmony_ci offset = 0; 89862306a36Sopenharmony_ci break; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci default: 90162306a36Sopenharmony_ci return -EINVAL; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 90562306a36Sopenharmony_ci SUN8I_I2S_CTRL_MODE_MASK, mode); 90662306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN8I_I2S_TX_CHAN_SEL_REG, 90762306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, 90862306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); 90962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN50I_H6_I2S_RX_CHAN_SEL_REG, 91062306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET_MASK, 91162306a36Sopenharmony_ci SUN50I_H6_I2S_TX_CHAN_SEL_OFFSET(offset)); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci /* DAI clock master masks */ 91462306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 91562306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 91662306a36Sopenharmony_ci /* BCLK and LRCLK master */ 91762306a36Sopenharmony_ci val = SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 92162306a36Sopenharmony_ci /* BCLK and LRCLK slave */ 92262306a36Sopenharmony_ci val = 0; 92362306a36Sopenharmony_ci break; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci default: 92662306a36Sopenharmony_ci return -EINVAL; 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 93062306a36Sopenharmony_ci SUN8I_I2S_CTRL_BCLK_OUT | SUN8I_I2S_CTRL_LRCK_OUT, 93162306a36Sopenharmony_ci val); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci /* Set sign extension to pad out LSB with 0 */ 93462306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FMT1_REG, 93562306a36Sopenharmony_ci SUN8I_I2S_FMT1_REG_SEXT_MASK, 93662306a36Sopenharmony_ci SUN8I_I2S_FMT1_REG_SEXT(0)); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return 0; 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int sun4i_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 94262306a36Sopenharmony_ci{ 94362306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 94462306a36Sopenharmony_ci int ret; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci ret = i2s->variant->set_fmt(i2s, fmt); 94762306a36Sopenharmony_ci if (ret) { 94862306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported format configuration\n"); 94962306a36Sopenharmony_ci return ret; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci i2s->format = fmt; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci return 0; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic void sun4i_i2s_start_capture(struct sun4i_i2s *i2s) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci /* Flush RX FIFO */ 96062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, 96162306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_FLUSH_RX, 96262306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_FLUSH_RX); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Clear RX counter */ 96562306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN4I_I2S_RX_CNT_REG, 0); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* Enable RX Block */ 96862306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 96962306a36Sopenharmony_ci SUN4I_I2S_CTRL_RX_EN, 97062306a36Sopenharmony_ci SUN4I_I2S_CTRL_RX_EN); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci /* Enable RX DRQ */ 97362306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, 97462306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, 97562306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN); 97662306a36Sopenharmony_ci} 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_cistatic void sun4i_i2s_start_playback(struct sun4i_i2s *i2s) 97962306a36Sopenharmony_ci{ 98062306a36Sopenharmony_ci /* Flush TX FIFO */ 98162306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_FIFO_CTRL_REG, 98262306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_FLUSH_TX, 98362306a36Sopenharmony_ci SUN4I_I2S_FIFO_CTRL_FLUSH_TX); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Clear TX counter */ 98662306a36Sopenharmony_ci regmap_write(i2s->regmap, SUN4I_I2S_TX_CNT_REG, 0); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* Enable TX Block */ 98962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 99062306a36Sopenharmony_ci SUN4I_I2S_CTRL_TX_EN, 99162306a36Sopenharmony_ci SUN4I_I2S_CTRL_TX_EN); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Enable TX DRQ */ 99462306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, 99562306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, 99662306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic void sun4i_i2s_stop_capture(struct sun4i_i2s *i2s) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci /* Disable RX Block */ 100262306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 100362306a36Sopenharmony_ci SUN4I_I2S_CTRL_RX_EN, 100462306a36Sopenharmony_ci 0); 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci /* Disable RX DRQ */ 100762306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, 100862306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_RX_DRQ_EN, 100962306a36Sopenharmony_ci 0); 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic void sun4i_i2s_stop_playback(struct sun4i_i2s *i2s) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci /* Disable TX Block */ 101562306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 101662306a36Sopenharmony_ci SUN4I_I2S_CTRL_TX_EN, 101762306a36Sopenharmony_ci 0); 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Disable TX DRQ */ 102062306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_DMA_INT_CTRL_REG, 102162306a36Sopenharmony_ci SUN4I_I2S_DMA_INT_CTRL_TX_DRQ_EN, 102262306a36Sopenharmony_ci 0); 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic int sun4i_i2s_trigger(struct snd_pcm_substream *substream, int cmd, 102662306a36Sopenharmony_ci struct snd_soc_dai *dai) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci switch (cmd) { 103162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 103262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 103362306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 103462306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 103562306a36Sopenharmony_ci sun4i_i2s_start_playback(i2s); 103662306a36Sopenharmony_ci else 103762306a36Sopenharmony_ci sun4i_i2s_start_capture(i2s); 103862306a36Sopenharmony_ci break; 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 104162306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 104262306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 104362306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 104462306a36Sopenharmony_ci sun4i_i2s_stop_playback(i2s); 104562306a36Sopenharmony_ci else 104662306a36Sopenharmony_ci sun4i_i2s_stop_capture(i2s); 104762306a36Sopenharmony_ci break; 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci default: 105062306a36Sopenharmony_ci return -EINVAL; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci return 0; 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic int sun4i_i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, 105762306a36Sopenharmony_ci unsigned int freq, int dir) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (clk_id != 0) 106262306a36Sopenharmony_ci return -EINVAL; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci i2s->mclk_freq = freq; 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return 0; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_cistatic int sun4i_i2s_set_tdm_slot(struct snd_soc_dai *dai, 107062306a36Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 107162306a36Sopenharmony_ci int slots, int slot_width) 107262306a36Sopenharmony_ci{ 107362306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if (slots > 8) 107662306a36Sopenharmony_ci return -EINVAL; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci i2s->slots = slots; 107962306a36Sopenharmony_ci i2s->slot_width = slot_width; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci return 0; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic int sun4i_i2s_dai_probe(struct snd_soc_dai *dai) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci struct sun4i_i2s *i2s = snd_soc_dai_get_drvdata(dai); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci snd_soc_dai_init_dma_data(dai, 108962306a36Sopenharmony_ci &i2s->playback_dma_data, 109062306a36Sopenharmony_ci &i2s->capture_dma_data); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci return 0; 109362306a36Sopenharmony_ci} 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic const struct snd_soc_dai_ops sun4i_i2s_dai_ops = { 109662306a36Sopenharmony_ci .probe = sun4i_i2s_dai_probe, 109762306a36Sopenharmony_ci .hw_params = sun4i_i2s_hw_params, 109862306a36Sopenharmony_ci .set_fmt = sun4i_i2s_set_fmt, 109962306a36Sopenharmony_ci .set_sysclk = sun4i_i2s_set_sysclk, 110062306a36Sopenharmony_ci .set_tdm_slot = sun4i_i2s_set_tdm_slot, 110162306a36Sopenharmony_ci .trigger = sun4i_i2s_trigger, 110262306a36Sopenharmony_ci}; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci#define SUN4I_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 110562306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_LE | \ 110662306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE) 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_cistatic struct snd_soc_dai_driver sun4i_i2s_dai = { 110962306a36Sopenharmony_ci .capture = { 111062306a36Sopenharmony_ci .stream_name = "Capture", 111162306a36Sopenharmony_ci .channels_min = 1, 111262306a36Sopenharmony_ci .channels_max = 8, 111362306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 111462306a36Sopenharmony_ci .formats = SUN4I_FORMATS, 111562306a36Sopenharmony_ci }, 111662306a36Sopenharmony_ci .playback = { 111762306a36Sopenharmony_ci .stream_name = "Playback", 111862306a36Sopenharmony_ci .channels_min = 1, 111962306a36Sopenharmony_ci .channels_max = 8, 112062306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 112162306a36Sopenharmony_ci .formats = SUN4I_FORMATS, 112262306a36Sopenharmony_ci }, 112362306a36Sopenharmony_ci .ops = &sun4i_i2s_dai_ops, 112462306a36Sopenharmony_ci .symmetric_rate = 1, 112562306a36Sopenharmony_ci}; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_cistatic const struct snd_soc_component_driver sun4i_i2s_component = { 112862306a36Sopenharmony_ci .name = "sun4i-dai", 112962306a36Sopenharmony_ci .legacy_dai_naming = 1, 113062306a36Sopenharmony_ci}; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic bool sun4i_i2s_rd_reg(struct device *dev, unsigned int reg) 113362306a36Sopenharmony_ci{ 113462306a36Sopenharmony_ci switch (reg) { 113562306a36Sopenharmony_ci case SUN4I_I2S_FIFO_TX_REG: 113662306a36Sopenharmony_ci return false; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci default: 113962306a36Sopenharmony_ci return true; 114062306a36Sopenharmony_ci } 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic bool sun4i_i2s_wr_reg(struct device *dev, unsigned int reg) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci switch (reg) { 114662306a36Sopenharmony_ci case SUN4I_I2S_FIFO_RX_REG: 114762306a36Sopenharmony_ci case SUN4I_I2S_FIFO_STA_REG: 114862306a36Sopenharmony_ci return false; 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_ci default: 115162306a36Sopenharmony_ci return true; 115262306a36Sopenharmony_ci } 115362306a36Sopenharmony_ci} 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_cistatic bool sun4i_i2s_volatile_reg(struct device *dev, unsigned int reg) 115662306a36Sopenharmony_ci{ 115762306a36Sopenharmony_ci switch (reg) { 115862306a36Sopenharmony_ci case SUN4I_I2S_FIFO_RX_REG: 115962306a36Sopenharmony_ci case SUN4I_I2S_INT_STA_REG: 116062306a36Sopenharmony_ci case SUN4I_I2S_RX_CNT_REG: 116162306a36Sopenharmony_ci case SUN4I_I2S_TX_CNT_REG: 116262306a36Sopenharmony_ci return true; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci default: 116562306a36Sopenharmony_ci return false; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cistatic bool sun8i_i2s_rd_reg(struct device *dev, unsigned int reg) 117062306a36Sopenharmony_ci{ 117162306a36Sopenharmony_ci switch (reg) { 117262306a36Sopenharmony_ci case SUN8I_I2S_FIFO_TX_REG: 117362306a36Sopenharmony_ci return false; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci default: 117662306a36Sopenharmony_ci return true; 117762306a36Sopenharmony_ci } 117862306a36Sopenharmony_ci} 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_cistatic bool sun8i_i2s_volatile_reg(struct device *dev, unsigned int reg) 118162306a36Sopenharmony_ci{ 118262306a36Sopenharmony_ci switch (reg) { 118362306a36Sopenharmony_ci case SUN4I_I2S_FIFO_CTRL_REG: 118462306a36Sopenharmony_ci case SUN4I_I2S_FIFO_RX_REG: 118562306a36Sopenharmony_ci case SUN4I_I2S_FIFO_STA_REG: 118662306a36Sopenharmony_ci case SUN4I_I2S_RX_CNT_REG: 118762306a36Sopenharmony_ci case SUN4I_I2S_TX_CNT_REG: 118862306a36Sopenharmony_ci case SUN8I_I2S_FIFO_TX_REG: 118962306a36Sopenharmony_ci case SUN8I_I2S_INT_STA_REG: 119062306a36Sopenharmony_ci return true; 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci default: 119362306a36Sopenharmony_ci return false; 119462306a36Sopenharmony_ci } 119562306a36Sopenharmony_ci} 119662306a36Sopenharmony_ci 119762306a36Sopenharmony_cistatic const struct reg_default sun4i_i2s_reg_defaults[] = { 119862306a36Sopenharmony_ci { SUN4I_I2S_CTRL_REG, 0x00000000 }, 119962306a36Sopenharmony_ci { SUN4I_I2S_FMT0_REG, 0x0000000c }, 120062306a36Sopenharmony_ci { SUN4I_I2S_FMT1_REG, 0x00004020 }, 120162306a36Sopenharmony_ci { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, 120262306a36Sopenharmony_ci { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, 120362306a36Sopenharmony_ci { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, 120462306a36Sopenharmony_ci { SUN4I_I2S_TX_CHAN_SEL_REG, 0x00000001 }, 120562306a36Sopenharmony_ci { SUN4I_I2S_TX_CHAN_MAP_REG, 0x76543210 }, 120662306a36Sopenharmony_ci { SUN4I_I2S_RX_CHAN_SEL_REG, 0x00000001 }, 120762306a36Sopenharmony_ci { SUN4I_I2S_RX_CHAN_MAP_REG, 0x00003210 }, 120862306a36Sopenharmony_ci}; 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic const struct reg_default sun8i_i2s_reg_defaults[] = { 121162306a36Sopenharmony_ci { SUN4I_I2S_CTRL_REG, 0x00060000 }, 121262306a36Sopenharmony_ci { SUN4I_I2S_FMT0_REG, 0x00000033 }, 121362306a36Sopenharmony_ci { SUN4I_I2S_FMT1_REG, 0x00000030 }, 121462306a36Sopenharmony_ci { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, 121562306a36Sopenharmony_ci { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, 121662306a36Sopenharmony_ci { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, 121762306a36Sopenharmony_ci { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, 121862306a36Sopenharmony_ci { SUN8I_I2S_TX_CHAN_SEL_REG, 0x00000000 }, 121962306a36Sopenharmony_ci { SUN8I_I2S_TX_CHAN_MAP_REG, 0x00000000 }, 122062306a36Sopenharmony_ci { SUN8I_I2S_RX_CHAN_SEL_REG, 0x00000000 }, 122162306a36Sopenharmony_ci { SUN8I_I2S_RX_CHAN_MAP_REG, 0x00000000 }, 122262306a36Sopenharmony_ci}; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_cistatic const struct reg_default sun50i_h6_i2s_reg_defaults[] = { 122562306a36Sopenharmony_ci { SUN4I_I2S_CTRL_REG, 0x00060000 }, 122662306a36Sopenharmony_ci { SUN4I_I2S_FMT0_REG, 0x00000033 }, 122762306a36Sopenharmony_ci { SUN4I_I2S_FMT1_REG, 0x00000030 }, 122862306a36Sopenharmony_ci { SUN4I_I2S_FIFO_CTRL_REG, 0x000400f0 }, 122962306a36Sopenharmony_ci { SUN4I_I2S_DMA_INT_CTRL_REG, 0x00000000 }, 123062306a36Sopenharmony_ci { SUN4I_I2S_CLK_DIV_REG, 0x00000000 }, 123162306a36Sopenharmony_ci { SUN8I_I2S_CHAN_CFG_REG, 0x00000000 }, 123262306a36Sopenharmony_ci { SUN50I_H6_I2S_TX_CHAN_SEL_REG(0), 0x00000000 }, 123362306a36Sopenharmony_ci { SUN50I_H6_I2S_TX_CHAN_MAP0_REG(0), 0x00000000 }, 123462306a36Sopenharmony_ci { SUN50I_H6_I2S_TX_CHAN_MAP1_REG(0), 0x00000000 }, 123562306a36Sopenharmony_ci { SUN50I_H6_I2S_RX_CHAN_SEL_REG, 0x00000000 }, 123662306a36Sopenharmony_ci { SUN50I_H6_I2S_RX_CHAN_MAP0_REG, 0x00000000 }, 123762306a36Sopenharmony_ci { SUN50I_H6_I2S_RX_CHAN_MAP1_REG, 0x00000000 }, 123862306a36Sopenharmony_ci}; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_cistatic const struct regmap_config sun4i_i2s_regmap_config = { 124162306a36Sopenharmony_ci .reg_bits = 32, 124262306a36Sopenharmony_ci .reg_stride = 4, 124362306a36Sopenharmony_ci .val_bits = 32, 124462306a36Sopenharmony_ci .max_register = SUN4I_I2S_RX_CHAN_MAP_REG, 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 124762306a36Sopenharmony_ci .reg_defaults = sun4i_i2s_reg_defaults, 124862306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(sun4i_i2s_reg_defaults), 124962306a36Sopenharmony_ci .writeable_reg = sun4i_i2s_wr_reg, 125062306a36Sopenharmony_ci .readable_reg = sun4i_i2s_rd_reg, 125162306a36Sopenharmony_ci .volatile_reg = sun4i_i2s_volatile_reg, 125262306a36Sopenharmony_ci}; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_cistatic const struct regmap_config sun8i_i2s_regmap_config = { 125562306a36Sopenharmony_ci .reg_bits = 32, 125662306a36Sopenharmony_ci .reg_stride = 4, 125762306a36Sopenharmony_ci .val_bits = 32, 125862306a36Sopenharmony_ci .max_register = SUN8I_I2S_RX_CHAN_MAP_REG, 125962306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 126062306a36Sopenharmony_ci .reg_defaults = sun8i_i2s_reg_defaults, 126162306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(sun8i_i2s_reg_defaults), 126262306a36Sopenharmony_ci .writeable_reg = sun4i_i2s_wr_reg, 126362306a36Sopenharmony_ci .readable_reg = sun8i_i2s_rd_reg, 126462306a36Sopenharmony_ci .volatile_reg = sun8i_i2s_volatile_reg, 126562306a36Sopenharmony_ci}; 126662306a36Sopenharmony_ci 126762306a36Sopenharmony_cistatic const struct regmap_config sun50i_h6_i2s_regmap_config = { 126862306a36Sopenharmony_ci .reg_bits = 32, 126962306a36Sopenharmony_ci .reg_stride = 4, 127062306a36Sopenharmony_ci .val_bits = 32, 127162306a36Sopenharmony_ci .max_register = SUN50I_R329_I2S_RX_CHAN_MAP3_REG, 127262306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 127362306a36Sopenharmony_ci .reg_defaults = sun50i_h6_i2s_reg_defaults, 127462306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(sun50i_h6_i2s_reg_defaults), 127562306a36Sopenharmony_ci .writeable_reg = sun4i_i2s_wr_reg, 127662306a36Sopenharmony_ci .readable_reg = sun8i_i2s_rd_reg, 127762306a36Sopenharmony_ci .volatile_reg = sun8i_i2s_volatile_reg, 127862306a36Sopenharmony_ci}; 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic int sun4i_i2s_runtime_resume(struct device *dev) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci struct sun4i_i2s *i2s = dev_get_drvdata(dev); 128362306a36Sopenharmony_ci int ret; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci ret = clk_prepare_enable(i2s->bus_clk); 128662306a36Sopenharmony_ci if (ret) { 128762306a36Sopenharmony_ci dev_err(dev, "Failed to enable bus clock\n"); 128862306a36Sopenharmony_ci return ret; 128962306a36Sopenharmony_ci } 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci regcache_cache_only(i2s->regmap, false); 129262306a36Sopenharmony_ci regcache_mark_dirty(i2s->regmap); 129362306a36Sopenharmony_ci 129462306a36Sopenharmony_ci ret = regcache_sync(i2s->regmap); 129562306a36Sopenharmony_ci if (ret) { 129662306a36Sopenharmony_ci dev_err(dev, "Failed to sync regmap cache\n"); 129762306a36Sopenharmony_ci goto err_disable_clk; 129862306a36Sopenharmony_ci } 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci /* Enable the whole hardware block */ 130162306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 130262306a36Sopenharmony_ci SUN4I_I2S_CTRL_GL_EN, SUN4I_I2S_CTRL_GL_EN); 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* Enable the first output line */ 130562306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 130662306a36Sopenharmony_ci SUN4I_I2S_CTRL_SDO_EN_MASK, 130762306a36Sopenharmony_ci SUN4I_I2S_CTRL_SDO_EN(0)); 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci ret = clk_prepare_enable(i2s->mod_clk); 131062306a36Sopenharmony_ci if (ret) { 131162306a36Sopenharmony_ci dev_err(dev, "Failed to enable module clock\n"); 131262306a36Sopenharmony_ci goto err_disable_clk; 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci return 0; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cierr_disable_clk: 131862306a36Sopenharmony_ci clk_disable_unprepare(i2s->bus_clk); 131962306a36Sopenharmony_ci return ret; 132062306a36Sopenharmony_ci} 132162306a36Sopenharmony_ci 132262306a36Sopenharmony_cistatic int sun4i_i2s_runtime_suspend(struct device *dev) 132362306a36Sopenharmony_ci{ 132462306a36Sopenharmony_ci struct sun4i_i2s *i2s = dev_get_drvdata(dev); 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci clk_disable_unprepare(i2s->mod_clk); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci /* Disable our output lines */ 132962306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 133062306a36Sopenharmony_ci SUN4I_I2S_CTRL_SDO_EN_MASK, 0); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Disable the whole hardware block */ 133362306a36Sopenharmony_ci regmap_update_bits(i2s->regmap, SUN4I_I2S_CTRL_REG, 133462306a36Sopenharmony_ci SUN4I_I2S_CTRL_GL_EN, 0); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci regcache_cache_only(i2s->regmap, true); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci clk_disable_unprepare(i2s->bus_clk); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci return 0; 134162306a36Sopenharmony_ci} 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun4i_a10_i2s_quirks = { 134462306a36Sopenharmony_ci .has_reset = false, 134562306a36Sopenharmony_ci .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, 134662306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, 134762306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), 134862306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), 134962306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), 135062306a36Sopenharmony_ci .bclk_dividers = sun4i_i2s_bclk_div, 135162306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), 135262306a36Sopenharmony_ci .mclk_dividers = sun4i_i2s_mclk_div, 135362306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), 135462306a36Sopenharmony_ci .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, 135562306a36Sopenharmony_ci .get_sr = sun4i_i2s_get_sr, 135662306a36Sopenharmony_ci .get_wss = sun4i_i2s_get_wss, 135762306a36Sopenharmony_ci .set_chan_cfg = sun4i_i2s_set_chan_cfg, 135862306a36Sopenharmony_ci .set_fmt = sun4i_i2s_set_soc_fmt, 135962306a36Sopenharmony_ci}; 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun6i_a31_i2s_quirks = { 136262306a36Sopenharmony_ci .has_reset = true, 136362306a36Sopenharmony_ci .reg_offset_txdata = SUN4I_I2S_FIFO_TX_REG, 136462306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, 136562306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), 136662306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), 136762306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), 136862306a36Sopenharmony_ci .bclk_dividers = sun4i_i2s_bclk_div, 136962306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), 137062306a36Sopenharmony_ci .mclk_dividers = sun4i_i2s_mclk_div, 137162306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), 137262306a36Sopenharmony_ci .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, 137362306a36Sopenharmony_ci .get_sr = sun4i_i2s_get_sr, 137462306a36Sopenharmony_ci .get_wss = sun4i_i2s_get_wss, 137562306a36Sopenharmony_ci .set_chan_cfg = sun4i_i2s_set_chan_cfg, 137662306a36Sopenharmony_ci .set_fmt = sun4i_i2s_set_soc_fmt, 137762306a36Sopenharmony_ci}; 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci/* 138062306a36Sopenharmony_ci * This doesn't describe the TDM controller documented in the A83t 138162306a36Sopenharmony_ci * datasheet, but the three undocumented I2S controller that use the 138262306a36Sopenharmony_ci * older design. 138362306a36Sopenharmony_ci */ 138462306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun8i_a83t_i2s_quirks = { 138562306a36Sopenharmony_ci .has_reset = true, 138662306a36Sopenharmony_ci .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 138762306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, 138862306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), 138962306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), 139062306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), 139162306a36Sopenharmony_ci .bclk_dividers = sun4i_i2s_bclk_div, 139262306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), 139362306a36Sopenharmony_ci .mclk_dividers = sun4i_i2s_mclk_div, 139462306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), 139562306a36Sopenharmony_ci .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, 139662306a36Sopenharmony_ci .get_sr = sun4i_i2s_get_sr, 139762306a36Sopenharmony_ci .get_wss = sun4i_i2s_get_wss, 139862306a36Sopenharmony_ci .set_chan_cfg = sun4i_i2s_set_chan_cfg, 139962306a36Sopenharmony_ci .set_fmt = sun4i_i2s_set_soc_fmt, 140062306a36Sopenharmony_ci}; 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun8i_h3_i2s_quirks = { 140362306a36Sopenharmony_ci .has_reset = true, 140462306a36Sopenharmony_ci .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 140562306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun8i_i2s_regmap_config, 140662306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), 140762306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), 140862306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), 140962306a36Sopenharmony_ci .bclk_dividers = sun8i_i2s_clk_div, 141062306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 141162306a36Sopenharmony_ci .mclk_dividers = sun8i_i2s_clk_div, 141262306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 141362306a36Sopenharmony_ci .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, 141462306a36Sopenharmony_ci .get_sr = sun8i_i2s_get_sr_wss, 141562306a36Sopenharmony_ci .get_wss = sun8i_i2s_get_sr_wss, 141662306a36Sopenharmony_ci .set_chan_cfg = sun8i_i2s_set_chan_cfg, 141762306a36Sopenharmony_ci .set_fmt = sun8i_i2s_set_soc_fmt, 141862306a36Sopenharmony_ci}; 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun50i_a64_codec_i2s_quirks = { 142162306a36Sopenharmony_ci .has_reset = true, 142262306a36Sopenharmony_ci .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 142362306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun4i_i2s_regmap_config, 142462306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 7, 7), 142562306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 2, 3), 142662306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 5), 142762306a36Sopenharmony_ci .bclk_dividers = sun4i_i2s_bclk_div, 142862306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun4i_i2s_bclk_div), 142962306a36Sopenharmony_ci .mclk_dividers = sun4i_i2s_mclk_div, 143062306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun4i_i2s_mclk_div), 143162306a36Sopenharmony_ci .get_bclk_parent_rate = sun4i_i2s_get_bclk_parent_rate, 143262306a36Sopenharmony_ci .get_sr = sun4i_i2s_get_sr, 143362306a36Sopenharmony_ci .get_wss = sun4i_i2s_get_wss, 143462306a36Sopenharmony_ci .set_chan_cfg = sun4i_i2s_set_chan_cfg, 143562306a36Sopenharmony_ci .set_fmt = sun4i_i2s_set_soc_fmt, 143662306a36Sopenharmony_ci}; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun50i_h6_i2s_quirks = { 143962306a36Sopenharmony_ci .has_reset = true, 144062306a36Sopenharmony_ci .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 144162306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, 144262306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), 144362306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), 144462306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), 144562306a36Sopenharmony_ci .bclk_dividers = sun8i_i2s_clk_div, 144662306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 144762306a36Sopenharmony_ci .mclk_dividers = sun8i_i2s_clk_div, 144862306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 144962306a36Sopenharmony_ci .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, 145062306a36Sopenharmony_ci .get_sr = sun8i_i2s_get_sr_wss, 145162306a36Sopenharmony_ci .get_wss = sun8i_i2s_get_sr_wss, 145262306a36Sopenharmony_ci .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg, 145362306a36Sopenharmony_ci .set_fmt = sun50i_h6_i2s_set_soc_fmt, 145462306a36Sopenharmony_ci}; 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_cistatic const struct sun4i_i2s_quirks sun50i_r329_i2s_quirks = { 145762306a36Sopenharmony_ci .has_reset = true, 145862306a36Sopenharmony_ci .reg_offset_txdata = SUN8I_I2S_FIFO_TX_REG, 145962306a36Sopenharmony_ci .sun4i_i2s_regmap = &sun50i_h6_i2s_regmap_config, 146062306a36Sopenharmony_ci .field_clkdiv_mclk_en = REG_FIELD(SUN4I_I2S_CLK_DIV_REG, 8, 8), 146162306a36Sopenharmony_ci .field_fmt_wss = REG_FIELD(SUN4I_I2S_FMT0_REG, 0, 2), 146262306a36Sopenharmony_ci .field_fmt_sr = REG_FIELD(SUN4I_I2S_FMT0_REG, 4, 6), 146362306a36Sopenharmony_ci .num_din_pins = 4, 146462306a36Sopenharmony_ci .num_dout_pins = 4, 146562306a36Sopenharmony_ci .bclk_dividers = sun8i_i2s_clk_div, 146662306a36Sopenharmony_ci .num_bclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 146762306a36Sopenharmony_ci .mclk_dividers = sun8i_i2s_clk_div, 146862306a36Sopenharmony_ci .num_mclk_dividers = ARRAY_SIZE(sun8i_i2s_clk_div), 146962306a36Sopenharmony_ci .get_bclk_parent_rate = sun8i_i2s_get_bclk_parent_rate, 147062306a36Sopenharmony_ci .get_sr = sun8i_i2s_get_sr_wss, 147162306a36Sopenharmony_ci .get_wss = sun8i_i2s_get_sr_wss, 147262306a36Sopenharmony_ci .set_chan_cfg = sun50i_h6_i2s_set_chan_cfg, 147362306a36Sopenharmony_ci .set_fmt = sun50i_h6_i2s_set_soc_fmt, 147462306a36Sopenharmony_ci}; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cistatic int sun4i_i2s_init_regmap_fields(struct device *dev, 147762306a36Sopenharmony_ci struct sun4i_i2s *i2s) 147862306a36Sopenharmony_ci{ 147962306a36Sopenharmony_ci i2s->field_clkdiv_mclk_en = 148062306a36Sopenharmony_ci devm_regmap_field_alloc(dev, i2s->regmap, 148162306a36Sopenharmony_ci i2s->variant->field_clkdiv_mclk_en); 148262306a36Sopenharmony_ci if (IS_ERR(i2s->field_clkdiv_mclk_en)) 148362306a36Sopenharmony_ci return PTR_ERR(i2s->field_clkdiv_mclk_en); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci i2s->field_fmt_wss = 148662306a36Sopenharmony_ci devm_regmap_field_alloc(dev, i2s->regmap, 148762306a36Sopenharmony_ci i2s->variant->field_fmt_wss); 148862306a36Sopenharmony_ci if (IS_ERR(i2s->field_fmt_wss)) 148962306a36Sopenharmony_ci return PTR_ERR(i2s->field_fmt_wss); 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci i2s->field_fmt_sr = 149262306a36Sopenharmony_ci devm_regmap_field_alloc(dev, i2s->regmap, 149362306a36Sopenharmony_ci i2s->variant->field_fmt_sr); 149462306a36Sopenharmony_ci if (IS_ERR(i2s->field_fmt_sr)) 149562306a36Sopenharmony_ci return PTR_ERR(i2s->field_fmt_sr); 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci return 0; 149862306a36Sopenharmony_ci} 149962306a36Sopenharmony_ci 150062306a36Sopenharmony_cistatic int sun4i_i2s_probe(struct platform_device *pdev) 150162306a36Sopenharmony_ci{ 150262306a36Sopenharmony_ci struct sun4i_i2s *i2s; 150362306a36Sopenharmony_ci struct resource *res; 150462306a36Sopenharmony_ci void __iomem *regs; 150562306a36Sopenharmony_ci int irq, ret; 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_ci i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL); 150862306a36Sopenharmony_ci if (!i2s) 150962306a36Sopenharmony_ci return -ENOMEM; 151062306a36Sopenharmony_ci platform_set_drvdata(pdev, i2s); 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 151362306a36Sopenharmony_ci if (IS_ERR(regs)) 151462306a36Sopenharmony_ci return PTR_ERR(regs); 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 151762306a36Sopenharmony_ci if (irq < 0) 151862306a36Sopenharmony_ci return irq; 151962306a36Sopenharmony_ci 152062306a36Sopenharmony_ci i2s->variant = of_device_get_match_data(&pdev->dev); 152162306a36Sopenharmony_ci if (!i2s->variant) { 152262306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to determine the quirks to use\n"); 152362306a36Sopenharmony_ci return -ENODEV; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci i2s->bus_clk = devm_clk_get(&pdev->dev, "apb"); 152762306a36Sopenharmony_ci if (IS_ERR(i2s->bus_clk)) { 152862306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't get our bus clock\n"); 152962306a36Sopenharmony_ci return PTR_ERR(i2s->bus_clk); 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci i2s->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 153362306a36Sopenharmony_ci i2s->variant->sun4i_i2s_regmap); 153462306a36Sopenharmony_ci if (IS_ERR(i2s->regmap)) { 153562306a36Sopenharmony_ci dev_err(&pdev->dev, "Regmap initialisation failed\n"); 153662306a36Sopenharmony_ci return PTR_ERR(i2s->regmap); 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_ci i2s->mod_clk = devm_clk_get(&pdev->dev, "mod"); 154062306a36Sopenharmony_ci if (IS_ERR(i2s->mod_clk)) { 154162306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't get our mod clock\n"); 154262306a36Sopenharmony_ci return PTR_ERR(i2s->mod_clk); 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci if (i2s->variant->has_reset) { 154662306a36Sopenharmony_ci i2s->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); 154762306a36Sopenharmony_ci if (IS_ERR(i2s->rst)) { 154862306a36Sopenharmony_ci dev_err(&pdev->dev, "Failed to get reset control\n"); 154962306a36Sopenharmony_ci return PTR_ERR(i2s->rst); 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci } 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (!IS_ERR(i2s->rst)) { 155462306a36Sopenharmony_ci ret = reset_control_deassert(i2s->rst); 155562306a36Sopenharmony_ci if (ret) { 155662306a36Sopenharmony_ci dev_err(&pdev->dev, 155762306a36Sopenharmony_ci "Failed to deassert the reset control\n"); 155862306a36Sopenharmony_ci return -EINVAL; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci i2s->playback_dma_data.addr = res->start + 156362306a36Sopenharmony_ci i2s->variant->reg_offset_txdata; 156462306a36Sopenharmony_ci i2s->playback_dma_data.maxburst = 8; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci i2s->capture_dma_data.addr = res->start + SUN4I_I2S_FIFO_RX_REG; 156762306a36Sopenharmony_ci i2s->capture_dma_data.maxburst = 8; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 157062306a36Sopenharmony_ci if (!pm_runtime_enabled(&pdev->dev)) { 157162306a36Sopenharmony_ci ret = sun4i_i2s_runtime_resume(&pdev->dev); 157262306a36Sopenharmony_ci if (ret) 157362306a36Sopenharmony_ci goto err_pm_disable; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci ret = sun4i_i2s_init_regmap_fields(&pdev->dev, i2s); 157762306a36Sopenharmony_ci if (ret) { 157862306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not initialise regmap fields\n"); 157962306a36Sopenharmony_ci goto err_suspend; 158062306a36Sopenharmony_ci } 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 158362306a36Sopenharmony_ci if (ret) { 158462306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not register PCM\n"); 158562306a36Sopenharmony_ci goto err_suspend; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 158962306a36Sopenharmony_ci &sun4i_i2s_component, 159062306a36Sopenharmony_ci &sun4i_i2s_dai, 1); 159162306a36Sopenharmony_ci if (ret) { 159262306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not register DAI\n"); 159362306a36Sopenharmony_ci goto err_suspend; 159462306a36Sopenharmony_ci } 159562306a36Sopenharmony_ci 159662306a36Sopenharmony_ci return 0; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cierr_suspend: 159962306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 160062306a36Sopenharmony_ci sun4i_i2s_runtime_suspend(&pdev->dev); 160162306a36Sopenharmony_cierr_pm_disable: 160262306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 160362306a36Sopenharmony_ci if (!IS_ERR(i2s->rst)) 160462306a36Sopenharmony_ci reset_control_assert(i2s->rst); 160562306a36Sopenharmony_ci 160662306a36Sopenharmony_ci return ret; 160762306a36Sopenharmony_ci} 160862306a36Sopenharmony_ci 160962306a36Sopenharmony_cistatic void sun4i_i2s_remove(struct platform_device *pdev) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci struct sun4i_i2s *i2s = dev_get_drvdata(&pdev->dev); 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 161462306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 161562306a36Sopenharmony_ci sun4i_i2s_runtime_suspend(&pdev->dev); 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_ci if (!IS_ERR(i2s->rst)) 161862306a36Sopenharmony_ci reset_control_assert(i2s->rst); 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_cistatic const struct of_device_id sun4i_i2s_match[] = { 162262306a36Sopenharmony_ci { 162362306a36Sopenharmony_ci .compatible = "allwinner,sun4i-a10-i2s", 162462306a36Sopenharmony_ci .data = &sun4i_a10_i2s_quirks, 162562306a36Sopenharmony_ci }, 162662306a36Sopenharmony_ci { 162762306a36Sopenharmony_ci .compatible = "allwinner,sun6i-a31-i2s", 162862306a36Sopenharmony_ci .data = &sun6i_a31_i2s_quirks, 162962306a36Sopenharmony_ci }, 163062306a36Sopenharmony_ci { 163162306a36Sopenharmony_ci .compatible = "allwinner,sun8i-a83t-i2s", 163262306a36Sopenharmony_ci .data = &sun8i_a83t_i2s_quirks, 163362306a36Sopenharmony_ci }, 163462306a36Sopenharmony_ci { 163562306a36Sopenharmony_ci .compatible = "allwinner,sun8i-h3-i2s", 163662306a36Sopenharmony_ci .data = &sun8i_h3_i2s_quirks, 163762306a36Sopenharmony_ci }, 163862306a36Sopenharmony_ci { 163962306a36Sopenharmony_ci .compatible = "allwinner,sun50i-a64-codec-i2s", 164062306a36Sopenharmony_ci .data = &sun50i_a64_codec_i2s_quirks, 164162306a36Sopenharmony_ci }, 164262306a36Sopenharmony_ci { 164362306a36Sopenharmony_ci .compatible = "allwinner,sun50i-h6-i2s", 164462306a36Sopenharmony_ci .data = &sun50i_h6_i2s_quirks, 164562306a36Sopenharmony_ci }, 164662306a36Sopenharmony_ci { 164762306a36Sopenharmony_ci .compatible = "allwinner,sun50i-r329-i2s", 164862306a36Sopenharmony_ci .data = &sun50i_r329_i2s_quirks, 164962306a36Sopenharmony_ci }, 165062306a36Sopenharmony_ci {} 165162306a36Sopenharmony_ci}; 165262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun4i_i2s_match); 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_cistatic const struct dev_pm_ops sun4i_i2s_pm_ops = { 165562306a36Sopenharmony_ci .runtime_resume = sun4i_i2s_runtime_resume, 165662306a36Sopenharmony_ci .runtime_suspend = sun4i_i2s_runtime_suspend, 165762306a36Sopenharmony_ci}; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_cistatic struct platform_driver sun4i_i2s_driver = { 166062306a36Sopenharmony_ci .probe = sun4i_i2s_probe, 166162306a36Sopenharmony_ci .remove_new = sun4i_i2s_remove, 166262306a36Sopenharmony_ci .driver = { 166362306a36Sopenharmony_ci .name = "sun4i-i2s", 166462306a36Sopenharmony_ci .of_match_table = sun4i_i2s_match, 166562306a36Sopenharmony_ci .pm = &sun4i_i2s_pm_ops, 166662306a36Sopenharmony_ci }, 166762306a36Sopenharmony_ci}; 166862306a36Sopenharmony_cimodule_platform_driver(sun4i_i2s_driver); 166962306a36Sopenharmony_ci 167062306a36Sopenharmony_ciMODULE_AUTHOR("Andrea Venturi <be17068@iperbole.bo.it>"); 167162306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 167262306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A10 I2S driver"); 167362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1674