1227f609cSHerve Codina // SPDX-License-Identifier: GPL-2.0 2227f609cSHerve Codina // 3227f609cSHerve Codina // peb2466.c -- Infineon PEB2466 ALSA SoC driver 4227f609cSHerve Codina // 5227f609cSHerve Codina // Copyright 2023 CS GROUP France 6227f609cSHerve Codina // 7227f609cSHerve Codina // Author: Herve Codina <herve.codina@bootlin.com> 8227f609cSHerve Codina 9227f609cSHerve Codina #include <asm/unaligned.h> 10227f609cSHerve Codina #include <linux/clk.h> 11227f609cSHerve Codina #include <linux/firmware.h> 12227f609cSHerve Codina #include <linux/gpio/consumer.h> 13227f609cSHerve Codina #include <linux/gpio/driver.h> 14227f609cSHerve Codina #include <linux/module.h> 15227f609cSHerve Codina #include <linux/mutex.h> 16227f609cSHerve Codina #include <linux/slab.h> 17227f609cSHerve Codina #include <linux/spi/spi.h> 18227f609cSHerve Codina #include <sound/pcm_params.h> 19227f609cSHerve Codina #include <sound/soc.h> 20227f609cSHerve Codina #include <sound/tlv.h> 21227f609cSHerve Codina 22227f609cSHerve Codina #define PEB2466_NB_CHANNEL 4 23227f609cSHerve Codina 24227f609cSHerve Codina struct peb2466_lookup { 25227f609cSHerve Codina u8 (*table)[4]; 26227f609cSHerve Codina unsigned int count; 27227f609cSHerve Codina }; 28227f609cSHerve Codina 29227f609cSHerve Codina #define PEB2466_TLV_SIZE (sizeof((unsigned int []){TLV_DB_SCALE_ITEM(0, 0, 0)}) / \ 30227f609cSHerve Codina sizeof(unsigned int)) 31227f609cSHerve Codina 32227f609cSHerve Codina struct peb2466_lkup_ctrl { 33227f609cSHerve Codina int reg; 34227f609cSHerve Codina unsigned int index; 35227f609cSHerve Codina const struct peb2466_lookup *lookup; 36227f609cSHerve Codina unsigned int tlv_array[PEB2466_TLV_SIZE]; 37227f609cSHerve Codina }; 38227f609cSHerve Codina 39227f609cSHerve Codina struct peb2466 { 40227f609cSHerve Codina struct spi_device *spi; 41227f609cSHerve Codina struct clk *mclk; 42227f609cSHerve Codina struct gpio_desc *reset_gpio; 43227f609cSHerve Codina u8 spi_tx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ 44227f609cSHerve Codina u8 spi_rx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ 45227f609cSHerve Codina struct regmap *regmap; 46227f609cSHerve Codina struct { 47227f609cSHerve Codina struct peb2466_lookup ax_lookup; 48227f609cSHerve Codina struct peb2466_lookup ar_lookup; 49227f609cSHerve Codina struct peb2466_lkup_ctrl ax_lkup_ctrl; 50227f609cSHerve Codina struct peb2466_lkup_ctrl ar_lkup_ctrl; 51227f609cSHerve Codina unsigned int tg1_freq_item; 52227f609cSHerve Codina unsigned int tg2_freq_item; 53227f609cSHerve Codina } ch[PEB2466_NB_CHANNEL]; 54227f609cSHerve Codina int max_chan_playback; 55227f609cSHerve Codina int max_chan_capture; 56227f609cSHerve Codina struct { 57227f609cSHerve Codina struct gpio_chip gpio_chip; 58227f609cSHerve Codina struct mutex lock; 59227f609cSHerve Codina struct { 60227f609cSHerve Codina unsigned int xr0; 61227f609cSHerve Codina unsigned int xr1; 62227f609cSHerve Codina unsigned int xr2; 63227f609cSHerve Codina unsigned int xr3; 64227f609cSHerve Codina } cache; 65227f609cSHerve Codina } gpio; 66227f609cSHerve Codina }; 67227f609cSHerve Codina 68227f609cSHerve Codina #define PEB2466_CMD_R (1 << 5) 69227f609cSHerve Codina #define PEB2466_CMD_W (0 << 5) 70227f609cSHerve Codina 71227f609cSHerve Codina #define PEB2466_CMD_MASK 0x18 72227f609cSHerve Codina #define PEB2466_CMD_XOP 0x18 /* XOP is 0bxxx11xxx */ 73227f609cSHerve Codina #define PEB2466_CMD_SOP 0x10 /* SOP is 0bxxx10xxx */ 74227f609cSHerve Codina #define PEB2466_CMD_COP 0x00 /* COP is 0bxxx0xxxx, handle 0bxxx00xxx */ 75227f609cSHerve Codina #define PEB2466_CMD_COP1 0x08 /* COP is 0bxxx0xxxx, handle 0bxxx01xxx */ 76227f609cSHerve Codina 77227f609cSHerve Codina #define PEB2466_MAKE_XOP(_lsel) (PEB2466_CMD_XOP | (_lsel)) 78227f609cSHerve Codina #define PEB2466_MAKE_SOP(_ad, _lsel) (PEB2466_CMD_SOP | ((_ad) << 6) | (_lsel)) 79227f609cSHerve Codina #define PEB2466_MAKE_COP(_ad, _code) (PEB2466_CMD_COP | ((_ad) << 6) | (_code)) 80227f609cSHerve Codina 81227f609cSHerve Codina #define PEB2466_CR0(_ch) PEB2466_MAKE_SOP(_ch, 0x0) 82227f609cSHerve Codina #define PEB2466_CR0_TH (1 << 7) 83227f609cSHerve Codina #define PEB2466_CR0_IMR1 (1 << 6) 84227f609cSHerve Codina #define PEB2466_CR0_FRX (1 << 5) 85227f609cSHerve Codina #define PEB2466_CR0_FRR (1 << 4) 86227f609cSHerve Codina #define PEB2466_CR0_AX (1 << 3) 87227f609cSHerve Codina #define PEB2466_CR0_AR (1 << 2) 88227f609cSHerve Codina #define PEB2466_CR0_THSEL_MASK (0x3 << 0) 89227f609cSHerve Codina #define PEB2466_CR0_THSEL(_set) ((_set) << 0) 90227f609cSHerve Codina 91227f609cSHerve Codina #define PEB2466_CR1(_ch) PEB2466_MAKE_SOP(_ch, 0x1) 92227f609cSHerve Codina #define PEB2466_CR1_ETG2 (1 << 7) 93227f609cSHerve Codina #define PEB2466_CR1_ETG1 (1 << 6) 94227f609cSHerve Codina #define PEB2466_CR1_PTG2 (1 << 5) 95227f609cSHerve Codina #define PEB2466_CR1_PTG1 (1 << 4) 96227f609cSHerve Codina #define PEB2466_CR1_LAW_MASK (1 << 3) 97227f609cSHerve Codina #define PEB2466_CR1_LAW_ALAW (0 << 3) 98227f609cSHerve Codina #define PEB2466_CR1_LAW_MULAW (1 << 3) 99227f609cSHerve Codina #define PEB2466_CR1_PU (1 << 0) 100227f609cSHerve Codina 101227f609cSHerve Codina #define PEB2466_CR2(_ch) PEB2466_MAKE_SOP(_ch, 0x2) 102227f609cSHerve Codina #define PEB2466_CR3(_ch) PEB2466_MAKE_SOP(_ch, 0x3) 103227f609cSHerve Codina #define PEB2466_CR4(_ch) PEB2466_MAKE_SOP(_ch, 0x4) 104227f609cSHerve Codina #define PEB2466_CR5(_ch) PEB2466_MAKE_SOP(_ch, 0x5) 105227f609cSHerve Codina 106227f609cSHerve Codina #define PEB2466_XR0 PEB2466_MAKE_XOP(0x0) 107227f609cSHerve Codina #define PEB2466_XR1 PEB2466_MAKE_XOP(0x1) 108227f609cSHerve Codina #define PEB2466_XR2 PEB2466_MAKE_XOP(0x2) 109227f609cSHerve Codina #define PEB2466_XR3 PEB2466_MAKE_XOP(0x3) 110227f609cSHerve Codina #define PEB2466_XR4 PEB2466_MAKE_XOP(0x4) 111227f609cSHerve Codina #define PEB2466_XR5 PEB2466_MAKE_XOP(0x5) 112227f609cSHerve Codina #define PEB2466_XR5_MCLK_1536 (0x0 << 6) 113227f609cSHerve Codina #define PEB2466_XR5_MCLK_2048 (0x1 << 6) 114227f609cSHerve Codina #define PEB2466_XR5_MCLK_4096 (0x2 << 6) 115227f609cSHerve Codina #define PEB2466_XR5_MCLK_8192 (0x3 << 6) 116227f609cSHerve Codina 117227f609cSHerve Codina #define PEB2466_XR6 PEB2466_MAKE_XOP(0x6) 118227f609cSHerve Codina #define PEB2466_XR6_PCM_OFFSET(_off) ((_off) << 0) 119227f609cSHerve Codina 120227f609cSHerve Codina #define PEB2466_XR7 PEB2466_MAKE_XOP(0x7) 121227f609cSHerve Codina 122227f609cSHerve Codina #define PEB2466_TH_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x0) 123227f609cSHerve Codina #define PEB2466_TH_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x1) 124227f609cSHerve Codina #define PEB2466_TH_FILTER_P3(_ch) PEB2466_MAKE_COP(_ch, 0x2) 125227f609cSHerve Codina #define PEB2466_IMR1_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x4) 126227f609cSHerve Codina #define PEB2466_IMR1_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x5) 127227f609cSHerve Codina #define PEB2466_FRX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x6) 128227f609cSHerve Codina #define PEB2466_FRR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x7) 129227f609cSHerve Codina #define PEB2466_AX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x8) 130227f609cSHerve Codina #define PEB2466_AR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x9) 131227f609cSHerve Codina #define PEB2466_TG1(_ch) PEB2466_MAKE_COP(_ch, 0xc) 132227f609cSHerve Codina #define PEB2466_TG2(_ch) PEB2466_MAKE_COP(_ch, 0xd) 133227f609cSHerve Codina 134227f609cSHerve Codina static int peb2466_write_byte(struct peb2466 *peb2466, u8 cmd, u8 val) 135227f609cSHerve Codina { 136227f609cSHerve Codina struct spi_transfer xfer = { 137227f609cSHerve Codina .tx_buf = &peb2466->spi_tx_buf, 138227f609cSHerve Codina .len = 2, 139227f609cSHerve Codina }; 140227f609cSHerve Codina 141227f609cSHerve Codina peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; 142227f609cSHerve Codina peb2466->spi_tx_buf[1] = val; 143227f609cSHerve Codina 144227f609cSHerve Codina dev_dbg(&peb2466->spi->dev, "write byte (cmd %02x) %02x\n", 145227f609cSHerve Codina peb2466->spi_tx_buf[0], peb2466->spi_tx_buf[1]); 146227f609cSHerve Codina 147227f609cSHerve Codina return spi_sync_transfer(peb2466->spi, &xfer, 1); 148227f609cSHerve Codina } 149227f609cSHerve Codina 150227f609cSHerve Codina static int peb2466_read_byte(struct peb2466 *peb2466, u8 cmd, u8 *val) 151227f609cSHerve Codina { 152227f609cSHerve Codina struct spi_transfer xfer = { 153227f609cSHerve Codina .tx_buf = &peb2466->spi_tx_buf, 154227f609cSHerve Codina .rx_buf = &peb2466->spi_rx_buf, 155227f609cSHerve Codina .len = 3, 156227f609cSHerve Codina }; 157227f609cSHerve Codina int ret; 158227f609cSHerve Codina 159227f609cSHerve Codina peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_R; 160227f609cSHerve Codina 161227f609cSHerve Codina ret = spi_sync_transfer(peb2466->spi, &xfer, 1); 162227f609cSHerve Codina if (ret) 163227f609cSHerve Codina return ret; 164227f609cSHerve Codina 165227f609cSHerve Codina if (peb2466->spi_rx_buf[1] != 0x81) { 166227f609cSHerve Codina dev_err(&peb2466->spi->dev, 167227f609cSHerve Codina "spi xfer rd (cmd %02x) invalid ident byte (0x%02x)\n", 168227f609cSHerve Codina peb2466->spi_tx_buf[0], peb2466->spi_rx_buf[1]); 169227f609cSHerve Codina return -EILSEQ; 170227f609cSHerve Codina } 171227f609cSHerve Codina 172227f609cSHerve Codina *val = peb2466->spi_rx_buf[2]; 173227f609cSHerve Codina 174227f609cSHerve Codina dev_dbg(&peb2466->spi->dev, "read byte (cmd %02x) %02x\n", 175227f609cSHerve Codina peb2466->spi_tx_buf[0], *val); 176227f609cSHerve Codina 177227f609cSHerve Codina return 0; 178227f609cSHerve Codina } 179227f609cSHerve Codina 180227f609cSHerve Codina static int peb2466_write_buf(struct peb2466 *peb2466, u8 cmd, const u8 *buf, unsigned int len) 181227f609cSHerve Codina { 182227f609cSHerve Codina struct spi_transfer xfer = { 183227f609cSHerve Codina .tx_buf = &peb2466->spi_tx_buf, 184227f609cSHerve Codina .len = len + 1, 185227f609cSHerve Codina }; 186227f609cSHerve Codina 187227f609cSHerve Codina if (len > 8) 188227f609cSHerve Codina return -EINVAL; 189227f609cSHerve Codina 190227f609cSHerve Codina peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; 191227f609cSHerve Codina memcpy(&peb2466->spi_tx_buf[1], buf, len); 192227f609cSHerve Codina 193227f609cSHerve Codina dev_dbg(&peb2466->spi->dev, "write buf (cmd %02x, %u) %*ph\n", 194227f609cSHerve Codina peb2466->spi_tx_buf[0], len, len, &peb2466->spi_tx_buf[1]); 195227f609cSHerve Codina 196227f609cSHerve Codina return spi_sync_transfer(peb2466->spi, &xfer, 1); 197227f609cSHerve Codina } 198227f609cSHerve Codina 199227f609cSHerve Codina static int peb2466_reg_write(void *context, unsigned int reg, unsigned int val) 200227f609cSHerve Codina { 201227f609cSHerve Codina struct peb2466 *peb2466 = context; 202227f609cSHerve Codina int ret; 203227f609cSHerve Codina 204227f609cSHerve Codina /* 205227f609cSHerve Codina * Only XOP and SOP commands can be handled as registers. 206227f609cSHerve Codina * COP commands are handled using direct peb2466_write_buf() calls. 207227f609cSHerve Codina */ 208227f609cSHerve Codina switch (reg & PEB2466_CMD_MASK) { 209227f609cSHerve Codina case PEB2466_CMD_XOP: 210227f609cSHerve Codina case PEB2466_CMD_SOP: 211227f609cSHerve Codina ret = peb2466_write_byte(peb2466, reg, val); 212227f609cSHerve Codina break; 213227f609cSHerve Codina default: 214227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n"); 215227f609cSHerve Codina ret = -EINVAL; 216227f609cSHerve Codina break; 217227f609cSHerve Codina } 218227f609cSHerve Codina return ret; 219227f609cSHerve Codina } 220227f609cSHerve Codina 221227f609cSHerve Codina static int peb2466_reg_read(void *context, unsigned int reg, unsigned int *val) 222227f609cSHerve Codina { 223227f609cSHerve Codina struct peb2466 *peb2466 = context; 224227f609cSHerve Codina int ret; 225227f609cSHerve Codina u8 tmp; 226227f609cSHerve Codina 227227f609cSHerve Codina /* Only XOP and SOP commands can be handled as registers */ 228227f609cSHerve Codina switch (reg & PEB2466_CMD_MASK) { 229227f609cSHerve Codina case PEB2466_CMD_XOP: 230227f609cSHerve Codina case PEB2466_CMD_SOP: 231227f609cSHerve Codina ret = peb2466_read_byte(peb2466, reg, &tmp); 232227f609cSHerve Codina *val = tmp; 233227f609cSHerve Codina break; 234227f609cSHerve Codina default: 235227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n"); 236227f609cSHerve Codina ret = -EINVAL; 237227f609cSHerve Codina break; 238227f609cSHerve Codina } 239227f609cSHerve Codina return ret; 240227f609cSHerve Codina } 241227f609cSHerve Codina 242227f609cSHerve Codina static const struct regmap_config peb2466_regmap_config = { 243227f609cSHerve Codina .reg_bits = 8, 244227f609cSHerve Codina .val_bits = 8, 245227f609cSHerve Codina .max_register = 0xFF, 246227f609cSHerve Codina .reg_write = peb2466_reg_write, 247227f609cSHerve Codina .reg_read = peb2466_reg_read, 248227f609cSHerve Codina .cache_type = REGCACHE_NONE, 249227f609cSHerve Codina }; 250227f609cSHerve Codina 251227f609cSHerve Codina static int peb2466_lkup_ctrl_info(struct snd_kcontrol *kcontrol, 252227f609cSHerve Codina struct snd_ctl_elem_info *uinfo) 253227f609cSHerve Codina { 254227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl = 255227f609cSHerve Codina (struct peb2466_lkup_ctrl *)kcontrol->private_value; 256227f609cSHerve Codina 257227f609cSHerve Codina uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 258227f609cSHerve Codina uinfo->count = 1; 259227f609cSHerve Codina uinfo->value.integer.min = 0; 260227f609cSHerve Codina uinfo->value.integer.max = lkup_ctrl->lookup->count - 1; 261227f609cSHerve Codina return 0; 262227f609cSHerve Codina } 263227f609cSHerve Codina 264227f609cSHerve Codina static int peb2466_lkup_ctrl_get(struct snd_kcontrol *kcontrol, 265227f609cSHerve Codina struct snd_ctl_elem_value *ucontrol) 266227f609cSHerve Codina { 267227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl = 268227f609cSHerve Codina (struct peb2466_lkup_ctrl *)kcontrol->private_value; 269227f609cSHerve Codina 270227f609cSHerve Codina ucontrol->value.integer.value[0] = lkup_ctrl->index; 271227f609cSHerve Codina return 0; 272227f609cSHerve Codina } 273227f609cSHerve Codina 274227f609cSHerve Codina static int peb2466_lkup_ctrl_put(struct snd_kcontrol *kcontrol, 275227f609cSHerve Codina struct snd_ctl_elem_value *ucontrol) 276227f609cSHerve Codina { 277227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl = 278227f609cSHerve Codina (struct peb2466_lkup_ctrl *)kcontrol->private_value; 279227f609cSHerve Codina struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 280227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 281227f609cSHerve Codina unsigned int index; 282227f609cSHerve Codina int ret; 283227f609cSHerve Codina 284227f609cSHerve Codina index = ucontrol->value.integer.value[0]; 285227f609cSHerve Codina if (index >= lkup_ctrl->lookup->count) 286227f609cSHerve Codina return -EINVAL; 287227f609cSHerve Codina 288227f609cSHerve Codina if (index == lkup_ctrl->index) 289227f609cSHerve Codina return 0; 290227f609cSHerve Codina 291227f609cSHerve Codina ret = peb2466_write_buf(peb2466, lkup_ctrl->reg, 292227f609cSHerve Codina lkup_ctrl->lookup->table[index], 4); 293227f609cSHerve Codina if (ret) 294227f609cSHerve Codina return ret; 295227f609cSHerve Codina 296227f609cSHerve Codina lkup_ctrl->index = index; 297227f609cSHerve Codina return 1; /* The value changed */ 298227f609cSHerve Codina } 299227f609cSHerve Codina 300227f609cSHerve Codina static int peb2466_add_lkup_ctrl(struct snd_soc_component *component, 301227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl, 302227f609cSHerve Codina const char *name, int min_val, int step) 303227f609cSHerve Codina { 304227f609cSHerve Codina DECLARE_TLV_DB_SCALE(tlv_array, min_val, step, 0); 305227f609cSHerve Codina struct snd_kcontrol_new control = {0}; 306227f609cSHerve Codina 307227f609cSHerve Codina BUILD_BUG_ON(sizeof(lkup_ctrl->tlv_array) < sizeof(tlv_array)); 308227f609cSHerve Codina memcpy(lkup_ctrl->tlv_array, tlv_array, sizeof(tlv_array)); 309227f609cSHerve Codina 310227f609cSHerve Codina control.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 311227f609cSHerve Codina control.name = name; 312227f609cSHerve Codina control.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | 313227f609cSHerve Codina SNDRV_CTL_ELEM_ACCESS_READWRITE; 314227f609cSHerve Codina control.tlv.p = lkup_ctrl->tlv_array; 315227f609cSHerve Codina control.info = peb2466_lkup_ctrl_info; 316227f609cSHerve Codina control.get = peb2466_lkup_ctrl_get; 317227f609cSHerve Codina control.put = peb2466_lkup_ctrl_put; 318227f609cSHerve Codina control.private_value = (unsigned long)lkup_ctrl; 319227f609cSHerve Codina 320227f609cSHerve Codina return snd_soc_add_component_controls(component, &control, 1); 321227f609cSHerve Codina } 322227f609cSHerve Codina 323227f609cSHerve Codina enum peb2466_tone_freq { 324227f609cSHerve Codina PEB2466_TONE_697HZ, 325227f609cSHerve Codina PEB2466_TONE_800HZ, 326227f609cSHerve Codina PEB2466_TONE_950HZ, 327227f609cSHerve Codina PEB2466_TONE_1000HZ, 328227f609cSHerve Codina PEB2466_TONE_1008HZ, 329227f609cSHerve Codina PEB2466_TONE_2000HZ, 330227f609cSHerve Codina }; 331227f609cSHerve Codina 332227f609cSHerve Codina static const u8 peb2466_tone_lookup[][4] = { 333227f609cSHerve Codina [PEB2466_TONE_697HZ] = {0x0a, 0x33, 0x5a, 0x2c}, 334227f609cSHerve Codina [PEB2466_TONE_800HZ] = {0x12, 0xD6, 0x5a, 0xc0}, 335227f609cSHerve Codina [PEB2466_TONE_950HZ] = {0x1c, 0xf0, 0x5c, 0xc0}, 336227f609cSHerve Codina [PEB2466_TONE_1000HZ] = {0}, /* lookup value not used for 1000Hz */ 337227f609cSHerve Codina [PEB2466_TONE_1008HZ] = {0x1a, 0xae, 0x57, 0x70}, 338227f609cSHerve Codina [PEB2466_TONE_2000HZ] = {0x00, 0x80, 0x50, 0x09}, 339227f609cSHerve Codina }; 340227f609cSHerve Codina 341227f609cSHerve Codina static const char * const peb2466_tone_freq_txt[] = { 342227f609cSHerve Codina [PEB2466_TONE_697HZ] = "697Hz", 343227f609cSHerve Codina [PEB2466_TONE_800HZ] = "800Hz", 344227f609cSHerve Codina [PEB2466_TONE_950HZ] = "950Hz", 345227f609cSHerve Codina [PEB2466_TONE_1000HZ] = "1000Hz", 346227f609cSHerve Codina [PEB2466_TONE_1008HZ] = "1008Hz", 347227f609cSHerve Codina [PEB2466_TONE_2000HZ] = "2000Hz" 348227f609cSHerve Codina }; 349227f609cSHerve Codina 350227f609cSHerve Codina static const struct soc_enum peb2466_tg_freq[][2] = { 351227f609cSHerve Codina [0] = { 352227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG1(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 353227f609cSHerve Codina peb2466_tone_freq_txt), 354227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG2(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 355227f609cSHerve Codina peb2466_tone_freq_txt) 356227f609cSHerve Codina }, 357227f609cSHerve Codina [1] = { 358227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG1(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 359227f609cSHerve Codina peb2466_tone_freq_txt), 360227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG2(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 361227f609cSHerve Codina peb2466_tone_freq_txt) 362227f609cSHerve Codina }, 363227f609cSHerve Codina [2] = { 364227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG1(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 365227f609cSHerve Codina peb2466_tone_freq_txt), 366227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG2(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 367227f609cSHerve Codina peb2466_tone_freq_txt) 368227f609cSHerve Codina }, 369227f609cSHerve Codina [3] = { 370227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG1(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 371227f609cSHerve Codina peb2466_tone_freq_txt), 372227f609cSHerve Codina SOC_ENUM_SINGLE(PEB2466_TG2(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 373227f609cSHerve Codina peb2466_tone_freq_txt) 374227f609cSHerve Codina } 375227f609cSHerve Codina }; 376227f609cSHerve Codina 377227f609cSHerve Codina static int peb2466_tg_freq_get(struct snd_kcontrol *kcontrol, 378227f609cSHerve Codina struct snd_ctl_elem_value *ucontrol) 379227f609cSHerve Codina { 380227f609cSHerve Codina struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 381227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 382227f609cSHerve Codina struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 383227f609cSHerve Codina 384227f609cSHerve Codina switch (e->reg) { 385227f609cSHerve Codina case PEB2466_TG1(0): 386227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg1_freq_item; 387227f609cSHerve Codina break; 388227f609cSHerve Codina case PEB2466_TG2(0): 389227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg2_freq_item; 390227f609cSHerve Codina break; 391227f609cSHerve Codina case PEB2466_TG1(1): 392227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg1_freq_item; 393227f609cSHerve Codina break; 394227f609cSHerve Codina case PEB2466_TG2(1): 395227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg2_freq_item; 396227f609cSHerve Codina break; 397227f609cSHerve Codina case PEB2466_TG1(2): 398227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg1_freq_item; 399227f609cSHerve Codina break; 400227f609cSHerve Codina case PEB2466_TG2(2): 401227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg2_freq_item; 402227f609cSHerve Codina break; 403227f609cSHerve Codina case PEB2466_TG1(3): 404227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg1_freq_item; 405227f609cSHerve Codina break; 406227f609cSHerve Codina case PEB2466_TG2(3): 407227f609cSHerve Codina ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg2_freq_item; 408227f609cSHerve Codina break; 409227f609cSHerve Codina default: 410227f609cSHerve Codina return -EINVAL; 411227f609cSHerve Codina } 412227f609cSHerve Codina return 0; 413227f609cSHerve Codina } 414227f609cSHerve Codina 415227f609cSHerve Codina static int peb2466_tg_freq_put(struct snd_kcontrol *kcontrol, 416227f609cSHerve Codina struct snd_ctl_elem_value *ucontrol) 417227f609cSHerve Codina { 418227f609cSHerve Codina struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 419227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 420227f609cSHerve Codina struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 421227f609cSHerve Codina unsigned int *tg_freq_item; 422227f609cSHerve Codina u8 cr1_reg, cr1_mask; 423227f609cSHerve Codina unsigned int index; 424227f609cSHerve Codina int ret; 425227f609cSHerve Codina 426227f609cSHerve Codina index = ucontrol->value.enumerated.item[0]; 427227f609cSHerve Codina 428227f609cSHerve Codina if (index >= ARRAY_SIZE(peb2466_tone_lookup)) 429227f609cSHerve Codina return -EINVAL; 430227f609cSHerve Codina 431227f609cSHerve Codina switch (e->reg) { 432227f609cSHerve Codina case PEB2466_TG1(0): 433227f609cSHerve Codina tg_freq_item = &peb2466->ch[0].tg1_freq_item; 434227f609cSHerve Codina cr1_reg = PEB2466_CR1(0); 435227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG1; 436227f609cSHerve Codina break; 437227f609cSHerve Codina case PEB2466_TG2(0): 438227f609cSHerve Codina tg_freq_item = &peb2466->ch[0].tg2_freq_item; 439227f609cSHerve Codina cr1_reg = PEB2466_CR1(0); 440227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG2; 441227f609cSHerve Codina break; 442227f609cSHerve Codina case PEB2466_TG1(1): 443227f609cSHerve Codina tg_freq_item = &peb2466->ch[1].tg1_freq_item; 444227f609cSHerve Codina cr1_reg = PEB2466_CR1(1); 445227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG1; 446227f609cSHerve Codina break; 447227f609cSHerve Codina case PEB2466_TG2(1): 448227f609cSHerve Codina tg_freq_item = &peb2466->ch[1].tg2_freq_item; 449227f609cSHerve Codina cr1_reg = PEB2466_CR1(1); 450227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG2; 451227f609cSHerve Codina break; 452227f609cSHerve Codina case PEB2466_TG1(2): 453227f609cSHerve Codina tg_freq_item = &peb2466->ch[2].tg1_freq_item; 454227f609cSHerve Codina cr1_reg = PEB2466_CR1(2); 455227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG1; 456227f609cSHerve Codina break; 457227f609cSHerve Codina case PEB2466_TG2(2): 458227f609cSHerve Codina tg_freq_item = &peb2466->ch[2].tg2_freq_item; 459227f609cSHerve Codina cr1_reg = PEB2466_CR1(2); 460227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG2; 461227f609cSHerve Codina break; 462227f609cSHerve Codina case PEB2466_TG1(3): 463227f609cSHerve Codina tg_freq_item = &peb2466->ch[3].tg1_freq_item; 464227f609cSHerve Codina cr1_reg = PEB2466_CR1(3); 465227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG1; 466227f609cSHerve Codina break; 467227f609cSHerve Codina case PEB2466_TG2(3): 468227f609cSHerve Codina tg_freq_item = &peb2466->ch[3].tg2_freq_item; 469227f609cSHerve Codina cr1_reg = PEB2466_CR1(3); 470227f609cSHerve Codina cr1_mask = PEB2466_CR1_PTG2; 471227f609cSHerve Codina break; 472227f609cSHerve Codina default: 473227f609cSHerve Codina return -EINVAL; 474227f609cSHerve Codina } 475227f609cSHerve Codina 476227f609cSHerve Codina if (index == *tg_freq_item) 477227f609cSHerve Codina return 0; 478227f609cSHerve Codina 479227f609cSHerve Codina if (index == PEB2466_TONE_1000HZ) { 480227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, cr1_reg, cr1_mask, 0); 481227f609cSHerve Codina if (ret) 482227f609cSHerve Codina return ret; 483227f609cSHerve Codina } else { 484227f609cSHerve Codina ret = peb2466_write_buf(peb2466, e->reg, peb2466_tone_lookup[index], 4); 485227f609cSHerve Codina if (ret) 486227f609cSHerve Codina return ret; 487227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, cr1_reg, cr1_mask, cr1_mask); 488227f609cSHerve Codina if (ret) 489227f609cSHerve Codina return ret; 490227f609cSHerve Codina } 491227f609cSHerve Codina 492227f609cSHerve Codina *tg_freq_item = index; 493227f609cSHerve Codina return 1; /* The value changed */ 494227f609cSHerve Codina } 495227f609cSHerve Codina 496227f609cSHerve Codina static const struct snd_kcontrol_new peb2466_ch0_out_mix_controls[] = { 497227f609cSHerve Codina SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(0), 6, 1, 0), 498227f609cSHerve Codina SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(0), 7, 1, 0), 499227f609cSHerve Codina SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(0), 0, 1, 0) 500227f609cSHerve Codina }; 501227f609cSHerve Codina 502227f609cSHerve Codina static const struct snd_kcontrol_new peb2466_ch1_out_mix_controls[] = { 503227f609cSHerve Codina SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(1), 6, 1, 0), 504227f609cSHerve Codina SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(1), 7, 1, 0), 505227f609cSHerve Codina SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(1), 0, 1, 0) 506227f609cSHerve Codina }; 507227f609cSHerve Codina 508227f609cSHerve Codina static const struct snd_kcontrol_new peb2466_ch2_out_mix_controls[] = { 509227f609cSHerve Codina SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(2), 6, 1, 0), 510227f609cSHerve Codina SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(2), 7, 1, 0), 511227f609cSHerve Codina SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(2), 0, 1, 0) 512227f609cSHerve Codina }; 513227f609cSHerve Codina 514227f609cSHerve Codina static const struct snd_kcontrol_new peb2466_ch3_out_mix_controls[] = { 515227f609cSHerve Codina SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(3), 6, 1, 0), 516227f609cSHerve Codina SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(3), 7, 1, 0), 517227f609cSHerve Codina SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(3), 0, 1, 0) 518227f609cSHerve Codina }; 519227f609cSHerve Codina 520227f609cSHerve Codina static const struct snd_kcontrol_new peb2466_controls[] = { 521227f609cSHerve Codina /* Attenuators */ 522227f609cSHerve Codina SOC_SINGLE("DAC0 -6dB Playback Switch", PEB2466_CR3(0), 2, 1, 0), 523227f609cSHerve Codina SOC_SINGLE("DAC1 -6dB Playback Switch", PEB2466_CR3(1), 2, 1, 0), 524227f609cSHerve Codina SOC_SINGLE("DAC2 -6dB Playback Switch", PEB2466_CR3(2), 2, 1, 0), 525227f609cSHerve Codina SOC_SINGLE("DAC3 -6dB Playback Switch", PEB2466_CR3(3), 2, 1, 0), 526227f609cSHerve Codina 527227f609cSHerve Codina /* Amplifiers */ 528227f609cSHerve Codina SOC_SINGLE("ADC0 +6dB Capture Switch", PEB2466_CR3(0), 3, 1, 0), 529227f609cSHerve Codina SOC_SINGLE("ADC1 +6dB Capture Switch", PEB2466_CR3(1), 3, 1, 0), 530227f609cSHerve Codina SOC_SINGLE("ADC2 +6dB Capture Switch", PEB2466_CR3(2), 3, 1, 0), 531227f609cSHerve Codina SOC_SINGLE("ADC3 +6dB Capture Switch", PEB2466_CR3(3), 3, 1, 0), 532227f609cSHerve Codina 533227f609cSHerve Codina /* Tone generators */ 534227f609cSHerve Codina SOC_ENUM_EXT("DAC0 TG1 Freq", peb2466_tg_freq[0][0], 535227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 536227f609cSHerve Codina SOC_ENUM_EXT("DAC1 TG1 Freq", peb2466_tg_freq[1][0], 537227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 538227f609cSHerve Codina SOC_ENUM_EXT("DAC2 TG1 Freq", peb2466_tg_freq[2][0], 539227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 540227f609cSHerve Codina SOC_ENUM_EXT("DAC3 TG1 Freq", peb2466_tg_freq[3][0], 541227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 542227f609cSHerve Codina 543227f609cSHerve Codina SOC_ENUM_EXT("DAC0 TG2 Freq", peb2466_tg_freq[0][1], 544227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 545227f609cSHerve Codina SOC_ENUM_EXT("DAC1 TG2 Freq", peb2466_tg_freq[1][1], 546227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 547227f609cSHerve Codina SOC_ENUM_EXT("DAC2 TG2 Freq", peb2466_tg_freq[2][1], 548227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 549227f609cSHerve Codina SOC_ENUM_EXT("DAC3 TG2 Freq", peb2466_tg_freq[3][1], 550227f609cSHerve Codina peb2466_tg_freq_get, peb2466_tg_freq_put), 551227f609cSHerve Codina }; 552227f609cSHerve Codina 553227f609cSHerve Codina static const struct snd_soc_dapm_widget peb2466_dapm_widgets[] = { 554227f609cSHerve Codina SND_SOC_DAPM_SUPPLY("CH0 PWR", PEB2466_CR1(0), 0, 0, NULL, 0), 555227f609cSHerve Codina SND_SOC_DAPM_SUPPLY("CH1 PWR", PEB2466_CR1(1), 0, 0, NULL, 0), 556227f609cSHerve Codina SND_SOC_DAPM_SUPPLY("CH2 PWR", PEB2466_CR1(2), 0, 0, NULL, 0), 557227f609cSHerve Codina SND_SOC_DAPM_SUPPLY("CH3 PWR", PEB2466_CR1(3), 0, 0, NULL, 0), 558227f609cSHerve Codina 559227f609cSHerve Codina SND_SOC_DAPM_DAC("CH0 DIN", "Playback", SND_SOC_NOPM, 0, 0), 560227f609cSHerve Codina SND_SOC_DAPM_DAC("CH1 DIN", "Playback", SND_SOC_NOPM, 0, 0), 561227f609cSHerve Codina SND_SOC_DAPM_DAC("CH2 DIN", "Playback", SND_SOC_NOPM, 0, 0), 562227f609cSHerve Codina SND_SOC_DAPM_DAC("CH3 DIN", "Playback", SND_SOC_NOPM, 0, 0), 563227f609cSHerve Codina 564227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH0 TG1"), 565227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH1 TG1"), 566227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH2 TG1"), 567227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH3 TG1"), 568227f609cSHerve Codina 569227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH0 TG2"), 570227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH1 TG2"), 571227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH2 TG2"), 572227f609cSHerve Codina SND_SOC_DAPM_SIGGEN("CH3 TG2"), 573227f609cSHerve Codina 574227f609cSHerve Codina SND_SOC_DAPM_MIXER("DAC0 Mixer", SND_SOC_NOPM, 0, 0, 575227f609cSHerve Codina peb2466_ch0_out_mix_controls, 576227f609cSHerve Codina ARRAY_SIZE(peb2466_ch0_out_mix_controls)), 577227f609cSHerve Codina SND_SOC_DAPM_MIXER("DAC1 Mixer", SND_SOC_NOPM, 0, 0, 578227f609cSHerve Codina peb2466_ch1_out_mix_controls, 579227f609cSHerve Codina ARRAY_SIZE(peb2466_ch1_out_mix_controls)), 580227f609cSHerve Codina SND_SOC_DAPM_MIXER("DAC2 Mixer", SND_SOC_NOPM, 0, 0, 581227f609cSHerve Codina peb2466_ch2_out_mix_controls, 582227f609cSHerve Codina ARRAY_SIZE(peb2466_ch2_out_mix_controls)), 583227f609cSHerve Codina SND_SOC_DAPM_MIXER("DAC3 Mixer", SND_SOC_NOPM, 0, 0, 584227f609cSHerve Codina peb2466_ch3_out_mix_controls, 585227f609cSHerve Codina ARRAY_SIZE(peb2466_ch3_out_mix_controls)), 586227f609cSHerve Codina 587227f609cSHerve Codina SND_SOC_DAPM_PGA("DAC0 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 588227f609cSHerve Codina SND_SOC_DAPM_PGA("DAC1 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 589227f609cSHerve Codina SND_SOC_DAPM_PGA("DAC2 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 590227f609cSHerve Codina SND_SOC_DAPM_PGA("DAC3 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 591227f609cSHerve Codina 592227f609cSHerve Codina SND_SOC_DAPM_OUTPUT("OUT0"), 593227f609cSHerve Codina SND_SOC_DAPM_OUTPUT("OUT1"), 594227f609cSHerve Codina SND_SOC_DAPM_OUTPUT("OUT2"), 595227f609cSHerve Codina SND_SOC_DAPM_OUTPUT("OUT3"), 596227f609cSHerve Codina 597227f609cSHerve Codina SND_SOC_DAPM_INPUT("IN0"), 598227f609cSHerve Codina SND_SOC_DAPM_INPUT("IN1"), 599227f609cSHerve Codina SND_SOC_DAPM_INPUT("IN2"), 600227f609cSHerve Codina SND_SOC_DAPM_INPUT("IN3"), 601227f609cSHerve Codina 602227f609cSHerve Codina SND_SOC_DAPM_DAC("ADC0", "Capture", SND_SOC_NOPM, 0, 0), 603227f609cSHerve Codina SND_SOC_DAPM_DAC("ADC1", "Capture", SND_SOC_NOPM, 0, 0), 604227f609cSHerve Codina SND_SOC_DAPM_DAC("ADC2", "Capture", SND_SOC_NOPM, 0, 0), 605227f609cSHerve Codina SND_SOC_DAPM_DAC("ADC3", "Capture", SND_SOC_NOPM, 0, 0), 606227f609cSHerve Codina }; 607227f609cSHerve Codina 608227f609cSHerve Codina static const struct snd_soc_dapm_route peb2466_dapm_routes[] = { 609227f609cSHerve Codina { "CH0 DIN", NULL, "CH0 PWR" }, 610227f609cSHerve Codina { "CH1 DIN", NULL, "CH1 PWR" }, 611227f609cSHerve Codina { "CH2 DIN", NULL, "CH2 PWR" }, 612227f609cSHerve Codina { "CH3 DIN", NULL, "CH3 PWR" }, 613227f609cSHerve Codina 614227f609cSHerve Codina { "CH0 TG1", NULL, "CH0 PWR" }, 615227f609cSHerve Codina { "CH1 TG1", NULL, "CH1 PWR" }, 616227f609cSHerve Codina { "CH2 TG1", NULL, "CH2 PWR" }, 617227f609cSHerve Codina { "CH3 TG1", NULL, "CH3 PWR" }, 618227f609cSHerve Codina 619227f609cSHerve Codina { "CH0 TG2", NULL, "CH0 PWR" }, 620227f609cSHerve Codina { "CH1 TG2", NULL, "CH1 PWR" }, 621227f609cSHerve Codina { "CH2 TG2", NULL, "CH2 PWR" }, 622227f609cSHerve Codina { "CH3 TG2", NULL, "CH3 PWR" }, 623227f609cSHerve Codina 624227f609cSHerve Codina { "DAC0 Mixer", "TG1 Switch", "CH0 TG1" }, 625227f609cSHerve Codina { "DAC0 Mixer", "TG2 Switch", "CH0 TG2" }, 626227f609cSHerve Codina { "DAC0 Mixer", "Voice Switch", "CH0 DIN" }, 627227f609cSHerve Codina { "DAC0 Mixer", NULL, "CH0 DIN" }, 628227f609cSHerve Codina 629227f609cSHerve Codina { "DAC1 Mixer", "TG1 Switch", "CH1 TG1" }, 630227f609cSHerve Codina { "DAC1 Mixer", "TG2 Switch", "CH1 TG2" }, 631227f609cSHerve Codina { "DAC1 Mixer", "Voice Switch", "CH1 DIN" }, 632227f609cSHerve Codina { "DAC1 Mixer", NULL, "CH1 DIN" }, 633227f609cSHerve Codina 634227f609cSHerve Codina { "DAC2 Mixer", "TG1 Switch", "CH2 TG1" }, 635227f609cSHerve Codina { "DAC2 Mixer", "TG2 Switch", "CH2 TG2" }, 636227f609cSHerve Codina { "DAC2 Mixer", "Voice Switch", "CH2 DIN" }, 637227f609cSHerve Codina { "DAC2 Mixer", NULL, "CH2 DIN" }, 638227f609cSHerve Codina 639227f609cSHerve Codina { "DAC3 Mixer", "TG1 Switch", "CH3 TG1" }, 640227f609cSHerve Codina { "DAC3 Mixer", "TG2 Switch", "CH3 TG2" }, 641227f609cSHerve Codina { "DAC3 Mixer", "Voice Switch", "CH3 DIN" }, 642227f609cSHerve Codina { "DAC3 Mixer", NULL, "CH3 DIN" }, 643227f609cSHerve Codina 644227f609cSHerve Codina { "DAC0 PGA", NULL, "DAC0 Mixer" }, 645227f609cSHerve Codina { "DAC1 PGA", NULL, "DAC1 Mixer" }, 646227f609cSHerve Codina { "DAC2 PGA", NULL, "DAC2 Mixer" }, 647227f609cSHerve Codina { "DAC3 PGA", NULL, "DAC3 Mixer" }, 648227f609cSHerve Codina 649227f609cSHerve Codina { "OUT0", NULL, "DAC0 PGA" }, 650227f609cSHerve Codina { "OUT1", NULL, "DAC1 PGA" }, 651227f609cSHerve Codina { "OUT2", NULL, "DAC2 PGA" }, 652227f609cSHerve Codina { "OUT3", NULL, "DAC3 PGA" }, 653227f609cSHerve Codina 654227f609cSHerve Codina { "ADC0", NULL, "IN0" }, 655227f609cSHerve Codina { "ADC1", NULL, "IN1" }, 656227f609cSHerve Codina { "ADC2", NULL, "IN2" }, 657227f609cSHerve Codina { "ADC3", NULL, "IN3" }, 658227f609cSHerve Codina 659227f609cSHerve Codina { "ADC0", NULL, "CH0 PWR" }, 660227f609cSHerve Codina { "ADC1", NULL, "CH1 PWR" }, 661227f609cSHerve Codina { "ADC2", NULL, "CH2 PWR" }, 662227f609cSHerve Codina { "ADC3", NULL, "CH3 PWR" }, 663227f609cSHerve Codina }; 664227f609cSHerve Codina 665227f609cSHerve Codina static int peb2466_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 666227f609cSHerve Codina unsigned int rx_mask, int slots, int width) 667227f609cSHerve Codina { 668227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 669227f609cSHerve Codina unsigned int chan; 670227f609cSHerve Codina unsigned int mask; 671227f609cSHerve Codina u8 slot; 672227f609cSHerve Codina int ret; 673227f609cSHerve Codina 674227f609cSHerve Codina switch (width) { 675227f609cSHerve Codina case 0: 676227f609cSHerve Codina /* Not set -> default 8 */ 677227f609cSHerve Codina case 8: 678227f609cSHerve Codina break; 679227f609cSHerve Codina default: 680227f609cSHerve Codina dev_err(dai->dev, "tdm slot width %d not supported\n", width); 681227f609cSHerve Codina return -EINVAL; 682227f609cSHerve Codina } 683227f609cSHerve Codina 684227f609cSHerve Codina mask = tx_mask; 685227f609cSHerve Codina slot = 0; 686227f609cSHerve Codina chan = 0; 687227f609cSHerve Codina while (mask && chan < PEB2466_NB_CHANNEL) { 688227f609cSHerve Codina if (mask & 0x1) { 689227f609cSHerve Codina ret = regmap_write(peb2466->regmap, PEB2466_CR5(chan), slot); 690227f609cSHerve Codina if (ret) { 691227f609cSHerve Codina dev_err(dai->dev, "chan %d set tx tdm slot failed (%d)\n", 692227f609cSHerve Codina chan, ret); 693227f609cSHerve Codina return ret; 694227f609cSHerve Codina } 695227f609cSHerve Codina chan++; 696227f609cSHerve Codina } 697227f609cSHerve Codina mask >>= 1; 698227f609cSHerve Codina slot++; 699227f609cSHerve Codina } 700227f609cSHerve Codina if (mask) { 701227f609cSHerve Codina dev_err(dai->dev, "too much tx slots defined (mask = 0x%x) support max %d\n", 702227f609cSHerve Codina tx_mask, PEB2466_NB_CHANNEL); 703227f609cSHerve Codina return -EINVAL; 704227f609cSHerve Codina } 705227f609cSHerve Codina peb2466->max_chan_playback = chan; 706227f609cSHerve Codina 707227f609cSHerve Codina mask = rx_mask; 708227f609cSHerve Codina slot = 0; 709227f609cSHerve Codina chan = 0; 710227f609cSHerve Codina while (mask && chan < PEB2466_NB_CHANNEL) { 711227f609cSHerve Codina if (mask & 0x1) { 712227f609cSHerve Codina ret = regmap_write(peb2466->regmap, PEB2466_CR4(chan), slot); 713227f609cSHerve Codina if (ret) { 714227f609cSHerve Codina dev_err(dai->dev, "chan %d set rx tdm slot failed (%d)\n", 715227f609cSHerve Codina chan, ret); 716227f609cSHerve Codina return ret; 717227f609cSHerve Codina } 718227f609cSHerve Codina chan++; 719227f609cSHerve Codina } 720227f609cSHerve Codina mask >>= 1; 721227f609cSHerve Codina slot++; 722227f609cSHerve Codina } 723227f609cSHerve Codina if (mask) { 724227f609cSHerve Codina dev_err(dai->dev, "too much rx slots defined (mask = 0x%x) support max %d\n", 725227f609cSHerve Codina rx_mask, PEB2466_NB_CHANNEL); 726227f609cSHerve Codina return -EINVAL; 727227f609cSHerve Codina } 728227f609cSHerve Codina peb2466->max_chan_capture = chan; 729227f609cSHerve Codina 730227f609cSHerve Codina return 0; 731227f609cSHerve Codina } 732227f609cSHerve Codina 733227f609cSHerve Codina static int peb2466_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 734227f609cSHerve Codina { 735227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 736227f609cSHerve Codina u8 xr6; 737227f609cSHerve Codina 738227f609cSHerve Codina switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 739227f609cSHerve Codina case SND_SOC_DAIFMT_DSP_A: 740227f609cSHerve Codina xr6 = PEB2466_XR6_PCM_OFFSET(1); 741227f609cSHerve Codina break; 742227f609cSHerve Codina case SND_SOC_DAIFMT_DSP_B: 743227f609cSHerve Codina xr6 = PEB2466_XR6_PCM_OFFSET(0); 744227f609cSHerve Codina break; 745227f609cSHerve Codina default: 746227f609cSHerve Codina dev_err(dai->dev, "Unsupported format 0x%x\n", 747227f609cSHerve Codina fmt & SND_SOC_DAIFMT_FORMAT_MASK); 748227f609cSHerve Codina return -EINVAL; 749227f609cSHerve Codina } 750227f609cSHerve Codina return regmap_write(peb2466->regmap, PEB2466_XR6, xr6); 751227f609cSHerve Codina } 752227f609cSHerve Codina 753227f609cSHerve Codina static int peb2466_dai_hw_params(struct snd_pcm_substream *substream, 754227f609cSHerve Codina struct snd_pcm_hw_params *params, 755227f609cSHerve Codina struct snd_soc_dai *dai) 756227f609cSHerve Codina { 757227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 758227f609cSHerve Codina unsigned int ch; 759227f609cSHerve Codina int ret; 760227f609cSHerve Codina u8 cr1; 761227f609cSHerve Codina 762227f609cSHerve Codina switch (params_format(params)) { 763227f609cSHerve Codina case SNDRV_PCM_FORMAT_MU_LAW: 764227f609cSHerve Codina cr1 = PEB2466_CR1_LAW_MULAW; 765227f609cSHerve Codina break; 766227f609cSHerve Codina case SNDRV_PCM_FORMAT_A_LAW: 767227f609cSHerve Codina cr1 = PEB2466_CR1_LAW_ALAW; 768227f609cSHerve Codina break; 769227f609cSHerve Codina default: 770227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Unsupported format 0x%x\n", 771227f609cSHerve Codina params_format(params)); 772227f609cSHerve Codina return -EINVAL; 773227f609cSHerve Codina } 774227f609cSHerve Codina 775227f609cSHerve Codina for (ch = 0; ch < PEB2466_NB_CHANNEL; ch++) { 776227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR1(ch), 777227f609cSHerve Codina PEB2466_CR1_LAW_MASK, cr1); 778227f609cSHerve Codina if (ret) 779227f609cSHerve Codina return ret; 780227f609cSHerve Codina } 781227f609cSHerve Codina 782227f609cSHerve Codina return 0; 783227f609cSHerve Codina } 784227f609cSHerve Codina 785227f609cSHerve Codina static const unsigned int peb2466_sample_bits[] = {8}; 786227f609cSHerve Codina 787227f609cSHerve Codina static struct snd_pcm_hw_constraint_list peb2466_sample_bits_constr = { 788227f609cSHerve Codina .list = peb2466_sample_bits, 789227f609cSHerve Codina .count = ARRAY_SIZE(peb2466_sample_bits), 790227f609cSHerve Codina }; 791227f609cSHerve Codina 792227f609cSHerve Codina static int peb2466_dai_startup(struct snd_pcm_substream *substream, 793227f609cSHerve Codina struct snd_soc_dai *dai) 794227f609cSHerve Codina { 795227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 796227f609cSHerve Codina unsigned int max_ch; 797227f609cSHerve Codina int ret; 798227f609cSHerve Codina 799227f609cSHerve Codina max_ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 800227f609cSHerve Codina peb2466->max_chan_playback : peb2466->max_chan_capture; 801227f609cSHerve Codina 802227f609cSHerve Codina /* 803227f609cSHerve Codina * Disable stream support (min = 0, max = 0) if no timeslots were 804227f609cSHerve Codina * configured. 805227f609cSHerve Codina */ 806227f609cSHerve Codina ret = snd_pcm_hw_constraint_minmax(substream->runtime, 807227f609cSHerve Codina SNDRV_PCM_HW_PARAM_CHANNELS, 808227f609cSHerve Codina max_ch ? 1 : 0, max_ch); 809227f609cSHerve Codina if (ret < 0) 810227f609cSHerve Codina return ret; 811227f609cSHerve Codina 812227f609cSHerve Codina return snd_pcm_hw_constraint_list(substream->runtime, 0, 813227f609cSHerve Codina SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 814227f609cSHerve Codina &peb2466_sample_bits_constr); 815227f609cSHerve Codina } 816227f609cSHerve Codina 817595265c9SKrzysztof Kozlowski static const u64 peb2466_dai_formats[] = { 818227f609cSHerve Codina SND_SOC_POSSIBLE_DAIFMT_DSP_A | 819227f609cSHerve Codina SND_SOC_POSSIBLE_DAIFMT_DSP_B, 820227f609cSHerve Codina }; 821227f609cSHerve Codina 822227f609cSHerve Codina static const struct snd_soc_dai_ops peb2466_dai_ops = { 823227f609cSHerve Codina .startup = peb2466_dai_startup, 824227f609cSHerve Codina .hw_params = peb2466_dai_hw_params, 825227f609cSHerve Codina .set_tdm_slot = peb2466_dai_set_tdm_slot, 826227f609cSHerve Codina .set_fmt = peb2466_dai_set_fmt, 827227f609cSHerve Codina .auto_selectable_formats = peb2466_dai_formats, 828227f609cSHerve Codina .num_auto_selectable_formats = ARRAY_SIZE(peb2466_dai_formats), 829227f609cSHerve Codina }; 830227f609cSHerve Codina 831227f609cSHerve Codina static struct snd_soc_dai_driver peb2466_dai_driver = { 832227f609cSHerve Codina .name = "peb2466", 833227f609cSHerve Codina .playback = { 834227f609cSHerve Codina .stream_name = "Playback", 835227f609cSHerve Codina .channels_min = 1, 836227f609cSHerve Codina .channels_max = PEB2466_NB_CHANNEL, 837227f609cSHerve Codina .rates = SNDRV_PCM_RATE_8000, 838227f609cSHerve Codina .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, 839227f609cSHerve Codina }, 840227f609cSHerve Codina .capture = { 841227f609cSHerve Codina .stream_name = "Capture", 842227f609cSHerve Codina .channels_min = 1, 843227f609cSHerve Codina .channels_max = PEB2466_NB_CHANNEL, 844227f609cSHerve Codina .rates = SNDRV_PCM_RATE_8000, 845227f609cSHerve Codina .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, 846227f609cSHerve Codina }, 847227f609cSHerve Codina .ops = &peb2466_dai_ops, 848227f609cSHerve Codina }; 849227f609cSHerve Codina 850227f609cSHerve Codina static int peb2466_reset_audio(struct peb2466 *peb2466) 851227f609cSHerve Codina { 852227f609cSHerve Codina static const struct reg_sequence reg_reset[] = { 853227f609cSHerve Codina { .reg = PEB2466_XR6, .def = 0x00 }, 854227f609cSHerve Codina 855227f609cSHerve Codina { .reg = PEB2466_CR5(0), .def = 0x00 }, 856227f609cSHerve Codina { .reg = PEB2466_CR4(0), .def = 0x00 }, 857227f609cSHerve Codina { .reg = PEB2466_CR3(0), .def = 0x00 }, 858227f609cSHerve Codina { .reg = PEB2466_CR2(0), .def = 0x00 }, 859227f609cSHerve Codina { .reg = PEB2466_CR1(0), .def = 0x00 }, 860227f609cSHerve Codina { .reg = PEB2466_CR0(0), .def = PEB2466_CR0_IMR1 }, 861227f609cSHerve Codina 862227f609cSHerve Codina { .reg = PEB2466_CR5(1), .def = 0x00 }, 863227f609cSHerve Codina { .reg = PEB2466_CR4(1), .def = 0x00 }, 864227f609cSHerve Codina { .reg = PEB2466_CR3(1), .def = 0x00 }, 865227f609cSHerve Codina { .reg = PEB2466_CR2(1), .def = 0x00 }, 866227f609cSHerve Codina { .reg = PEB2466_CR1(1), .def = 0x00 }, 867227f609cSHerve Codina { .reg = PEB2466_CR0(1), .def = PEB2466_CR0_IMR1 }, 868227f609cSHerve Codina 869227f609cSHerve Codina { .reg = PEB2466_CR5(2), .def = 0x00 }, 870227f609cSHerve Codina { .reg = PEB2466_CR4(2), .def = 0x00 }, 871227f609cSHerve Codina { .reg = PEB2466_CR3(2), .def = 0x00 }, 872227f609cSHerve Codina { .reg = PEB2466_CR2(2), .def = 0x00 }, 873227f609cSHerve Codina { .reg = PEB2466_CR1(2), .def = 0x00 }, 874227f609cSHerve Codina { .reg = PEB2466_CR0(2), .def = PEB2466_CR0_IMR1 }, 875227f609cSHerve Codina 876227f609cSHerve Codina { .reg = PEB2466_CR5(3), .def = 0x00 }, 877227f609cSHerve Codina { .reg = PEB2466_CR4(3), .def = 0x00 }, 878227f609cSHerve Codina { .reg = PEB2466_CR3(3), .def = 0x00 }, 879227f609cSHerve Codina { .reg = PEB2466_CR2(3), .def = 0x00 }, 880227f609cSHerve Codina { .reg = PEB2466_CR1(3), .def = 0x00 }, 881227f609cSHerve Codina { .reg = PEB2466_CR0(3), .def = PEB2466_CR0_IMR1 }, 882227f609cSHerve Codina }; 883227f609cSHerve Codina static const u8 imr1_p1[8] = {0x00, 0x90, 0x09, 0x00, 0x90, 0x09, 0x00, 0x00}; 884227f609cSHerve Codina static const u8 imr1_p2[8] = {0x7F, 0xFF, 0x00, 0x00, 0x90, 0x14, 0x40, 0x08}; 885227f609cSHerve Codina static const u8 zero[8] = {0}; 886227f609cSHerve Codina int ret; 887227f609cSHerve Codina int i; 888227f609cSHerve Codina 889227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 890227f609cSHerve Codina peb2466->ch[i].tg1_freq_item = PEB2466_TONE_1000HZ; 891227f609cSHerve Codina peb2466->ch[i].tg2_freq_item = PEB2466_TONE_1000HZ; 892227f609cSHerve Codina 893227f609cSHerve Codina /* 894227f609cSHerve Codina * Even if not used, disabling IM/R1 filter is not recommended. 895227f609cSHerve Codina * Instead, we must configure it with default coefficients and 896227f609cSHerve Codina * enable it. 897227f609cSHerve Codina * The filter will be enabled right after (in the following 898227f609cSHerve Codina * regmap_multi_reg_write() call). 899227f609cSHerve Codina */ 900227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), imr1_p1, 8); 901227f609cSHerve Codina if (ret) 902227f609cSHerve Codina return ret; 903227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), imr1_p2, 8); 904227f609cSHerve Codina if (ret) 905227f609cSHerve Codina return ret; 906227f609cSHerve Codina 907227f609cSHerve Codina /* Set all other filters coefficients to zero */ 908227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), zero, 8); 909227f609cSHerve Codina if (ret) 910227f609cSHerve Codina return ret; 911227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), zero, 8); 912227f609cSHerve Codina if (ret) 913227f609cSHerve Codina return ret; 914227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), zero, 8); 915227f609cSHerve Codina if (ret) 916227f609cSHerve Codina return ret; 917227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), zero, 8); 918227f609cSHerve Codina if (ret) 919227f609cSHerve Codina return ret; 920227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), zero, 8); 921227f609cSHerve Codina if (ret) 922227f609cSHerve Codina return ret; 923227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), zero, 4); 924227f609cSHerve Codina if (ret) 925227f609cSHerve Codina return ret; 926227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), zero, 4); 927227f609cSHerve Codina if (ret) 928227f609cSHerve Codina return ret; 929227f609cSHerve Codina } 930227f609cSHerve Codina 931227f609cSHerve Codina return regmap_multi_reg_write(peb2466->regmap, reg_reset, ARRAY_SIZE(reg_reset)); 932227f609cSHerve Codina } 933227f609cSHerve Codina 934227f609cSHerve Codina static int peb2466_fw_parse_thfilter(struct snd_soc_component *component, 935227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 936227f609cSHerve Codina { 937227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 938227f609cSHerve Codina u8 mask; 939227f609cSHerve Codina int ret; 940227f609cSHerve Codina int i; 941227f609cSHerve Codina 942227f609cSHerve Codina dev_info(component->dev, "fw TH filter: mask %x, %*phN\n", *data, 943227f609cSHerve Codina lng - 1, data + 1); 944227f609cSHerve Codina 945227f609cSHerve Codina /* 946227f609cSHerve Codina * TH_FILTER TLV data: 947227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 948227f609cSHerve Codina * - @1 8 bytes: TH-Filter coefficients part1 949227f609cSHerve Codina * - @9 8 bytes: TH-Filter coefficients part2 950227f609cSHerve Codina * - @17 8 bytes: TH-Filter coefficients part3 951227f609cSHerve Codina */ 952227f609cSHerve Codina mask = *data; 953227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 954227f609cSHerve Codina if (!(mask & (1 << i))) 955227f609cSHerve Codina continue; 956227f609cSHerve Codina 957227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 958227f609cSHerve Codina PEB2466_CR0_TH, 0); 959227f609cSHerve Codina if (ret) 960227f609cSHerve Codina return ret; 961227f609cSHerve Codina 962227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), data + 1, 8); 963227f609cSHerve Codina if (ret) 964227f609cSHerve Codina return ret; 965227f609cSHerve Codina 966227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), data + 9, 8); 967227f609cSHerve Codina if (ret) 968227f609cSHerve Codina return ret; 969227f609cSHerve Codina 970227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), data + 17, 8); 971227f609cSHerve Codina if (ret) 972227f609cSHerve Codina return ret; 973227f609cSHerve Codina 974227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 975227f609cSHerve Codina PEB2466_CR0_TH | PEB2466_CR0_THSEL_MASK, 976227f609cSHerve Codina PEB2466_CR0_TH | PEB2466_CR0_THSEL(i)); 977227f609cSHerve Codina if (ret) 978227f609cSHerve Codina return ret; 979227f609cSHerve Codina } 980227f609cSHerve Codina return 0; 981227f609cSHerve Codina } 982227f609cSHerve Codina 983227f609cSHerve Codina static int peb2466_fw_parse_imr1filter(struct snd_soc_component *component, 984227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 985227f609cSHerve Codina { 986227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 987227f609cSHerve Codina u8 mask; 988227f609cSHerve Codina int ret; 989227f609cSHerve Codina int i; 990227f609cSHerve Codina 991227f609cSHerve Codina dev_info(component->dev, "fw IM/R1 filter: mask %x, %*phN\n", *data, 992227f609cSHerve Codina lng - 1, data + 1); 993227f609cSHerve Codina 994227f609cSHerve Codina /* 995227f609cSHerve Codina * IMR1_FILTER TLV data: 996227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 997227f609cSHerve Codina * - @1 8 bytes: IM/R1-Filter coefficients part1 998227f609cSHerve Codina * - @9 8 bytes: IM/R1-Filter coefficients part2 999227f609cSHerve Codina */ 1000227f609cSHerve Codina mask = *data; 1001227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1002227f609cSHerve Codina if (!(mask & (1 << i))) 1003227f609cSHerve Codina continue; 1004227f609cSHerve Codina 1005227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1006227f609cSHerve Codina PEB2466_CR0_IMR1, 0); 1007227f609cSHerve Codina if (ret) 1008227f609cSHerve Codina return ret; 1009227f609cSHerve Codina 1010227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), data + 1, 8); 1011227f609cSHerve Codina if (ret) 1012227f609cSHerve Codina return ret; 1013227f609cSHerve Codina 1014227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), data + 9, 8); 1015227f609cSHerve Codina if (ret) 1016227f609cSHerve Codina return ret; 1017227f609cSHerve Codina 1018227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1019227f609cSHerve Codina PEB2466_CR0_IMR1, PEB2466_CR0_IMR1); 1020227f609cSHerve Codina if (ret) 1021227f609cSHerve Codina return ret; 1022227f609cSHerve Codina } 1023227f609cSHerve Codina return 0; 1024227f609cSHerve Codina } 1025227f609cSHerve Codina 1026227f609cSHerve Codina static int peb2466_fw_parse_frxfilter(struct snd_soc_component *component, 1027227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1028227f609cSHerve Codina { 1029227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1030227f609cSHerve Codina u8 mask; 1031227f609cSHerve Codina int ret; 1032227f609cSHerve Codina int i; 1033227f609cSHerve Codina 1034227f609cSHerve Codina dev_info(component->dev, "fw FRX filter: mask %x, %*phN\n", *data, 1035227f609cSHerve Codina lng - 1, data + 1); 1036227f609cSHerve Codina 1037227f609cSHerve Codina /* 1038227f609cSHerve Codina * FRX_FILTER TLV data: 1039227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1040227f609cSHerve Codina * - @1 8 bytes: FRX-Filter coefficients 1041227f609cSHerve Codina */ 1042227f609cSHerve Codina mask = *data; 1043227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1044227f609cSHerve Codina if (!(mask & (1 << i))) 1045227f609cSHerve Codina continue; 1046227f609cSHerve Codina 1047227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1048227f609cSHerve Codina PEB2466_CR0_FRX, 0); 1049227f609cSHerve Codina if (ret) 1050227f609cSHerve Codina return ret; 1051227f609cSHerve Codina 1052227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), data + 1, 8); 1053227f609cSHerve Codina if (ret) 1054227f609cSHerve Codina return ret; 1055227f609cSHerve Codina 1056227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1057227f609cSHerve Codina PEB2466_CR0_FRX, PEB2466_CR0_FRX); 1058227f609cSHerve Codina if (ret) 1059227f609cSHerve Codina return ret; 1060227f609cSHerve Codina } 1061227f609cSHerve Codina return 0; 1062227f609cSHerve Codina } 1063227f609cSHerve Codina 1064227f609cSHerve Codina static int peb2466_fw_parse_frrfilter(struct snd_soc_component *component, 1065227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1066227f609cSHerve Codina { 1067227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1068227f609cSHerve Codina u8 mask; 1069227f609cSHerve Codina int ret; 1070227f609cSHerve Codina int i; 1071227f609cSHerve Codina 1072227f609cSHerve Codina dev_info(component->dev, "fw FRR filter: mask %x, %*phN\n", *data, 1073227f609cSHerve Codina lng - 1, data + 1); 1074227f609cSHerve Codina 1075227f609cSHerve Codina /* 1076227f609cSHerve Codina * FRR_FILTER TLV data: 1077227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1078227f609cSHerve Codina * - @1 8 bytes: FRR-Filter coefficients 1079227f609cSHerve Codina */ 1080227f609cSHerve Codina mask = *data; 1081227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1082227f609cSHerve Codina if (!(mask & (1 << i))) 1083227f609cSHerve Codina continue; 1084227f609cSHerve Codina 1085227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1086227f609cSHerve Codina PEB2466_CR0_FRR, 0); 1087227f609cSHerve Codina if (ret) 1088227f609cSHerve Codina return ret; 1089227f609cSHerve Codina 1090227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), data + 1, 8); 1091227f609cSHerve Codina if (ret) 1092227f609cSHerve Codina return ret; 1093227f609cSHerve Codina 1094227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1095227f609cSHerve Codina PEB2466_CR0_FRR, PEB2466_CR0_FRR); 1096227f609cSHerve Codina if (ret) 1097227f609cSHerve Codina return ret; 1098227f609cSHerve Codina } 1099227f609cSHerve Codina return 0; 1100227f609cSHerve Codina } 1101227f609cSHerve Codina 1102227f609cSHerve Codina static int peb2466_fw_parse_axfilter(struct snd_soc_component *component, 1103227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1104227f609cSHerve Codina { 1105227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1106227f609cSHerve Codina u8 mask; 1107227f609cSHerve Codina int ret; 1108227f609cSHerve Codina int i; 1109227f609cSHerve Codina 1110227f609cSHerve Codina dev_info(component->dev, "fw AX filter: mask %x, %*phN\n", *data, 1111227f609cSHerve Codina lng - 1, data + 1); 1112227f609cSHerve Codina 1113227f609cSHerve Codina /* 1114227f609cSHerve Codina * AX_FILTER TLV data: 1115227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1116227f609cSHerve Codina * - @1 4 bytes: AX-Filter coefficients 1117227f609cSHerve Codina */ 1118227f609cSHerve Codina mask = *data; 1119227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1120227f609cSHerve Codina if (!(mask & (1 << i))) 1121227f609cSHerve Codina continue; 1122227f609cSHerve Codina 1123227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1124227f609cSHerve Codina PEB2466_CR0_AX, 0); 1125227f609cSHerve Codina if (ret) 1126227f609cSHerve Codina return ret; 1127227f609cSHerve Codina 1128227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), data + 1, 4); 1129227f609cSHerve Codina if (ret) 1130227f609cSHerve Codina return ret; 1131227f609cSHerve Codina 1132227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1133227f609cSHerve Codina PEB2466_CR0_AX, PEB2466_CR0_AX); 1134227f609cSHerve Codina if (ret) 1135227f609cSHerve Codina return ret; 1136227f609cSHerve Codina } 1137227f609cSHerve Codina return 0; 1138227f609cSHerve Codina } 1139227f609cSHerve Codina 1140227f609cSHerve Codina static int peb2466_fw_parse_arfilter(struct snd_soc_component *component, 1141227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1142227f609cSHerve Codina { 1143227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1144227f609cSHerve Codina u8 mask; 1145227f609cSHerve Codina int ret; 1146227f609cSHerve Codina int i; 1147227f609cSHerve Codina 1148227f609cSHerve Codina dev_info(component->dev, "fw AR filter: mask %x, %*phN\n", *data, 1149227f609cSHerve Codina lng - 1, data + 1); 1150227f609cSHerve Codina 1151227f609cSHerve Codina /* 1152227f609cSHerve Codina * AR_FILTER TLV data: 1153227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1154227f609cSHerve Codina * - @1 4 bytes: AR-Filter coefficients 1155227f609cSHerve Codina */ 1156227f609cSHerve Codina mask = *data; 1157227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1158227f609cSHerve Codina if (!(mask & (1 << i))) 1159227f609cSHerve Codina continue; 1160227f609cSHerve Codina 1161227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1162227f609cSHerve Codina PEB2466_CR0_AR, 0); 1163227f609cSHerve Codina if (ret) 1164227f609cSHerve Codina return ret; 1165227f609cSHerve Codina 1166227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), data + 1, 4); 1167227f609cSHerve Codina if (ret) 1168227f609cSHerve Codina return ret; 1169227f609cSHerve Codina 1170227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1171227f609cSHerve Codina PEB2466_CR0_AR, PEB2466_CR0_AR); 1172227f609cSHerve Codina if (ret) 1173227f609cSHerve Codina return ret; 1174227f609cSHerve Codina } 1175227f609cSHerve Codina return 0; 1176227f609cSHerve Codina } 1177227f609cSHerve Codina 1178227f609cSHerve Codina static const char * const peb2466_ax_ctrl_names[] = { 1179227f609cSHerve Codina "ADC0 Capture Volume", 1180227f609cSHerve Codina "ADC1 Capture Volume", 1181227f609cSHerve Codina "ADC2 Capture Volume", 1182227f609cSHerve Codina "ADC3 Capture Volume", 1183227f609cSHerve Codina }; 1184227f609cSHerve Codina 1185227f609cSHerve Codina static int peb2466_fw_parse_axtable(struct snd_soc_component *component, 1186227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1187227f609cSHerve Codina { 1188227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1189227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl; 1190227f609cSHerve Codina struct peb2466_lookup *lookup; 1191227f609cSHerve Codina u8 (*table)[4]; 1192227f609cSHerve Codina u32 table_size; 1193227f609cSHerve Codina u32 init_index; 1194227f609cSHerve Codina s32 min_val; 1195227f609cSHerve Codina s32 step; 1196227f609cSHerve Codina u8 mask; 1197227f609cSHerve Codina int ret; 1198227f609cSHerve Codina int i; 1199227f609cSHerve Codina 1200227f609cSHerve Codina /* 1201227f609cSHerve Codina * AX_TABLE TLV data: 1202227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1203227f609cSHerve Codina * - @1 32bits signed: Min table value in centi dB (MinVal) 1204227f609cSHerve Codina * ie -300 means -3.0 dB 1205227f609cSHerve Codina * - @5 32bits signed: Step from on item to other item in centi dB (Step) 1206227f609cSHerve Codina * ie 25 means 0.25 dB) 1207227f609cSHerve Codina * - @9 32bits unsigned: Item index in the table to use for the initial 1208227f609cSHerve Codina * value 1209227f609cSHerve Codina * - @13 N*4 bytes: Table composed of 4 bytes items. 1210227f609cSHerve Codina * Each item correspond to an AX filter value. 1211227f609cSHerve Codina * 1212227f609cSHerve Codina * The conversion from raw value item in the table to/from the value in 1213227f609cSHerve Codina * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. 1214227f609cSHerve Codina */ 1215227f609cSHerve Codina 1216227f609cSHerve Codina /* Check Lng and extract the table size. */ 1217227f609cSHerve Codina if (lng < 13 || ((lng - 13) % 4)) { 1218227f609cSHerve Codina dev_err(component->dev, "fw AX table lng %u invalid\n", lng); 1219227f609cSHerve Codina return -EINVAL; 1220227f609cSHerve Codina } 1221227f609cSHerve Codina table_size = lng - 13; 1222227f609cSHerve Codina 1223227f609cSHerve Codina min_val = get_unaligned_be32(data + 1); 1224227f609cSHerve Codina step = get_unaligned_be32(data + 5); 1225227f609cSHerve Codina init_index = get_unaligned_be32(data + 9); 1226227f609cSHerve Codina if (init_index >= (table_size / 4)) { 1227227f609cSHerve Codina dev_err(component->dev, "fw AX table index %u out of table[%u]\n", 1228227f609cSHerve Codina init_index, table_size / 4); 1229227f609cSHerve Codina return -EINVAL; 1230227f609cSHerve Codina } 1231227f609cSHerve Codina 1232227f609cSHerve Codina dev_info(component->dev, 1233227f609cSHerve Codina "fw AX table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n", 1234227f609cSHerve Codina *data, min_val, step, table_size / 4, init_index, 1235227f609cSHerve Codina 4, data + 13 + (init_index * 4)); 1236227f609cSHerve Codina 1237227f609cSHerve Codina BUILD_BUG_ON(sizeof(*table) != 4); 1238227f609cSHerve Codina table = devm_kzalloc(&peb2466->spi->dev, table_size, GFP_KERNEL); 1239227f609cSHerve Codina if (!table) 1240227f609cSHerve Codina return -ENOMEM; 1241227f609cSHerve Codina memcpy(table, data + 13, table_size); 1242227f609cSHerve Codina 1243227f609cSHerve Codina mask = *data; 1244227f609cSHerve Codina BUILD_BUG_ON(ARRAY_SIZE(peb2466_ax_ctrl_names) != ARRAY_SIZE(peb2466->ch)); 1245227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1246227f609cSHerve Codina if (!(mask & (1 << i))) 1247227f609cSHerve Codina continue; 1248227f609cSHerve Codina 1249227f609cSHerve Codina lookup = &peb2466->ch[i].ax_lookup; 1250227f609cSHerve Codina lookup->table = table; 1251227f609cSHerve Codina lookup->count = table_size / 4; 1252227f609cSHerve Codina 1253227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1254227f609cSHerve Codina PEB2466_CR0_AX, 0); 1255227f609cSHerve Codina if (ret) 1256227f609cSHerve Codina return ret; 1257227f609cSHerve Codina 1258227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), 1259227f609cSHerve Codina lookup->table[init_index], 4); 1260227f609cSHerve Codina if (ret) 1261227f609cSHerve Codina return ret; 1262227f609cSHerve Codina 1263227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1264227f609cSHerve Codina PEB2466_CR0_AX, PEB2466_CR0_AX); 1265227f609cSHerve Codina if (ret) 1266227f609cSHerve Codina return ret; 1267227f609cSHerve Codina 1268227f609cSHerve Codina lkup_ctrl = &peb2466->ch[i].ax_lkup_ctrl; 1269227f609cSHerve Codina lkup_ctrl->lookup = lookup; 1270227f609cSHerve Codina lkup_ctrl->reg = PEB2466_AX_FILTER(i); 1271227f609cSHerve Codina lkup_ctrl->index = init_index; 1272227f609cSHerve Codina 1273227f609cSHerve Codina ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, 1274227f609cSHerve Codina peb2466_ax_ctrl_names[i], 1275227f609cSHerve Codina min_val, step); 1276227f609cSHerve Codina if (ret) 1277227f609cSHerve Codina return ret; 1278227f609cSHerve Codina } 1279227f609cSHerve Codina return 0; 1280227f609cSHerve Codina } 1281227f609cSHerve Codina 1282227f609cSHerve Codina static const char * const peb2466_ar_ctrl_names[] = { 1283227f609cSHerve Codina "DAC0 Playback Volume", 1284227f609cSHerve Codina "DAC1 Playback Volume", 1285227f609cSHerve Codina "DAC2 Playback Volume", 1286227f609cSHerve Codina "DAC3 Playback Volume", 1287227f609cSHerve Codina }; 1288227f609cSHerve Codina 1289227f609cSHerve Codina static int peb2466_fw_parse_artable(struct snd_soc_component *component, 1290227f609cSHerve Codina u16 tag, u32 lng, const u8 *data) 1291227f609cSHerve Codina { 1292227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1293227f609cSHerve Codina struct peb2466_lkup_ctrl *lkup_ctrl; 1294227f609cSHerve Codina struct peb2466_lookup *lookup; 1295227f609cSHerve Codina u8 (*table)[4]; 1296227f609cSHerve Codina u32 table_size; 1297227f609cSHerve Codina u32 init_index; 1298227f609cSHerve Codina s32 min_val; 1299227f609cSHerve Codina s32 step; 1300227f609cSHerve Codina u8 mask; 1301227f609cSHerve Codina int ret; 1302227f609cSHerve Codina int i; 1303227f609cSHerve Codina 1304227f609cSHerve Codina /* 1305227f609cSHerve Codina * AR_TABLE TLV data: 1306227f609cSHerve Codina * - @0 1 byte: Chan mask (bit set means related channel is concerned) 1307227f609cSHerve Codina * - @1 32bits signed: Min table value in centi dB (MinVal) 1308227f609cSHerve Codina * ie -300 means -3.0 dB 1309227f609cSHerve Codina * - @5 32bits signed: Step from on item to other item in centi dB (Step) 1310227f609cSHerve Codina * ie 25 means 0.25 dB) 1311227f609cSHerve Codina * - @9 32bits unsigned: Item index in the table to use for the initial 1312227f609cSHerve Codina * value 1313227f609cSHerve Codina * - @13 N*4 bytes: Table composed of 4 bytes items. 1314227f609cSHerve Codina * Each item correspond to an AR filter value. 1315227f609cSHerve Codina * 1316227f609cSHerve Codina * The conversion from raw value item in the table to/from the value in 1317227f609cSHerve Codina * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. 1318227f609cSHerve Codina */ 1319227f609cSHerve Codina 1320227f609cSHerve Codina /* Check Lng and extract the table size. */ 1321227f609cSHerve Codina if (lng < 13 || ((lng - 13) % 4)) { 1322227f609cSHerve Codina dev_err(component->dev, "fw AR table lng %u invalid\n", lng); 1323227f609cSHerve Codina return -EINVAL; 1324227f609cSHerve Codina } 1325227f609cSHerve Codina table_size = lng - 13; 1326227f609cSHerve Codina 1327227f609cSHerve Codina min_val = get_unaligned_be32(data + 1); 1328227f609cSHerve Codina step = get_unaligned_be32(data + 5); 1329227f609cSHerve Codina init_index = get_unaligned_be32(data + 9); 1330227f609cSHerve Codina if (init_index >= (table_size / 4)) { 1331227f609cSHerve Codina dev_err(component->dev, "fw AR table index %u out of table[%u]\n", 1332227f609cSHerve Codina init_index, table_size / 4); 1333227f609cSHerve Codina return -EINVAL; 1334227f609cSHerve Codina } 1335227f609cSHerve Codina 1336227f609cSHerve Codina dev_info(component->dev, 1337227f609cSHerve Codina "fw AR table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n", 1338227f609cSHerve Codina *data, min_val, step, table_size / 4, init_index, 1339227f609cSHerve Codina 4, data + 13 + (init_index * 4)); 1340227f609cSHerve Codina 1341227f609cSHerve Codina BUILD_BUG_ON(sizeof(*table) != 4); 1342227f609cSHerve Codina table = devm_kzalloc(&peb2466->spi->dev, table_size, GFP_KERNEL); 1343227f609cSHerve Codina if (!table) 1344227f609cSHerve Codina return -ENOMEM; 1345227f609cSHerve Codina memcpy(table, data + 13, table_size); 1346227f609cSHerve Codina 1347227f609cSHerve Codina mask = *data; 1348227f609cSHerve Codina BUILD_BUG_ON(ARRAY_SIZE(peb2466_ar_ctrl_names) != ARRAY_SIZE(peb2466->ch)); 1349227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 1350227f609cSHerve Codina if (!(mask & (1 << i))) 1351227f609cSHerve Codina continue; 1352227f609cSHerve Codina 1353227f609cSHerve Codina lookup = &peb2466->ch[i].ar_lookup; 1354227f609cSHerve Codina lookup->table = table; 1355227f609cSHerve Codina lookup->count = table_size / 4; 1356227f609cSHerve Codina 1357227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1358227f609cSHerve Codina PEB2466_CR0_AR, 0); 1359227f609cSHerve Codina if (ret) 1360227f609cSHerve Codina return ret; 1361227f609cSHerve Codina 1362227f609cSHerve Codina ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), 1363227f609cSHerve Codina lookup->table[init_index], 4); 1364227f609cSHerve Codina if (ret) 1365227f609cSHerve Codina return ret; 1366227f609cSHerve Codina 1367227f609cSHerve Codina ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 1368227f609cSHerve Codina PEB2466_CR0_AR, PEB2466_CR0_AR); 1369227f609cSHerve Codina if (ret) 1370227f609cSHerve Codina return ret; 1371227f609cSHerve Codina 1372227f609cSHerve Codina lkup_ctrl = &peb2466->ch[i].ar_lkup_ctrl; 1373227f609cSHerve Codina lkup_ctrl->lookup = lookup; 1374227f609cSHerve Codina lkup_ctrl->reg = PEB2466_AR_FILTER(i); 1375227f609cSHerve Codina lkup_ctrl->index = init_index; 1376227f609cSHerve Codina 1377227f609cSHerve Codina ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, 1378227f609cSHerve Codina peb2466_ar_ctrl_names[i], 1379227f609cSHerve Codina min_val, step); 1380227f609cSHerve Codina if (ret) 1381227f609cSHerve Codina return ret; 1382227f609cSHerve Codina } 1383227f609cSHerve Codina return 0; 1384227f609cSHerve Codina } 1385227f609cSHerve Codina 1386227f609cSHerve Codina struct peb2466_fw_tag_def { 1387227f609cSHerve Codina u16 tag; 1388227f609cSHerve Codina u32 lng_min; 1389227f609cSHerve Codina u32 lng_max; 1390227f609cSHerve Codina int (*parse)(struct snd_soc_component *component, 1391227f609cSHerve Codina u16 tag, u32 lng, const u8 *data); 1392227f609cSHerve Codina }; 1393227f609cSHerve Codina 1394227f609cSHerve Codina #define PEB2466_TAG_DEF_LNG_EQ(__tag, __lng, __parse) { \ 1395227f609cSHerve Codina .tag = __tag, \ 1396227f609cSHerve Codina .lng_min = __lng, \ 1397227f609cSHerve Codina .lng_max = __lng, \ 1398227f609cSHerve Codina .parse = __parse, \ 1399227f609cSHerve Codina } 1400227f609cSHerve Codina 1401227f609cSHerve Codina #define PEB2466_TAG_DEF_LNG_MIN(__tag, __lng_min, __parse) { \ 1402227f609cSHerve Codina .tag = __tag, \ 1403227f609cSHerve Codina .lng_min = __lng_min, \ 1404227f609cSHerve Codina .lng_max = U32_MAX, \ 1405227f609cSHerve Codina .parse = __parse, \ 1406227f609cSHerve Codina } 1407227f609cSHerve Codina 1408227f609cSHerve Codina static const struct peb2466_fw_tag_def peb2466_fw_tag_defs[] = { 1409227f609cSHerve Codina /* TH FILTER */ 1410227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0001, 1 + 3 * 8, peb2466_fw_parse_thfilter), 1411227f609cSHerve Codina /* IMR1 FILTER */ 1412227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0002, 1 + 2 * 8, peb2466_fw_parse_imr1filter), 1413227f609cSHerve Codina /* FRX FILTER */ 1414227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0003, 1 + 8, peb2466_fw_parse_frxfilter), 1415227f609cSHerve Codina /* FRR FILTER */ 1416227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0004, 1 + 8, peb2466_fw_parse_frrfilter), 1417227f609cSHerve Codina /* AX FILTER */ 1418227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0005, 1 + 4, peb2466_fw_parse_axfilter), 1419227f609cSHerve Codina /* AR FILTER */ 1420227f609cSHerve Codina PEB2466_TAG_DEF_LNG_EQ(0x0006, 1 + 4, peb2466_fw_parse_arfilter), 1421227f609cSHerve Codina /* AX TABLE */ 1422227f609cSHerve Codina PEB2466_TAG_DEF_LNG_MIN(0x0105, 1 + 3 * 4, peb2466_fw_parse_axtable), 1423227f609cSHerve Codina /* AR TABLE */ 1424227f609cSHerve Codina PEB2466_TAG_DEF_LNG_MIN(0x0106, 1 + 3 * 4, peb2466_fw_parse_artable), 1425227f609cSHerve Codina }; 1426227f609cSHerve Codina 1427227f609cSHerve Codina static const struct peb2466_fw_tag_def *peb2466_fw_get_tag_def(u16 tag) 1428227f609cSHerve Codina { 1429227f609cSHerve Codina int i; 1430227f609cSHerve Codina 1431227f609cSHerve Codina for (i = 0; i < ARRAY_SIZE(peb2466_fw_tag_defs); i++) { 1432227f609cSHerve Codina if (peb2466_fw_tag_defs[i].tag == tag) 1433227f609cSHerve Codina return &peb2466_fw_tag_defs[i]; 1434227f609cSHerve Codina } 1435227f609cSHerve Codina return NULL; 1436227f609cSHerve Codina } 1437227f609cSHerve Codina 1438227f609cSHerve Codina static int peb2466_fw_parse(struct snd_soc_component *component, 1439227f609cSHerve Codina const u8 *data, size_t size) 1440227f609cSHerve Codina { 1441227f609cSHerve Codina const struct peb2466_fw_tag_def *tag_def; 1442227f609cSHerve Codina size_t left; 1443227f609cSHerve Codina const u8 *buf; 1444227f609cSHerve Codina u16 val16; 1445227f609cSHerve Codina u16 tag; 1446227f609cSHerve Codina u32 lng; 1447227f609cSHerve Codina int ret; 1448227f609cSHerve Codina 1449227f609cSHerve Codina /* 1450227f609cSHerve Codina * Coefficients firmware binary structure (16bits and 32bits are 1451227f609cSHerve Codina * big-endian values). 1452227f609cSHerve Codina * 1453227f609cSHerve Codina * @0, 16bits: Magic (0x2466) 1454227f609cSHerve Codina * @2, 16bits: Version (0x0100 for version 1.0) 1455227f609cSHerve Codina * @4, 2+4+N bytes: TLV block 1456227f609cSHerve Codina * @4+(2+4+N) bytes: Next TLV block 1457227f609cSHerve Codina * ... 1458227f609cSHerve Codina * 1459227f609cSHerve Codina * Detail of a TLV block: 1460227f609cSHerve Codina * @0, 16bits: Tag 1461227f609cSHerve Codina * @2, 32bits: Lng 1462227f609cSHerve Codina * @6, lng bytes: Data 1463227f609cSHerve Codina * 1464227f609cSHerve Codina * The detail the Data for a given TLV Tag is provided in the related 1465227f609cSHerve Codina * parser. 1466227f609cSHerve Codina */ 1467227f609cSHerve Codina 1468227f609cSHerve Codina left = size; 1469227f609cSHerve Codina buf = data; 1470227f609cSHerve Codina 1471227f609cSHerve Codina if (left < 4) { 1472227f609cSHerve Codina dev_err(component->dev, "fw size %zu, exp at least 4\n", left); 1473227f609cSHerve Codina return -EINVAL; 1474227f609cSHerve Codina } 1475227f609cSHerve Codina 1476227f609cSHerve Codina /* Check magic */ 1477227f609cSHerve Codina val16 = get_unaligned_be16(buf); 1478227f609cSHerve Codina if (val16 != 0x2466) { 1479227f609cSHerve Codina dev_err(component->dev, "fw magic 0x%04x exp 0x2466\n", val16); 1480227f609cSHerve Codina return -EINVAL; 1481227f609cSHerve Codina } 1482227f609cSHerve Codina buf += 2; 1483227f609cSHerve Codina left -= 2; 1484227f609cSHerve Codina 1485227f609cSHerve Codina /* Check version */ 1486227f609cSHerve Codina val16 = get_unaligned_be16(buf); 1487227f609cSHerve Codina if (val16 != 0x0100) { 1488227f609cSHerve Codina dev_err(component->dev, "fw magic 0x%04x exp 0x0100\n", val16); 1489227f609cSHerve Codina return -EINVAL; 1490227f609cSHerve Codina } 1491227f609cSHerve Codina buf += 2; 1492227f609cSHerve Codina left -= 2; 1493227f609cSHerve Codina 1494227f609cSHerve Codina while (left) { 1495227f609cSHerve Codina if (left < 6) { 1496227f609cSHerve Codina dev_err(component->dev, "fw %td/%zu left %zu, exp at least 6\n", 1497227f609cSHerve Codina buf - data, size, left); 1498227f609cSHerve Codina return -EINVAL; 1499227f609cSHerve Codina } 1500227f609cSHerve Codina /* Check tag and lng */ 1501227f609cSHerve Codina tag = get_unaligned_be16(buf); 1502227f609cSHerve Codina lng = get_unaligned_be32(buf + 2); 1503227f609cSHerve Codina tag_def = peb2466_fw_get_tag_def(tag); 1504227f609cSHerve Codina if (!tag_def) { 1505227f609cSHerve Codina dev_err(component->dev, "fw %td/%zu tag 0x%04x unknown\n", 1506227f609cSHerve Codina buf - data, size, tag); 1507227f609cSHerve Codina return -EINVAL; 1508227f609cSHerve Codina } 1509227f609cSHerve Codina if (lng < tag_def->lng_min || lng > tag_def->lng_max) { 1510227f609cSHerve Codina dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, exp [%u;%u]\n", 1511227f609cSHerve Codina buf - data, size, tag, lng, tag_def->lng_min, tag_def->lng_max); 1512227f609cSHerve Codina return -EINVAL; 1513227f609cSHerve Codina } 1514227f609cSHerve Codina buf += 6; 1515227f609cSHerve Codina left -= 6; 1516227f609cSHerve Codina if (left < lng) { 1517227f609cSHerve Codina dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, left %zu\n", 1518227f609cSHerve Codina buf - data, size, tag, lng, left); 1519227f609cSHerve Codina return -EINVAL; 1520227f609cSHerve Codina } 1521227f609cSHerve Codina 1522227f609cSHerve Codina /* TLV block is valid -> parse the data part */ 1523227f609cSHerve Codina ret = tag_def->parse(component, tag, lng, buf); 1524227f609cSHerve Codina if (ret) { 1525227f609cSHerve Codina dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u parse failed\n", 1526227f609cSHerve Codina buf - data, size, tag, lng); 1527227f609cSHerve Codina return ret; 1528227f609cSHerve Codina } 1529227f609cSHerve Codina 1530227f609cSHerve Codina buf += lng; 1531227f609cSHerve Codina left -= lng; 1532227f609cSHerve Codina } 1533227f609cSHerve Codina return 0; 1534227f609cSHerve Codina } 1535227f609cSHerve Codina 1536227f609cSHerve Codina static int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name) 1537227f609cSHerve Codina { 1538227f609cSHerve Codina const struct firmware *fw; 1539227f609cSHerve Codina int ret; 1540227f609cSHerve Codina 1541227f609cSHerve Codina ret = request_firmware(&fw, fw_name, component->dev); 1542227f609cSHerve Codina if (ret) 1543227f609cSHerve Codina return ret; 1544227f609cSHerve Codina 1545227f609cSHerve Codina ret = peb2466_fw_parse(component, fw->data, fw->size); 1546227f609cSHerve Codina release_firmware(fw); 1547227f609cSHerve Codina 1548227f609cSHerve Codina return ret; 1549227f609cSHerve Codina } 1550227f609cSHerve Codina 1551227f609cSHerve Codina static int peb2466_component_probe(struct snd_soc_component *component) 1552227f609cSHerve Codina { 1553227f609cSHerve Codina struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 1554227f609cSHerve Codina const char *firmware_name; 1555227f609cSHerve Codina int ret; 1556227f609cSHerve Codina 1557227f609cSHerve Codina /* reset peb2466 audio part */ 1558227f609cSHerve Codina ret = peb2466_reset_audio(peb2466); 1559227f609cSHerve Codina if (ret) 1560227f609cSHerve Codina return ret; 1561227f609cSHerve Codina 1562227f609cSHerve Codina ret = of_property_read_string(peb2466->spi->dev.of_node, 1563227f609cSHerve Codina "firmware-name", &firmware_name); 1564227f609cSHerve Codina if (ret) 1565227f609cSHerve Codina return (ret == -EINVAL) ? 0 : ret; 1566227f609cSHerve Codina 1567227f609cSHerve Codina return peb2466_load_coeffs(component, firmware_name); 1568227f609cSHerve Codina } 1569227f609cSHerve Codina 1570227f609cSHerve Codina static const struct snd_soc_component_driver peb2466_component_driver = { 1571227f609cSHerve Codina .probe = peb2466_component_probe, 1572227f609cSHerve Codina .controls = peb2466_controls, 1573227f609cSHerve Codina .num_controls = ARRAY_SIZE(peb2466_controls), 1574227f609cSHerve Codina .dapm_widgets = peb2466_dapm_widgets, 1575227f609cSHerve Codina .num_dapm_widgets = ARRAY_SIZE(peb2466_dapm_widgets), 1576227f609cSHerve Codina .dapm_routes = peb2466_dapm_routes, 1577227f609cSHerve Codina .num_dapm_routes = ARRAY_SIZE(peb2466_dapm_routes), 1578227f609cSHerve Codina .endianness = 1, 1579227f609cSHerve Codina }; 1580227f609cSHerve Codina 1581227f609cSHerve Codina /* 1582227f609cSHerve Codina * The mapping used for the relationship between the gpio offset and the 1583227f609cSHerve Codina * physical pin is the following: 1584227f609cSHerve Codina * 1585227f609cSHerve Codina * offset pin 1586227f609cSHerve Codina * 0 SI1_0 1587227f609cSHerve Codina * 1 SI1_1 1588227f609cSHerve Codina * 2 SI2_0 1589227f609cSHerve Codina * 3 SI2_1 1590227f609cSHerve Codina * 4 SI3_0 1591227f609cSHerve Codina * 5 SI3_1 1592227f609cSHerve Codina * 6 SI4_0 1593227f609cSHerve Codina * 7 SI4_1 1594227f609cSHerve Codina * 8 SO1_0 1595227f609cSHerve Codina * 9 SO1_1 1596227f609cSHerve Codina * 10 SO2_0 1597227f609cSHerve Codina * 11 SO2_1 1598227f609cSHerve Codina * 12 SO3_0 1599227f609cSHerve Codina * 13 SO3_1 1600227f609cSHerve Codina * 14 SO4_0 1601227f609cSHerve Codina * 15 SO4_1 1602227f609cSHerve Codina * 16 SB1_0 1603227f609cSHerve Codina * 17 SB1_1 1604227f609cSHerve Codina * 18 SB2_0 1605227f609cSHerve Codina * 19 SB2_1 1606227f609cSHerve Codina * 20 SB3_0 1607227f609cSHerve Codina * 21 SB3_1 1608227f609cSHerve Codina * 22 SB4_0 1609227f609cSHerve Codina * 23 SB4_1 1610227f609cSHerve Codina * 24 SB1_2 1611227f609cSHerve Codina * 25 SB2_2 1612227f609cSHerve Codina * 26 SB3_2 1613227f609cSHerve Codina * 27 SB4_2 1614227f609cSHerve Codina */ 1615227f609cSHerve Codina 1616227f609cSHerve Codina static int peb2466_chip_gpio_offset_to_data_regmask(unsigned int offset, 1617227f609cSHerve Codina unsigned int *xr_reg, 1618227f609cSHerve Codina unsigned int *mask) 1619227f609cSHerve Codina { 1620227f609cSHerve Codina if (offset < 16) { 1621227f609cSHerve Codina /* 1622227f609cSHerve Codina * SIx_{0,1} and SOx_{0,1} 1623227f609cSHerve Codina * Read accesses read SIx_{0,1} values 1624227f609cSHerve Codina * Write accesses write SOx_{0,1} values 1625227f609cSHerve Codina */ 1626227f609cSHerve Codina *xr_reg = PEB2466_XR0; 1627227f609cSHerve Codina *mask = (1 << (offset % 8)); 1628227f609cSHerve Codina return 0; 1629227f609cSHerve Codina } 1630227f609cSHerve Codina if (offset < 24) { 1631227f609cSHerve Codina /* SBx_{0,1} */ 1632227f609cSHerve Codina *xr_reg = PEB2466_XR1; 1633227f609cSHerve Codina *mask = (1 << (offset - 16)); 1634227f609cSHerve Codina return 0; 1635227f609cSHerve Codina } 1636227f609cSHerve Codina if (offset < 28) { 1637227f609cSHerve Codina /* SBx_2 */ 1638227f609cSHerve Codina *xr_reg = PEB2466_XR3; 1639227f609cSHerve Codina *mask = (1 << (offset - 24 + 4)); 1640227f609cSHerve Codina return 0; 1641227f609cSHerve Codina } 1642227f609cSHerve Codina return -EINVAL; 1643227f609cSHerve Codina } 1644227f609cSHerve Codina 1645227f609cSHerve Codina static int peb2466_chip_gpio_offset_to_dir_regmask(unsigned int offset, 1646227f609cSHerve Codina unsigned int *xr_reg, 1647227f609cSHerve Codina unsigned int *mask) 1648227f609cSHerve Codina { 1649227f609cSHerve Codina if (offset < 16) { 1650227f609cSHerve Codina /* Direction cannot be changed for these GPIOs */ 1651227f609cSHerve Codina return -EINVAL; 1652227f609cSHerve Codina } 1653227f609cSHerve Codina if (offset < 24) { 1654227f609cSHerve Codina *xr_reg = PEB2466_XR2; 1655227f609cSHerve Codina *mask = (1 << (offset - 16)); 1656227f609cSHerve Codina return 0; 1657227f609cSHerve Codina } 1658227f609cSHerve Codina if (offset < 28) { 1659227f609cSHerve Codina *xr_reg = PEB2466_XR3; 1660227f609cSHerve Codina *mask = (1 << (offset - 24)); 1661227f609cSHerve Codina return 0; 1662227f609cSHerve Codina } 1663227f609cSHerve Codina return -EINVAL; 1664227f609cSHerve Codina } 1665227f609cSHerve Codina 1666227f609cSHerve Codina static unsigned int *peb2466_chip_gpio_get_cache(struct peb2466 *peb2466, 1667227f609cSHerve Codina unsigned int xr_reg) 1668227f609cSHerve Codina { 1669227f609cSHerve Codina unsigned int *cache; 1670227f609cSHerve Codina 1671227f609cSHerve Codina switch (xr_reg) { 1672227f609cSHerve Codina case PEB2466_XR0: 1673227f609cSHerve Codina cache = &peb2466->gpio.cache.xr0; 1674227f609cSHerve Codina break; 1675227f609cSHerve Codina case PEB2466_XR1: 1676227f609cSHerve Codina cache = &peb2466->gpio.cache.xr1; 1677227f609cSHerve Codina break; 1678227f609cSHerve Codina case PEB2466_XR2: 1679227f609cSHerve Codina cache = &peb2466->gpio.cache.xr2; 1680227f609cSHerve Codina break; 1681227f609cSHerve Codina case PEB2466_XR3: 1682227f609cSHerve Codina cache = &peb2466->gpio.cache.xr3; 1683227f609cSHerve Codina break; 1684227f609cSHerve Codina default: 1685227f609cSHerve Codina cache = NULL; 1686227f609cSHerve Codina break; 1687227f609cSHerve Codina } 1688227f609cSHerve Codina return cache; 1689227f609cSHerve Codina } 1690227f609cSHerve Codina 1691227f609cSHerve Codina static int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int xr_reg, 1692227f609cSHerve Codina unsigned int mask, unsigned int val) 1693227f609cSHerve Codina { 1694227f609cSHerve Codina unsigned int tmp; 1695227f609cSHerve Codina unsigned int *cache; 1696227f609cSHerve Codina int ret; 1697227f609cSHerve Codina 1698227f609cSHerve Codina /* 1699227f609cSHerve Codina * Read and write accesses use different peb2466 internal signals (input 1700227f609cSHerve Codina * signals on reads and output signals on writes). regmap_update_bits 1701227f609cSHerve Codina * cannot be used to read/modify/write the value. 1702227f609cSHerve Codina * So, a specific cache value is used. 1703227f609cSHerve Codina */ 1704227f609cSHerve Codina 1705227f609cSHerve Codina mutex_lock(&peb2466->gpio.lock); 1706227f609cSHerve Codina 1707227f609cSHerve Codina cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); 1708227f609cSHerve Codina if (!cache) { 1709227f609cSHerve Codina ret = -EINVAL; 1710227f609cSHerve Codina goto end; 1711227f609cSHerve Codina } 1712227f609cSHerve Codina 1713227f609cSHerve Codina tmp = *cache; 1714227f609cSHerve Codina tmp &= ~mask; 1715227f609cSHerve Codina tmp |= val; 1716227f609cSHerve Codina 1717227f609cSHerve Codina ret = regmap_write(peb2466->regmap, xr_reg, tmp); 1718227f609cSHerve Codina if (ret) 1719227f609cSHerve Codina goto end; 1720227f609cSHerve Codina 1721227f609cSHerve Codina *cache = tmp; 1722227f609cSHerve Codina ret = 0; 1723227f609cSHerve Codina 1724227f609cSHerve Codina end: 1725227f609cSHerve Codina mutex_unlock(&peb2466->gpio.lock); 1726227f609cSHerve Codina return ret; 1727227f609cSHerve Codina } 1728227f609cSHerve Codina 1729227f609cSHerve Codina static void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) 1730227f609cSHerve Codina { 1731227f609cSHerve Codina struct peb2466 *peb2466 = gpiochip_get_data(c); 1732227f609cSHerve Codina unsigned int xr_reg; 1733227f609cSHerve Codina unsigned int mask; 1734227f609cSHerve Codina int ret; 1735227f609cSHerve Codina 1736227f609cSHerve Codina if (offset < 8) { 1737227f609cSHerve Codina /* 1738227f609cSHerve Codina * SIx_{0,1} signals cannot be set and writing the related 1739227f609cSHerve Codina * register will change the SOx_{0,1} signals 1740227f609cSHerve Codina */ 1741227f609cSHerve Codina dev_warn(&peb2466->spi->dev, "cannot set gpio %d (read-only)\n", 1742227f609cSHerve Codina offset); 1743227f609cSHerve Codina return; 1744227f609cSHerve Codina } 1745227f609cSHerve Codina 1746227f609cSHerve Codina ret = peb2466_chip_gpio_offset_to_data_regmask(offset, &xr_reg, &mask); 1747227f609cSHerve Codina if (ret) { 1748227f609cSHerve Codina dev_err(&peb2466->spi->dev, "cannot set gpio %d (%d)\n", 1749227f609cSHerve Codina offset, ret); 1750227f609cSHerve Codina return; 1751227f609cSHerve Codina } 1752227f609cSHerve Codina 1753227f609cSHerve Codina ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val ? mask : 0); 1754227f609cSHerve Codina if (ret) { 1755227f609cSHerve Codina dev_err(&peb2466->spi->dev, "set gpio %d (0x%x, 0x%x) failed (%d)\n", 1756227f609cSHerve Codina offset, xr_reg, mask, ret); 1757227f609cSHerve Codina } 1758227f609cSHerve Codina } 1759227f609cSHerve Codina 1760227f609cSHerve Codina static int peb2466_chip_gpio_get(struct gpio_chip *c, unsigned int offset) 1761227f609cSHerve Codina { 1762227f609cSHerve Codina struct peb2466 *peb2466 = gpiochip_get_data(c); 1763227f609cSHerve Codina bool use_cache = false; 1764227f609cSHerve Codina unsigned int *cache; 1765227f609cSHerve Codina unsigned int xr_reg; 1766227f609cSHerve Codina unsigned int mask; 1767227f609cSHerve Codina unsigned int val; 1768227f609cSHerve Codina int ret; 1769227f609cSHerve Codina 1770227f609cSHerve Codina if (offset >= 8 && offset < 16) { 1771227f609cSHerve Codina /* 1772227f609cSHerve Codina * SOx_{0,1} signals cannot be read. Reading the related 1773227f609cSHerve Codina * register will read the SIx_{0,1} signals. 1774227f609cSHerve Codina * Use the cache to get value; 1775227f609cSHerve Codina */ 1776227f609cSHerve Codina use_cache = true; 1777227f609cSHerve Codina } 1778227f609cSHerve Codina 1779227f609cSHerve Codina ret = peb2466_chip_gpio_offset_to_data_regmask(offset, &xr_reg, &mask); 1780227f609cSHerve Codina if (ret) { 1781227f609cSHerve Codina dev_err(&peb2466->spi->dev, "cannot get gpio %d (%d)\n", 1782227f609cSHerve Codina offset, ret); 1783227f609cSHerve Codina return -EINVAL; 1784227f609cSHerve Codina } 1785227f609cSHerve Codina 1786227f609cSHerve Codina if (use_cache) { 1787227f609cSHerve Codina cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); 1788227f609cSHerve Codina if (!cache) 1789227f609cSHerve Codina return -EINVAL; 1790227f609cSHerve Codina val = *cache; 1791227f609cSHerve Codina } else { 1792227f609cSHerve Codina ret = regmap_read(peb2466->regmap, xr_reg, &val); 1793227f609cSHerve Codina if (ret) { 1794227f609cSHerve Codina dev_err(&peb2466->spi->dev, "get gpio %d (0x%x, 0x%x) failed (%d)\n", 1795227f609cSHerve Codina offset, xr_reg, mask, ret); 1796227f609cSHerve Codina return ret; 1797227f609cSHerve Codina } 1798227f609cSHerve Codina } 1799227f609cSHerve Codina 1800227f609cSHerve Codina return !!(val & mask); 1801227f609cSHerve Codina } 1802227f609cSHerve Codina 1803227f609cSHerve Codina static int peb2466_chip_get_direction(struct gpio_chip *c, unsigned int offset) 1804227f609cSHerve Codina { 1805227f609cSHerve Codina struct peb2466 *peb2466 = gpiochip_get_data(c); 1806227f609cSHerve Codina unsigned int xr_reg; 1807227f609cSHerve Codina unsigned int mask; 1808227f609cSHerve Codina unsigned int val; 1809227f609cSHerve Codina int ret; 1810227f609cSHerve Codina 1811227f609cSHerve Codina if (offset < 8) { 1812227f609cSHerve Codina /* SIx_{0,1} */ 1813227f609cSHerve Codina return GPIO_LINE_DIRECTION_IN; 1814227f609cSHerve Codina } 1815227f609cSHerve Codina if (offset < 16) { 1816227f609cSHerve Codina /* SOx_{0,1} */ 1817227f609cSHerve Codina return GPIO_LINE_DIRECTION_OUT; 1818227f609cSHerve Codina } 1819227f609cSHerve Codina 1820227f609cSHerve Codina ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 1821227f609cSHerve Codina if (ret) { 1822227f609cSHerve Codina dev_err(&peb2466->spi->dev, "cannot get gpio %d direction (%d)\n", 1823227f609cSHerve Codina offset, ret); 1824227f609cSHerve Codina return ret; 1825227f609cSHerve Codina } 1826227f609cSHerve Codina 1827227f609cSHerve Codina ret = regmap_read(peb2466->regmap, xr_reg, &val); 1828227f609cSHerve Codina if (ret) { 1829227f609cSHerve Codina dev_err(&peb2466->spi->dev, "get dir gpio %d (0x%x, 0x%x) failed (%d)\n", 1830227f609cSHerve Codina offset, xr_reg, mask, ret); 1831227f609cSHerve Codina return ret; 1832227f609cSHerve Codina } 1833227f609cSHerve Codina 1834227f609cSHerve Codina return val & mask ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 1835227f609cSHerve Codina } 1836227f609cSHerve Codina 1837227f609cSHerve Codina static int peb2466_chip_direction_input(struct gpio_chip *c, unsigned int offset) 1838227f609cSHerve Codina { 1839227f609cSHerve Codina struct peb2466 *peb2466 = gpiochip_get_data(c); 1840227f609cSHerve Codina unsigned int xr_reg; 1841227f609cSHerve Codina unsigned int mask; 1842227f609cSHerve Codina int ret; 1843227f609cSHerve Codina 1844227f609cSHerve Codina if (offset < 8) { 1845227f609cSHerve Codina /* SIx_{0,1} */ 1846227f609cSHerve Codina return 0; 1847227f609cSHerve Codina } 1848227f609cSHerve Codina if (offset < 16) { 1849227f609cSHerve Codina /* SOx_{0,1} */ 1850227f609cSHerve Codina return -EINVAL; 1851d227116cSYang Li } 1852227f609cSHerve Codina 1853227f609cSHerve Codina ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 1854227f609cSHerve Codina if (ret) { 1855227f609cSHerve Codina dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n", 1856227f609cSHerve Codina offset, ret); 1857227f609cSHerve Codina return ret; 1858227f609cSHerve Codina } 1859227f609cSHerve Codina 1860227f609cSHerve Codina ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, 0); 1861227f609cSHerve Codina if (ret) { 1862227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n", 1863227f609cSHerve Codina offset, xr_reg, mask, ret); 1864227f609cSHerve Codina return ret; 1865227f609cSHerve Codina } 1866227f609cSHerve Codina 1867227f609cSHerve Codina return 0; 1868227f609cSHerve Codina } 1869227f609cSHerve Codina 1870227f609cSHerve Codina static int peb2466_chip_direction_output(struct gpio_chip *c, unsigned int offset, int val) 1871227f609cSHerve Codina { 1872227f609cSHerve Codina struct peb2466 *peb2466 = gpiochip_get_data(c); 1873227f609cSHerve Codina unsigned int xr_reg; 1874227f609cSHerve Codina unsigned int mask; 1875227f609cSHerve Codina int ret; 1876227f609cSHerve Codina 1877227f609cSHerve Codina if (offset < 8) { 1878227f609cSHerve Codina /* SIx_{0,1} */ 1879227f609cSHerve Codina return -EINVAL; 1880227f609cSHerve Codina } 1881227f609cSHerve Codina 1882227f609cSHerve Codina peb2466_chip_gpio_set(c, offset, val); 1883227f609cSHerve Codina 1884227f609cSHerve Codina if (offset < 16) { 1885227f609cSHerve Codina /* SOx_{0,1} */ 1886227f609cSHerve Codina return 0; 1887d227116cSYang Li } 1888227f609cSHerve Codina 1889227f609cSHerve Codina ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 1890227f609cSHerve Codina if (ret) { 1891227f609cSHerve Codina dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n", 1892227f609cSHerve Codina offset, ret); 1893227f609cSHerve Codina return ret; 1894227f609cSHerve Codina } 1895227f609cSHerve Codina 1896227f609cSHerve Codina ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, mask); 1897227f609cSHerve Codina if (ret) { 1898227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n", 1899227f609cSHerve Codina offset, xr_reg, mask, ret); 1900227f609cSHerve Codina return ret; 1901227f609cSHerve Codina } 1902227f609cSHerve Codina 1903227f609cSHerve Codina return 0; 1904227f609cSHerve Codina } 1905227f609cSHerve Codina 1906227f609cSHerve Codina static int peb2466_reset_gpio(struct peb2466 *peb2466) 1907227f609cSHerve Codina { 1908227f609cSHerve Codina static const struct reg_sequence reg_reset[] = { 1909227f609cSHerve Codina /* Output pins at 0, input/output pins as input */ 1910227f609cSHerve Codina { .reg = PEB2466_XR0, .def = 0 }, 1911227f609cSHerve Codina { .reg = PEB2466_XR1, .def = 0 }, 1912227f609cSHerve Codina { .reg = PEB2466_XR2, .def = 0 }, 1913227f609cSHerve Codina { .reg = PEB2466_XR3, .def = 0 }, 1914227f609cSHerve Codina }; 1915227f609cSHerve Codina 1916227f609cSHerve Codina peb2466->gpio.cache.xr0 = 0; 1917227f609cSHerve Codina peb2466->gpio.cache.xr1 = 0; 1918227f609cSHerve Codina peb2466->gpio.cache.xr2 = 0; 1919227f609cSHerve Codina peb2466->gpio.cache.xr3 = 0; 1920227f609cSHerve Codina 1921227f609cSHerve Codina return regmap_multi_reg_write(peb2466->regmap, reg_reset, ARRAY_SIZE(reg_reset)); 1922227f609cSHerve Codina } 1923227f609cSHerve Codina 1924227f609cSHerve Codina static int peb2466_gpio_init(struct peb2466 *peb2466) 1925227f609cSHerve Codina { 1926227f609cSHerve Codina int ret; 1927227f609cSHerve Codina 1928227f609cSHerve Codina mutex_init(&peb2466->gpio.lock); 1929227f609cSHerve Codina 1930227f609cSHerve Codina ret = peb2466_reset_gpio(peb2466); 1931227f609cSHerve Codina if (ret) 1932227f609cSHerve Codina return ret; 1933227f609cSHerve Codina 1934227f609cSHerve Codina peb2466->gpio.gpio_chip.owner = THIS_MODULE; 1935227f609cSHerve Codina peb2466->gpio.gpio_chip.label = dev_name(&peb2466->spi->dev); 1936227f609cSHerve Codina peb2466->gpio.gpio_chip.parent = &peb2466->spi->dev; 1937227f609cSHerve Codina peb2466->gpio.gpio_chip.base = -1; 1938227f609cSHerve Codina peb2466->gpio.gpio_chip.ngpio = 28; 1939227f609cSHerve Codina peb2466->gpio.gpio_chip.get_direction = peb2466_chip_get_direction; 1940227f609cSHerve Codina peb2466->gpio.gpio_chip.direction_input = peb2466_chip_direction_input; 1941227f609cSHerve Codina peb2466->gpio.gpio_chip.direction_output = peb2466_chip_direction_output; 1942227f609cSHerve Codina peb2466->gpio.gpio_chip.get = peb2466_chip_gpio_get; 1943227f609cSHerve Codina peb2466->gpio.gpio_chip.set = peb2466_chip_gpio_set; 1944227f609cSHerve Codina peb2466->gpio.gpio_chip.can_sleep = true; 1945227f609cSHerve Codina 1946227f609cSHerve Codina return devm_gpiochip_add_data(&peb2466->spi->dev, &peb2466->gpio.gpio_chip, 1947227f609cSHerve Codina peb2466); 1948227f609cSHerve Codina } 1949227f609cSHerve Codina 1950227f609cSHerve Codina static int peb2466_spi_probe(struct spi_device *spi) 1951227f609cSHerve Codina { 1952227f609cSHerve Codina struct peb2466 *peb2466; 1953227f609cSHerve Codina unsigned long mclk_rate; 1954227f609cSHerve Codina int ret; 1955227f609cSHerve Codina u8 xr5; 1956227f609cSHerve Codina 1957227f609cSHerve Codina spi->bits_per_word = 8; 1958227f609cSHerve Codina ret = spi_setup(spi); 1959227f609cSHerve Codina if (ret < 0) 1960227f609cSHerve Codina return ret; 1961227f609cSHerve Codina 1962227f609cSHerve Codina peb2466 = devm_kzalloc(&spi->dev, sizeof(*peb2466), GFP_KERNEL); 1963227f609cSHerve Codina if (!peb2466) 1964227f609cSHerve Codina return -ENOMEM; 1965227f609cSHerve Codina 1966227f609cSHerve Codina peb2466->spi = spi; 1967227f609cSHerve Codina 1968227f609cSHerve Codina peb2466->regmap = devm_regmap_init(&peb2466->spi->dev, NULL, peb2466, 1969227f609cSHerve Codina &peb2466_regmap_config); 1970227f609cSHerve Codina if (IS_ERR(peb2466->regmap)) 1971227f609cSHerve Codina return PTR_ERR(peb2466->regmap); 1972227f609cSHerve Codina 1973227f609cSHerve Codina peb2466->reset_gpio = devm_gpiod_get_optional(&peb2466->spi->dev, 1974227f609cSHerve Codina "reset", GPIOD_OUT_LOW); 1975227f609cSHerve Codina if (IS_ERR(peb2466->reset_gpio)) 1976227f609cSHerve Codina return PTR_ERR(peb2466->reset_gpio); 1977227f609cSHerve Codina 1978*241c044eSying zuxin peb2466->mclk = devm_clk_get_enabled(&peb2466->spi->dev, "mclk"); 1979227f609cSHerve Codina if (IS_ERR(peb2466->mclk)) 1980227f609cSHerve Codina return PTR_ERR(peb2466->mclk); 1981227f609cSHerve Codina 1982227f609cSHerve Codina if (peb2466->reset_gpio) { 1983227f609cSHerve Codina gpiod_set_value_cansleep(peb2466->reset_gpio, 1); 1984227f609cSHerve Codina udelay(4); 1985227f609cSHerve Codina gpiod_set_value_cansleep(peb2466->reset_gpio, 0); 1986227f609cSHerve Codina udelay(4); 1987227f609cSHerve Codina } 1988227f609cSHerve Codina 1989227f609cSHerve Codina spi_set_drvdata(spi, peb2466); 1990227f609cSHerve Codina 1991227f609cSHerve Codina mclk_rate = clk_get_rate(peb2466->mclk); 1992227f609cSHerve Codina switch (mclk_rate) { 1993227f609cSHerve Codina case 1536000: 1994227f609cSHerve Codina xr5 = PEB2466_XR5_MCLK_1536; 1995227f609cSHerve Codina break; 1996227f609cSHerve Codina case 2048000: 1997227f609cSHerve Codina xr5 = PEB2466_XR5_MCLK_2048; 1998227f609cSHerve Codina break; 1999227f609cSHerve Codina case 4096000: 2000227f609cSHerve Codina xr5 = PEB2466_XR5_MCLK_4096; 2001227f609cSHerve Codina break; 2002227f609cSHerve Codina case 8192000: 2003227f609cSHerve Codina xr5 = PEB2466_XR5_MCLK_8192; 2004227f609cSHerve Codina break; 2005227f609cSHerve Codina default: 2006227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Unsupported clock rate %lu\n", 2007227f609cSHerve Codina mclk_rate); 2008227f609cSHerve Codina ret = -EINVAL; 2009227f609cSHerve Codina goto failed; 2010227f609cSHerve Codina } 2011227f609cSHerve Codina ret = regmap_write(peb2466->regmap, PEB2466_XR5, xr5); 2012227f609cSHerve Codina if (ret) { 2013227f609cSHerve Codina dev_err(&peb2466->spi->dev, "Setting MCLK failed (%d)\n", ret); 2014227f609cSHerve Codina goto failed; 2015227f609cSHerve Codina } 2016227f609cSHerve Codina 2017227f609cSHerve Codina ret = devm_snd_soc_register_component(&spi->dev, &peb2466_component_driver, 2018227f609cSHerve Codina &peb2466_dai_driver, 1); 2019227f609cSHerve Codina if (ret) 2020227f609cSHerve Codina goto failed; 2021227f609cSHerve Codina 2022227f609cSHerve Codina if (IS_ENABLED(CONFIG_GPIOLIB)) { 2023227f609cSHerve Codina ret = peb2466_gpio_init(peb2466); 2024227f609cSHerve Codina if (ret) 2025227f609cSHerve Codina goto failed; 2026227f609cSHerve Codina } 2027227f609cSHerve Codina 2028227f609cSHerve Codina return 0; 2029227f609cSHerve Codina 2030227f609cSHerve Codina failed: 2031227f609cSHerve Codina return ret; 2032227f609cSHerve Codina } 2033227f609cSHerve Codina 2034227f609cSHerve Codina static const struct of_device_id peb2466_of_match[] = { 2035227f609cSHerve Codina { .compatible = "infineon,peb2466", }, 2036227f609cSHerve Codina { } 2037227f609cSHerve Codina }; 2038227f609cSHerve Codina MODULE_DEVICE_TABLE(of, peb2466_of_match); 2039227f609cSHerve Codina 2040227f609cSHerve Codina static const struct spi_device_id peb2466_id_table[] = { 2041227f609cSHerve Codina { "peb2466", 0 }, 2042227f609cSHerve Codina { } 2043227f609cSHerve Codina }; 2044227f609cSHerve Codina MODULE_DEVICE_TABLE(spi, peb2466_id_table); 2045227f609cSHerve Codina 2046227f609cSHerve Codina static struct spi_driver peb2466_spi_driver = { 2047227f609cSHerve Codina .driver = { 2048227f609cSHerve Codina .name = "peb2466", 2049227f609cSHerve Codina .of_match_table = peb2466_of_match, 2050227f609cSHerve Codina }, 2051227f609cSHerve Codina .id_table = peb2466_id_table, 2052227f609cSHerve Codina .probe = peb2466_spi_probe, 2053227f609cSHerve Codina }; 2054227f609cSHerve Codina 2055227f609cSHerve Codina module_spi_driver(peb2466_spi_driver); 2056227f609cSHerve Codina 2057227f609cSHerve Codina MODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 2058227f609cSHerve Codina MODULE_DESCRIPTION("PEB2466 ALSA SoC driver"); 2059227f609cSHerve Codina MODULE_LICENSE("GPL"); 2060