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