162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// peb2466.c -- Infineon PEB2466 ALSA SoC driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright 2023 CS GROUP France 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// Author: Herve Codina <herve.codina@bootlin.com> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <asm/unaligned.h> 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/firmware.h> 1262306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1362306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/spi/spi.h> 1862306a36Sopenharmony_ci#include <sound/pcm_params.h> 1962306a36Sopenharmony_ci#include <sound/soc.h> 2062306a36Sopenharmony_ci#include <sound/tlv.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define PEB2466_NB_CHANNEL 4 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct peb2466_lookup { 2562306a36Sopenharmony_ci u8 (*table)[4]; 2662306a36Sopenharmony_ci unsigned int count; 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#define PEB2466_TLV_SIZE (sizeof((unsigned int []){TLV_DB_SCALE_ITEM(0, 0, 0)}) / \ 3062306a36Sopenharmony_ci sizeof(unsigned int)) 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct peb2466_lkup_ctrl { 3362306a36Sopenharmony_ci int reg; 3462306a36Sopenharmony_ci unsigned int index; 3562306a36Sopenharmony_ci const struct peb2466_lookup *lookup; 3662306a36Sopenharmony_ci unsigned int tlv_array[PEB2466_TLV_SIZE]; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct peb2466 { 4062306a36Sopenharmony_ci struct spi_device *spi; 4162306a36Sopenharmony_ci struct clk *mclk; 4262306a36Sopenharmony_ci struct gpio_desc *reset_gpio; 4362306a36Sopenharmony_ci u8 spi_tx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ 4462306a36Sopenharmony_ci u8 spi_rx_buf[2 + 8]; /* Cannot use stack area for SPI (dma-safe memory) */ 4562306a36Sopenharmony_ci struct regmap *regmap; 4662306a36Sopenharmony_ci struct { 4762306a36Sopenharmony_ci struct peb2466_lookup ax_lookup; 4862306a36Sopenharmony_ci struct peb2466_lookup ar_lookup; 4962306a36Sopenharmony_ci struct peb2466_lkup_ctrl ax_lkup_ctrl; 5062306a36Sopenharmony_ci struct peb2466_lkup_ctrl ar_lkup_ctrl; 5162306a36Sopenharmony_ci unsigned int tg1_freq_item; 5262306a36Sopenharmony_ci unsigned int tg2_freq_item; 5362306a36Sopenharmony_ci } ch[PEB2466_NB_CHANNEL]; 5462306a36Sopenharmony_ci int max_chan_playback; 5562306a36Sopenharmony_ci int max_chan_capture; 5662306a36Sopenharmony_ci struct { 5762306a36Sopenharmony_ci struct gpio_chip gpio_chip; 5862306a36Sopenharmony_ci struct mutex lock; 5962306a36Sopenharmony_ci struct { 6062306a36Sopenharmony_ci unsigned int xr0; 6162306a36Sopenharmony_ci unsigned int xr1; 6262306a36Sopenharmony_ci unsigned int xr2; 6362306a36Sopenharmony_ci unsigned int xr3; 6462306a36Sopenharmony_ci } cache; 6562306a36Sopenharmony_ci } gpio; 6662306a36Sopenharmony_ci}; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci#define PEB2466_CMD_R (1 << 5) 6962306a36Sopenharmony_ci#define PEB2466_CMD_W (0 << 5) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#define PEB2466_CMD_MASK 0x18 7262306a36Sopenharmony_ci#define PEB2466_CMD_XOP 0x18 /* XOP is 0bxxx11xxx */ 7362306a36Sopenharmony_ci#define PEB2466_CMD_SOP 0x10 /* SOP is 0bxxx10xxx */ 7462306a36Sopenharmony_ci#define PEB2466_CMD_COP 0x00 /* COP is 0bxxx0xxxx, handle 0bxxx00xxx */ 7562306a36Sopenharmony_ci#define PEB2466_CMD_COP1 0x08 /* COP is 0bxxx0xxxx, handle 0bxxx01xxx */ 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define PEB2466_MAKE_XOP(_lsel) (PEB2466_CMD_XOP | (_lsel)) 7862306a36Sopenharmony_ci#define PEB2466_MAKE_SOP(_ad, _lsel) (PEB2466_CMD_SOP | ((_ad) << 6) | (_lsel)) 7962306a36Sopenharmony_ci#define PEB2466_MAKE_COP(_ad, _code) (PEB2466_CMD_COP | ((_ad) << 6) | (_code)) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci#define PEB2466_CR0(_ch) PEB2466_MAKE_SOP(_ch, 0x0) 8262306a36Sopenharmony_ci#define PEB2466_CR0_TH (1 << 7) 8362306a36Sopenharmony_ci#define PEB2466_CR0_IMR1 (1 << 6) 8462306a36Sopenharmony_ci#define PEB2466_CR0_FRX (1 << 5) 8562306a36Sopenharmony_ci#define PEB2466_CR0_FRR (1 << 4) 8662306a36Sopenharmony_ci#define PEB2466_CR0_AX (1 << 3) 8762306a36Sopenharmony_ci#define PEB2466_CR0_AR (1 << 2) 8862306a36Sopenharmony_ci#define PEB2466_CR0_THSEL_MASK (0x3 << 0) 8962306a36Sopenharmony_ci#define PEB2466_CR0_THSEL(_set) ((_set) << 0) 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci#define PEB2466_CR1(_ch) PEB2466_MAKE_SOP(_ch, 0x1) 9262306a36Sopenharmony_ci#define PEB2466_CR1_ETG2 (1 << 7) 9362306a36Sopenharmony_ci#define PEB2466_CR1_ETG1 (1 << 6) 9462306a36Sopenharmony_ci#define PEB2466_CR1_PTG2 (1 << 5) 9562306a36Sopenharmony_ci#define PEB2466_CR1_PTG1 (1 << 4) 9662306a36Sopenharmony_ci#define PEB2466_CR1_LAW_MASK (1 << 3) 9762306a36Sopenharmony_ci#define PEB2466_CR1_LAW_ALAW (0 << 3) 9862306a36Sopenharmony_ci#define PEB2466_CR1_LAW_MULAW (1 << 3) 9962306a36Sopenharmony_ci#define PEB2466_CR1_PU (1 << 0) 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci#define PEB2466_CR2(_ch) PEB2466_MAKE_SOP(_ch, 0x2) 10262306a36Sopenharmony_ci#define PEB2466_CR3(_ch) PEB2466_MAKE_SOP(_ch, 0x3) 10362306a36Sopenharmony_ci#define PEB2466_CR4(_ch) PEB2466_MAKE_SOP(_ch, 0x4) 10462306a36Sopenharmony_ci#define PEB2466_CR5(_ch) PEB2466_MAKE_SOP(_ch, 0x5) 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci#define PEB2466_XR0 PEB2466_MAKE_XOP(0x0) 10762306a36Sopenharmony_ci#define PEB2466_XR1 PEB2466_MAKE_XOP(0x1) 10862306a36Sopenharmony_ci#define PEB2466_XR2 PEB2466_MAKE_XOP(0x2) 10962306a36Sopenharmony_ci#define PEB2466_XR3 PEB2466_MAKE_XOP(0x3) 11062306a36Sopenharmony_ci#define PEB2466_XR4 PEB2466_MAKE_XOP(0x4) 11162306a36Sopenharmony_ci#define PEB2466_XR5 PEB2466_MAKE_XOP(0x5) 11262306a36Sopenharmony_ci#define PEB2466_XR5_MCLK_1536 (0x0 << 6) 11362306a36Sopenharmony_ci#define PEB2466_XR5_MCLK_2048 (0x1 << 6) 11462306a36Sopenharmony_ci#define PEB2466_XR5_MCLK_4096 (0x2 << 6) 11562306a36Sopenharmony_ci#define PEB2466_XR5_MCLK_8192 (0x3 << 6) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define PEB2466_XR6 PEB2466_MAKE_XOP(0x6) 11862306a36Sopenharmony_ci#define PEB2466_XR6_PCM_OFFSET(_off) ((_off) << 0) 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci#define PEB2466_XR7 PEB2466_MAKE_XOP(0x7) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define PEB2466_TH_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x0) 12362306a36Sopenharmony_ci#define PEB2466_TH_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x1) 12462306a36Sopenharmony_ci#define PEB2466_TH_FILTER_P3(_ch) PEB2466_MAKE_COP(_ch, 0x2) 12562306a36Sopenharmony_ci#define PEB2466_IMR1_FILTER_P1(_ch) PEB2466_MAKE_COP(_ch, 0x4) 12662306a36Sopenharmony_ci#define PEB2466_IMR1_FILTER_P2(_ch) PEB2466_MAKE_COP(_ch, 0x5) 12762306a36Sopenharmony_ci#define PEB2466_FRX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x6) 12862306a36Sopenharmony_ci#define PEB2466_FRR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x7) 12962306a36Sopenharmony_ci#define PEB2466_AX_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x8) 13062306a36Sopenharmony_ci#define PEB2466_AR_FILTER(_ch) PEB2466_MAKE_COP(_ch, 0x9) 13162306a36Sopenharmony_ci#define PEB2466_TG1(_ch) PEB2466_MAKE_COP(_ch, 0xc) 13262306a36Sopenharmony_ci#define PEB2466_TG2(_ch) PEB2466_MAKE_COP(_ch, 0xd) 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int peb2466_write_byte(struct peb2466 *peb2466, u8 cmd, u8 val) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci struct spi_transfer xfer = { 13762306a36Sopenharmony_ci .tx_buf = &peb2466->spi_tx_buf, 13862306a36Sopenharmony_ci .len = 2, 13962306a36Sopenharmony_ci }; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; 14262306a36Sopenharmony_ci peb2466->spi_tx_buf[1] = val; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci dev_dbg(&peb2466->spi->dev, "write byte (cmd %02x) %02x\n", 14562306a36Sopenharmony_ci peb2466->spi_tx_buf[0], peb2466->spi_tx_buf[1]); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci return spi_sync_transfer(peb2466->spi, &xfer, 1); 14862306a36Sopenharmony_ci} 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic int peb2466_read_byte(struct peb2466 *peb2466, u8 cmd, u8 *val) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci struct spi_transfer xfer = { 15362306a36Sopenharmony_ci .tx_buf = &peb2466->spi_tx_buf, 15462306a36Sopenharmony_ci .rx_buf = &peb2466->spi_rx_buf, 15562306a36Sopenharmony_ci .len = 3, 15662306a36Sopenharmony_ci }; 15762306a36Sopenharmony_ci int ret; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_R; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci ret = spi_sync_transfer(peb2466->spi, &xfer, 1); 16262306a36Sopenharmony_ci if (ret) 16362306a36Sopenharmony_ci return ret; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (peb2466->spi_rx_buf[1] != 0x81) { 16662306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, 16762306a36Sopenharmony_ci "spi xfer rd (cmd %02x) invalid ident byte (0x%02x)\n", 16862306a36Sopenharmony_ci peb2466->spi_tx_buf[0], peb2466->spi_rx_buf[1]); 16962306a36Sopenharmony_ci return -EILSEQ; 17062306a36Sopenharmony_ci } 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci *val = peb2466->spi_rx_buf[2]; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci dev_dbg(&peb2466->spi->dev, "read byte (cmd %02x) %02x\n", 17562306a36Sopenharmony_ci peb2466->spi_tx_buf[0], *val); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci return 0; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int peb2466_write_buf(struct peb2466 *peb2466, u8 cmd, const u8 *buf, unsigned int len) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct spi_transfer xfer = { 18362306a36Sopenharmony_ci .tx_buf = &peb2466->spi_tx_buf, 18462306a36Sopenharmony_ci .len = len + 1, 18562306a36Sopenharmony_ci }; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci if (len > 8) 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci peb2466->spi_tx_buf[0] = cmd | PEB2466_CMD_W; 19162306a36Sopenharmony_ci memcpy(&peb2466->spi_tx_buf[1], buf, len); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dev_dbg(&peb2466->spi->dev, "write buf (cmd %02x, %u) %*ph\n", 19462306a36Sopenharmony_ci peb2466->spi_tx_buf[0], len, len, &peb2466->spi_tx_buf[1]); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci return spi_sync_transfer(peb2466->spi, &xfer, 1); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic int peb2466_reg_write(void *context, unsigned int reg, unsigned int val) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci struct peb2466 *peb2466 = context; 20262306a36Sopenharmony_ci int ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* 20562306a36Sopenharmony_ci * Only XOP and SOP commands can be handled as registers. 20662306a36Sopenharmony_ci * COP commands are handled using direct peb2466_write_buf() calls. 20762306a36Sopenharmony_ci */ 20862306a36Sopenharmony_ci switch (reg & PEB2466_CMD_MASK) { 20962306a36Sopenharmony_ci case PEB2466_CMD_XOP: 21062306a36Sopenharmony_ci case PEB2466_CMD_SOP: 21162306a36Sopenharmony_ci ret = peb2466_write_byte(peb2466, reg, val); 21262306a36Sopenharmony_ci break; 21362306a36Sopenharmony_ci default: 21462306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n"); 21562306a36Sopenharmony_ci ret = -EINVAL; 21662306a36Sopenharmony_ci break; 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci return ret; 21962306a36Sopenharmony_ci} 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_cistatic int peb2466_reg_read(void *context, unsigned int reg, unsigned int *val) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct peb2466 *peb2466 = context; 22462306a36Sopenharmony_ci int ret; 22562306a36Sopenharmony_ci u8 tmp; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Only XOP and SOP commands can be handled as registers */ 22862306a36Sopenharmony_ci switch (reg & PEB2466_CMD_MASK) { 22962306a36Sopenharmony_ci case PEB2466_CMD_XOP: 23062306a36Sopenharmony_ci case PEB2466_CMD_SOP: 23162306a36Sopenharmony_ci ret = peb2466_read_byte(peb2466, reg, &tmp); 23262306a36Sopenharmony_ci *val = tmp; 23362306a36Sopenharmony_ci break; 23462306a36Sopenharmony_ci default: 23562306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Not a XOP or SOP command\n"); 23662306a36Sopenharmony_ci ret = -EINVAL; 23762306a36Sopenharmony_ci break; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci return ret; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const struct regmap_config peb2466_regmap_config = { 24362306a36Sopenharmony_ci .reg_bits = 8, 24462306a36Sopenharmony_ci .val_bits = 8, 24562306a36Sopenharmony_ci .max_register = 0xFF, 24662306a36Sopenharmony_ci .reg_write = peb2466_reg_write, 24762306a36Sopenharmony_ci .reg_read = peb2466_reg_read, 24862306a36Sopenharmony_ci .cache_type = REGCACHE_NONE, 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic int peb2466_lkup_ctrl_info(struct snd_kcontrol *kcontrol, 25262306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl = 25562306a36Sopenharmony_ci (struct peb2466_lkup_ctrl *)kcontrol->private_value; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 25862306a36Sopenharmony_ci uinfo->count = 1; 25962306a36Sopenharmony_ci uinfo->value.integer.min = 0; 26062306a36Sopenharmony_ci uinfo->value.integer.max = lkup_ctrl->lookup->count - 1; 26162306a36Sopenharmony_ci return 0; 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic int peb2466_lkup_ctrl_get(struct snd_kcontrol *kcontrol, 26562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl = 26862306a36Sopenharmony_ci (struct peb2466_lkup_ctrl *)kcontrol->private_value; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci ucontrol->value.integer.value[0] = lkup_ctrl->index; 27162306a36Sopenharmony_ci return 0; 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistatic int peb2466_lkup_ctrl_put(struct snd_kcontrol *kcontrol, 27562306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 27662306a36Sopenharmony_ci{ 27762306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl = 27862306a36Sopenharmony_ci (struct peb2466_lkup_ctrl *)kcontrol->private_value; 27962306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 28062306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 28162306a36Sopenharmony_ci unsigned int index; 28262306a36Sopenharmony_ci int ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci index = ucontrol->value.integer.value[0]; 28562306a36Sopenharmony_ci if (index >= lkup_ctrl->lookup->count) 28662306a36Sopenharmony_ci return -EINVAL; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (index == lkup_ctrl->index) 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, lkup_ctrl->reg, 29262306a36Sopenharmony_ci lkup_ctrl->lookup->table[index], 4); 29362306a36Sopenharmony_ci if (ret) 29462306a36Sopenharmony_ci return ret; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci lkup_ctrl->index = index; 29762306a36Sopenharmony_ci return 1; /* The value changed */ 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int peb2466_add_lkup_ctrl(struct snd_soc_component *component, 30162306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl, 30262306a36Sopenharmony_ci const char *name, int min_val, int step) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci DECLARE_TLV_DB_SCALE(tlv_array, min_val, step, 0); 30562306a36Sopenharmony_ci struct snd_kcontrol_new control = {0}; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(lkup_ctrl->tlv_array) < sizeof(tlv_array)); 30862306a36Sopenharmony_ci memcpy(lkup_ctrl->tlv_array, tlv_array, sizeof(tlv_array)); 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci control.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 31162306a36Sopenharmony_ci control.name = name; 31262306a36Sopenharmony_ci control.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | 31362306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_READWRITE; 31462306a36Sopenharmony_ci control.tlv.p = lkup_ctrl->tlv_array; 31562306a36Sopenharmony_ci control.info = peb2466_lkup_ctrl_info; 31662306a36Sopenharmony_ci control.get = peb2466_lkup_ctrl_get; 31762306a36Sopenharmony_ci control.put = peb2466_lkup_ctrl_put; 31862306a36Sopenharmony_ci control.private_value = (unsigned long)lkup_ctrl; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return snd_soc_add_component_controls(component, &control, 1); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cienum peb2466_tone_freq { 32462306a36Sopenharmony_ci PEB2466_TONE_697HZ, 32562306a36Sopenharmony_ci PEB2466_TONE_800HZ, 32662306a36Sopenharmony_ci PEB2466_TONE_950HZ, 32762306a36Sopenharmony_ci PEB2466_TONE_1000HZ, 32862306a36Sopenharmony_ci PEB2466_TONE_1008HZ, 32962306a36Sopenharmony_ci PEB2466_TONE_2000HZ, 33062306a36Sopenharmony_ci}; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic const u8 peb2466_tone_lookup[][4] = { 33362306a36Sopenharmony_ci [PEB2466_TONE_697HZ] = {0x0a, 0x33, 0x5a, 0x2c}, 33462306a36Sopenharmony_ci [PEB2466_TONE_800HZ] = {0x12, 0xD6, 0x5a, 0xc0}, 33562306a36Sopenharmony_ci [PEB2466_TONE_950HZ] = {0x1c, 0xf0, 0x5c, 0xc0}, 33662306a36Sopenharmony_ci [PEB2466_TONE_1000HZ] = {0}, /* lookup value not used for 1000Hz */ 33762306a36Sopenharmony_ci [PEB2466_TONE_1008HZ] = {0x1a, 0xae, 0x57, 0x70}, 33862306a36Sopenharmony_ci [PEB2466_TONE_2000HZ] = {0x00, 0x80, 0x50, 0x09}, 33962306a36Sopenharmony_ci}; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic const char * const peb2466_tone_freq_txt[] = { 34262306a36Sopenharmony_ci [PEB2466_TONE_697HZ] = "697Hz", 34362306a36Sopenharmony_ci [PEB2466_TONE_800HZ] = "800Hz", 34462306a36Sopenharmony_ci [PEB2466_TONE_950HZ] = "950Hz", 34562306a36Sopenharmony_ci [PEB2466_TONE_1000HZ] = "1000Hz", 34662306a36Sopenharmony_ci [PEB2466_TONE_1008HZ] = "1008Hz", 34762306a36Sopenharmony_ci [PEB2466_TONE_2000HZ] = "2000Hz" 34862306a36Sopenharmony_ci}; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_cistatic const struct soc_enum peb2466_tg_freq[][2] = { 35162306a36Sopenharmony_ci [0] = { 35262306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG1(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 35362306a36Sopenharmony_ci peb2466_tone_freq_txt), 35462306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG2(0), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 35562306a36Sopenharmony_ci peb2466_tone_freq_txt) 35662306a36Sopenharmony_ci }, 35762306a36Sopenharmony_ci [1] = { 35862306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG1(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 35962306a36Sopenharmony_ci peb2466_tone_freq_txt), 36062306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG2(1), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 36162306a36Sopenharmony_ci peb2466_tone_freq_txt) 36262306a36Sopenharmony_ci }, 36362306a36Sopenharmony_ci [2] = { 36462306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG1(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 36562306a36Sopenharmony_ci peb2466_tone_freq_txt), 36662306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG2(2), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 36762306a36Sopenharmony_ci peb2466_tone_freq_txt) 36862306a36Sopenharmony_ci }, 36962306a36Sopenharmony_ci [3] = { 37062306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG1(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 37162306a36Sopenharmony_ci peb2466_tone_freq_txt), 37262306a36Sopenharmony_ci SOC_ENUM_SINGLE(PEB2466_TG2(3), 0, ARRAY_SIZE(peb2466_tone_freq_txt), 37362306a36Sopenharmony_ci peb2466_tone_freq_txt) 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic int peb2466_tg_freq_get(struct snd_kcontrol *kcontrol, 37862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 38162306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 38262306a36Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci switch (e->reg) { 38562306a36Sopenharmony_ci case PEB2466_TG1(0): 38662306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg1_freq_item; 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci case PEB2466_TG2(0): 38962306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[0].tg2_freq_item; 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci case PEB2466_TG1(1): 39262306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg1_freq_item; 39362306a36Sopenharmony_ci break; 39462306a36Sopenharmony_ci case PEB2466_TG2(1): 39562306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[1].tg2_freq_item; 39662306a36Sopenharmony_ci break; 39762306a36Sopenharmony_ci case PEB2466_TG1(2): 39862306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg1_freq_item; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci case PEB2466_TG2(2): 40162306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[2].tg2_freq_item; 40262306a36Sopenharmony_ci break; 40362306a36Sopenharmony_ci case PEB2466_TG1(3): 40462306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg1_freq_item; 40562306a36Sopenharmony_ci break; 40662306a36Sopenharmony_ci case PEB2466_TG2(3): 40762306a36Sopenharmony_ci ucontrol->value.enumerated.item[0] = peb2466->ch[3].tg2_freq_item; 40862306a36Sopenharmony_ci break; 40962306a36Sopenharmony_ci default: 41062306a36Sopenharmony_ci return -EINVAL; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci return 0; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int peb2466_tg_freq_put(struct snd_kcontrol *kcontrol, 41662306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); 41962306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 42062306a36Sopenharmony_ci struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; 42162306a36Sopenharmony_ci unsigned int *tg_freq_item; 42262306a36Sopenharmony_ci u8 cr1_reg, cr1_mask; 42362306a36Sopenharmony_ci unsigned int index; 42462306a36Sopenharmony_ci int ret; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci index = ucontrol->value.enumerated.item[0]; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (index >= ARRAY_SIZE(peb2466_tone_lookup)) 42962306a36Sopenharmony_ci return -EINVAL; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci switch (e->reg) { 43262306a36Sopenharmony_ci case PEB2466_TG1(0): 43362306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[0].tg1_freq_item; 43462306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(0); 43562306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG1; 43662306a36Sopenharmony_ci break; 43762306a36Sopenharmony_ci case PEB2466_TG2(0): 43862306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[0].tg2_freq_item; 43962306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(0); 44062306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG2; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci case PEB2466_TG1(1): 44362306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[1].tg1_freq_item; 44462306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(1); 44562306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG1; 44662306a36Sopenharmony_ci break; 44762306a36Sopenharmony_ci case PEB2466_TG2(1): 44862306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[1].tg2_freq_item; 44962306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(1); 45062306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG2; 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci case PEB2466_TG1(2): 45362306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[2].tg1_freq_item; 45462306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(2); 45562306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG1; 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case PEB2466_TG2(2): 45862306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[2].tg2_freq_item; 45962306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(2); 46062306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG2; 46162306a36Sopenharmony_ci break; 46262306a36Sopenharmony_ci case PEB2466_TG1(3): 46362306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[3].tg1_freq_item; 46462306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(3); 46562306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG1; 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci case PEB2466_TG2(3): 46862306a36Sopenharmony_ci tg_freq_item = &peb2466->ch[3].tg2_freq_item; 46962306a36Sopenharmony_ci cr1_reg = PEB2466_CR1(3); 47062306a36Sopenharmony_ci cr1_mask = PEB2466_CR1_PTG2; 47162306a36Sopenharmony_ci break; 47262306a36Sopenharmony_ci default: 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (index == *tg_freq_item) 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (index == PEB2466_TONE_1000HZ) { 48062306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, cr1_reg, cr1_mask, 0); 48162306a36Sopenharmony_ci if (ret) 48262306a36Sopenharmony_ci return ret; 48362306a36Sopenharmony_ci } else { 48462306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, e->reg, peb2466_tone_lookup[index], 4); 48562306a36Sopenharmony_ci if (ret) 48662306a36Sopenharmony_ci return ret; 48762306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, cr1_reg, cr1_mask, cr1_mask); 48862306a36Sopenharmony_ci if (ret) 48962306a36Sopenharmony_ci return ret; 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci *tg_freq_item = index; 49362306a36Sopenharmony_ci return 1; /* The value changed */ 49462306a36Sopenharmony_ci} 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_cistatic const struct snd_kcontrol_new peb2466_ch0_out_mix_controls[] = { 49762306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(0), 6, 1, 0), 49862306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(0), 7, 1, 0), 49962306a36Sopenharmony_ci SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(0), 0, 1, 0) 50062306a36Sopenharmony_ci}; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_cistatic const struct snd_kcontrol_new peb2466_ch1_out_mix_controls[] = { 50362306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(1), 6, 1, 0), 50462306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(1), 7, 1, 0), 50562306a36Sopenharmony_ci SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(1), 0, 1, 0) 50662306a36Sopenharmony_ci}; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cistatic const struct snd_kcontrol_new peb2466_ch2_out_mix_controls[] = { 50962306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(2), 6, 1, 0), 51062306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(2), 7, 1, 0), 51162306a36Sopenharmony_ci SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(2), 0, 1, 0) 51262306a36Sopenharmony_ci}; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_cistatic const struct snd_kcontrol_new peb2466_ch3_out_mix_controls[] = { 51562306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG1 Switch", PEB2466_CR1(3), 6, 1, 0), 51662306a36Sopenharmony_ci SOC_DAPM_SINGLE("TG2 Switch", PEB2466_CR1(3), 7, 1, 0), 51762306a36Sopenharmony_ci SOC_DAPM_SINGLE("Voice Switch", PEB2466_CR2(3), 0, 1, 0) 51862306a36Sopenharmony_ci}; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_cistatic const struct snd_kcontrol_new peb2466_controls[] = { 52162306a36Sopenharmony_ci /* Attenuators */ 52262306a36Sopenharmony_ci SOC_SINGLE("DAC0 -6dB Playback Switch", PEB2466_CR3(0), 2, 1, 0), 52362306a36Sopenharmony_ci SOC_SINGLE("DAC1 -6dB Playback Switch", PEB2466_CR3(1), 2, 1, 0), 52462306a36Sopenharmony_ci SOC_SINGLE("DAC2 -6dB Playback Switch", PEB2466_CR3(2), 2, 1, 0), 52562306a36Sopenharmony_ci SOC_SINGLE("DAC3 -6dB Playback Switch", PEB2466_CR3(3), 2, 1, 0), 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci /* Amplifiers */ 52862306a36Sopenharmony_ci SOC_SINGLE("ADC0 +6dB Capture Switch", PEB2466_CR3(0), 3, 1, 0), 52962306a36Sopenharmony_ci SOC_SINGLE("ADC1 +6dB Capture Switch", PEB2466_CR3(1), 3, 1, 0), 53062306a36Sopenharmony_ci SOC_SINGLE("ADC2 +6dB Capture Switch", PEB2466_CR3(2), 3, 1, 0), 53162306a36Sopenharmony_ci SOC_SINGLE("ADC3 +6dB Capture Switch", PEB2466_CR3(3), 3, 1, 0), 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci /* Tone generators */ 53462306a36Sopenharmony_ci SOC_ENUM_EXT("DAC0 TG1 Freq", peb2466_tg_freq[0][0], 53562306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 53662306a36Sopenharmony_ci SOC_ENUM_EXT("DAC1 TG1 Freq", peb2466_tg_freq[1][0], 53762306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 53862306a36Sopenharmony_ci SOC_ENUM_EXT("DAC2 TG1 Freq", peb2466_tg_freq[2][0], 53962306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 54062306a36Sopenharmony_ci SOC_ENUM_EXT("DAC3 TG1 Freq", peb2466_tg_freq[3][0], 54162306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci SOC_ENUM_EXT("DAC0 TG2 Freq", peb2466_tg_freq[0][1], 54462306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 54562306a36Sopenharmony_ci SOC_ENUM_EXT("DAC1 TG2 Freq", peb2466_tg_freq[1][1], 54662306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 54762306a36Sopenharmony_ci SOC_ENUM_EXT("DAC2 TG2 Freq", peb2466_tg_freq[2][1], 54862306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 54962306a36Sopenharmony_ci SOC_ENUM_EXT("DAC3 TG2 Freq", peb2466_tg_freq[3][1], 55062306a36Sopenharmony_ci peb2466_tg_freq_get, peb2466_tg_freq_put), 55162306a36Sopenharmony_ci}; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget peb2466_dapm_widgets[] = { 55462306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("CH0 PWR", PEB2466_CR1(0), 0, 0, NULL, 0), 55562306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("CH1 PWR", PEB2466_CR1(1), 0, 0, NULL, 0), 55662306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("CH2 PWR", PEB2466_CR1(2), 0, 0, NULL, 0), 55762306a36Sopenharmony_ci SND_SOC_DAPM_SUPPLY("CH3 PWR", PEB2466_CR1(3), 0, 0, NULL, 0), 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci SND_SOC_DAPM_DAC("CH0 DIN", "Playback", SND_SOC_NOPM, 0, 0), 56062306a36Sopenharmony_ci SND_SOC_DAPM_DAC("CH1 DIN", "Playback", SND_SOC_NOPM, 0, 0), 56162306a36Sopenharmony_ci SND_SOC_DAPM_DAC("CH2 DIN", "Playback", SND_SOC_NOPM, 0, 0), 56262306a36Sopenharmony_ci SND_SOC_DAPM_DAC("CH3 DIN", "Playback", SND_SOC_NOPM, 0, 0), 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH0 TG1"), 56562306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH1 TG1"), 56662306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH2 TG1"), 56762306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH3 TG1"), 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH0 TG2"), 57062306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH1 TG2"), 57162306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH2 TG2"), 57262306a36Sopenharmony_ci SND_SOC_DAPM_SIGGEN("CH3 TG2"), 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAC0 Mixer", SND_SOC_NOPM, 0, 0, 57562306a36Sopenharmony_ci peb2466_ch0_out_mix_controls, 57662306a36Sopenharmony_ci ARRAY_SIZE(peb2466_ch0_out_mix_controls)), 57762306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAC1 Mixer", SND_SOC_NOPM, 0, 0, 57862306a36Sopenharmony_ci peb2466_ch1_out_mix_controls, 57962306a36Sopenharmony_ci ARRAY_SIZE(peb2466_ch1_out_mix_controls)), 58062306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAC2 Mixer", SND_SOC_NOPM, 0, 0, 58162306a36Sopenharmony_ci peb2466_ch2_out_mix_controls, 58262306a36Sopenharmony_ci ARRAY_SIZE(peb2466_ch2_out_mix_controls)), 58362306a36Sopenharmony_ci SND_SOC_DAPM_MIXER("DAC3 Mixer", SND_SOC_NOPM, 0, 0, 58462306a36Sopenharmony_ci peb2466_ch3_out_mix_controls, 58562306a36Sopenharmony_ci ARRAY_SIZE(peb2466_ch3_out_mix_controls)), 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci SND_SOC_DAPM_PGA("DAC0 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 58862306a36Sopenharmony_ci SND_SOC_DAPM_PGA("DAC1 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 58962306a36Sopenharmony_ci SND_SOC_DAPM_PGA("DAC2 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 59062306a36Sopenharmony_ci SND_SOC_DAPM_PGA("DAC3 PGA", SND_SOC_NOPM, 0, 0, NULL, 0), 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT0"), 59362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT1"), 59462306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT2"), 59562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("OUT3"), 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("IN0"), 59862306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("IN1"), 59962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("IN2"), 60062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("IN3"), 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci SND_SOC_DAPM_DAC("ADC0", "Capture", SND_SOC_NOPM, 0, 0), 60362306a36Sopenharmony_ci SND_SOC_DAPM_DAC("ADC1", "Capture", SND_SOC_NOPM, 0, 0), 60462306a36Sopenharmony_ci SND_SOC_DAPM_DAC("ADC2", "Capture", SND_SOC_NOPM, 0, 0), 60562306a36Sopenharmony_ci SND_SOC_DAPM_DAC("ADC3", "Capture", SND_SOC_NOPM, 0, 0), 60662306a36Sopenharmony_ci}; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route peb2466_dapm_routes[] = { 60962306a36Sopenharmony_ci { "CH0 DIN", NULL, "CH0 PWR" }, 61062306a36Sopenharmony_ci { "CH1 DIN", NULL, "CH1 PWR" }, 61162306a36Sopenharmony_ci { "CH2 DIN", NULL, "CH2 PWR" }, 61262306a36Sopenharmony_ci { "CH3 DIN", NULL, "CH3 PWR" }, 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci { "CH0 TG1", NULL, "CH0 PWR" }, 61562306a36Sopenharmony_ci { "CH1 TG1", NULL, "CH1 PWR" }, 61662306a36Sopenharmony_ci { "CH2 TG1", NULL, "CH2 PWR" }, 61762306a36Sopenharmony_ci { "CH3 TG1", NULL, "CH3 PWR" }, 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci { "CH0 TG2", NULL, "CH0 PWR" }, 62062306a36Sopenharmony_ci { "CH1 TG2", NULL, "CH1 PWR" }, 62162306a36Sopenharmony_ci { "CH2 TG2", NULL, "CH2 PWR" }, 62262306a36Sopenharmony_ci { "CH3 TG2", NULL, "CH3 PWR" }, 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci { "DAC0 Mixer", "TG1 Switch", "CH0 TG1" }, 62562306a36Sopenharmony_ci { "DAC0 Mixer", "TG2 Switch", "CH0 TG2" }, 62662306a36Sopenharmony_ci { "DAC0 Mixer", "Voice Switch", "CH0 DIN" }, 62762306a36Sopenharmony_ci { "DAC0 Mixer", NULL, "CH0 DIN" }, 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci { "DAC1 Mixer", "TG1 Switch", "CH1 TG1" }, 63062306a36Sopenharmony_ci { "DAC1 Mixer", "TG2 Switch", "CH1 TG2" }, 63162306a36Sopenharmony_ci { "DAC1 Mixer", "Voice Switch", "CH1 DIN" }, 63262306a36Sopenharmony_ci { "DAC1 Mixer", NULL, "CH1 DIN" }, 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci { "DAC2 Mixer", "TG1 Switch", "CH2 TG1" }, 63562306a36Sopenharmony_ci { "DAC2 Mixer", "TG2 Switch", "CH2 TG2" }, 63662306a36Sopenharmony_ci { "DAC2 Mixer", "Voice Switch", "CH2 DIN" }, 63762306a36Sopenharmony_ci { "DAC2 Mixer", NULL, "CH2 DIN" }, 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci { "DAC3 Mixer", "TG1 Switch", "CH3 TG1" }, 64062306a36Sopenharmony_ci { "DAC3 Mixer", "TG2 Switch", "CH3 TG2" }, 64162306a36Sopenharmony_ci { "DAC3 Mixer", "Voice Switch", "CH3 DIN" }, 64262306a36Sopenharmony_ci { "DAC3 Mixer", NULL, "CH3 DIN" }, 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci { "DAC0 PGA", NULL, "DAC0 Mixer" }, 64562306a36Sopenharmony_ci { "DAC1 PGA", NULL, "DAC1 Mixer" }, 64662306a36Sopenharmony_ci { "DAC2 PGA", NULL, "DAC2 Mixer" }, 64762306a36Sopenharmony_ci { "DAC3 PGA", NULL, "DAC3 Mixer" }, 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci { "OUT0", NULL, "DAC0 PGA" }, 65062306a36Sopenharmony_ci { "OUT1", NULL, "DAC1 PGA" }, 65162306a36Sopenharmony_ci { "OUT2", NULL, "DAC2 PGA" }, 65262306a36Sopenharmony_ci { "OUT3", NULL, "DAC3 PGA" }, 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci { "ADC0", NULL, "IN0" }, 65562306a36Sopenharmony_ci { "ADC1", NULL, "IN1" }, 65662306a36Sopenharmony_ci { "ADC2", NULL, "IN2" }, 65762306a36Sopenharmony_ci { "ADC3", NULL, "IN3" }, 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci { "ADC0", NULL, "CH0 PWR" }, 66062306a36Sopenharmony_ci { "ADC1", NULL, "CH1 PWR" }, 66162306a36Sopenharmony_ci { "ADC2", NULL, "CH2 PWR" }, 66262306a36Sopenharmony_ci { "ADC3", NULL, "CH3 PWR" }, 66362306a36Sopenharmony_ci}; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_cistatic int peb2466_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask, 66662306a36Sopenharmony_ci unsigned int rx_mask, int slots, int width) 66762306a36Sopenharmony_ci{ 66862306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 66962306a36Sopenharmony_ci unsigned int chan; 67062306a36Sopenharmony_ci unsigned int mask; 67162306a36Sopenharmony_ci u8 slot; 67262306a36Sopenharmony_ci int ret; 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci switch (width) { 67562306a36Sopenharmony_ci case 0: 67662306a36Sopenharmony_ci /* Not set -> default 8 */ 67762306a36Sopenharmony_ci case 8: 67862306a36Sopenharmony_ci break; 67962306a36Sopenharmony_ci default: 68062306a36Sopenharmony_ci dev_err(dai->dev, "tdm slot width %d not supported\n", width); 68162306a36Sopenharmony_ci return -EINVAL; 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci mask = tx_mask; 68562306a36Sopenharmony_ci slot = 0; 68662306a36Sopenharmony_ci chan = 0; 68762306a36Sopenharmony_ci while (mask && chan < PEB2466_NB_CHANNEL) { 68862306a36Sopenharmony_ci if (mask & 0x1) { 68962306a36Sopenharmony_ci ret = regmap_write(peb2466->regmap, PEB2466_CR5(chan), slot); 69062306a36Sopenharmony_ci if (ret) { 69162306a36Sopenharmony_ci dev_err(dai->dev, "chan %d set tx tdm slot failed (%d)\n", 69262306a36Sopenharmony_ci chan, ret); 69362306a36Sopenharmony_ci return ret; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci chan++; 69662306a36Sopenharmony_ci } 69762306a36Sopenharmony_ci mask >>= 1; 69862306a36Sopenharmony_ci slot++; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci if (mask) { 70162306a36Sopenharmony_ci dev_err(dai->dev, "too much tx slots defined (mask = 0x%x) support max %d\n", 70262306a36Sopenharmony_ci tx_mask, PEB2466_NB_CHANNEL); 70362306a36Sopenharmony_ci return -EINVAL; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci peb2466->max_chan_playback = chan; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci mask = rx_mask; 70862306a36Sopenharmony_ci slot = 0; 70962306a36Sopenharmony_ci chan = 0; 71062306a36Sopenharmony_ci while (mask && chan < PEB2466_NB_CHANNEL) { 71162306a36Sopenharmony_ci if (mask & 0x1) { 71262306a36Sopenharmony_ci ret = regmap_write(peb2466->regmap, PEB2466_CR4(chan), slot); 71362306a36Sopenharmony_ci if (ret) { 71462306a36Sopenharmony_ci dev_err(dai->dev, "chan %d set rx tdm slot failed (%d)\n", 71562306a36Sopenharmony_ci chan, ret); 71662306a36Sopenharmony_ci return ret; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci chan++; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci mask >>= 1; 72162306a36Sopenharmony_ci slot++; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci if (mask) { 72462306a36Sopenharmony_ci dev_err(dai->dev, "too much rx slots defined (mask = 0x%x) support max %d\n", 72562306a36Sopenharmony_ci rx_mask, PEB2466_NB_CHANNEL); 72662306a36Sopenharmony_ci return -EINVAL; 72762306a36Sopenharmony_ci } 72862306a36Sopenharmony_ci peb2466->max_chan_capture = chan; 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci return 0; 73162306a36Sopenharmony_ci} 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_cistatic int peb2466_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) 73462306a36Sopenharmony_ci{ 73562306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 73662306a36Sopenharmony_ci u8 xr6; 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 73962306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 74062306a36Sopenharmony_ci xr6 = PEB2466_XR6_PCM_OFFSET(1); 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 74362306a36Sopenharmony_ci xr6 = PEB2466_XR6_PCM_OFFSET(0); 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci default: 74662306a36Sopenharmony_ci dev_err(dai->dev, "Unsupported format 0x%x\n", 74762306a36Sopenharmony_ci fmt & SND_SOC_DAIFMT_FORMAT_MASK); 74862306a36Sopenharmony_ci return -EINVAL; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci return regmap_write(peb2466->regmap, PEB2466_XR6, xr6); 75162306a36Sopenharmony_ci} 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_cistatic int peb2466_dai_hw_params(struct snd_pcm_substream *substream, 75462306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 75562306a36Sopenharmony_ci struct snd_soc_dai *dai) 75662306a36Sopenharmony_ci{ 75762306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 75862306a36Sopenharmony_ci unsigned int ch; 75962306a36Sopenharmony_ci int ret; 76062306a36Sopenharmony_ci u8 cr1; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci switch (params_format(params)) { 76362306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_MU_LAW: 76462306a36Sopenharmony_ci cr1 = PEB2466_CR1_LAW_MULAW; 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_A_LAW: 76762306a36Sopenharmony_ci cr1 = PEB2466_CR1_LAW_ALAW; 76862306a36Sopenharmony_ci break; 76962306a36Sopenharmony_ci default: 77062306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Unsupported format 0x%x\n", 77162306a36Sopenharmony_ci params_format(params)); 77262306a36Sopenharmony_ci return -EINVAL; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci for (ch = 0; ch < PEB2466_NB_CHANNEL; ch++) { 77662306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR1(ch), 77762306a36Sopenharmony_ci PEB2466_CR1_LAW_MASK, cr1); 77862306a36Sopenharmony_ci if (ret) 77962306a36Sopenharmony_ci return ret; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic const unsigned int peb2466_sample_bits[] = {8}; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic struct snd_pcm_hw_constraint_list peb2466_sample_bits_constr = { 78862306a36Sopenharmony_ci .list = peb2466_sample_bits, 78962306a36Sopenharmony_ci .count = ARRAY_SIZE(peb2466_sample_bits), 79062306a36Sopenharmony_ci}; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic int peb2466_dai_startup(struct snd_pcm_substream *substream, 79362306a36Sopenharmony_ci struct snd_soc_dai *dai) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(dai->component); 79662306a36Sopenharmony_ci unsigned int max_ch; 79762306a36Sopenharmony_ci int ret; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci max_ch = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 80062306a36Sopenharmony_ci peb2466->max_chan_playback : peb2466->max_chan_capture; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * Disable stream support (min = 0, max = 0) if no timeslots were 80462306a36Sopenharmony_ci * configured. 80562306a36Sopenharmony_ci */ 80662306a36Sopenharmony_ci ret = snd_pcm_hw_constraint_minmax(substream->runtime, 80762306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 80862306a36Sopenharmony_ci max_ch ? 1 : 0, max_ch); 80962306a36Sopenharmony_ci if (ret < 0) 81062306a36Sopenharmony_ci return ret; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return snd_pcm_hw_constraint_list(substream->runtime, 0, 81362306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 81462306a36Sopenharmony_ci &peb2466_sample_bits_constr); 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_cistatic u64 peb2466_dai_formats[] = { 81862306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_DSP_A | 81962306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_DSP_B, 82062306a36Sopenharmony_ci}; 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_cistatic const struct snd_soc_dai_ops peb2466_dai_ops = { 82362306a36Sopenharmony_ci .startup = peb2466_dai_startup, 82462306a36Sopenharmony_ci .hw_params = peb2466_dai_hw_params, 82562306a36Sopenharmony_ci .set_tdm_slot = peb2466_dai_set_tdm_slot, 82662306a36Sopenharmony_ci .set_fmt = peb2466_dai_set_fmt, 82762306a36Sopenharmony_ci .auto_selectable_formats = peb2466_dai_formats, 82862306a36Sopenharmony_ci .num_auto_selectable_formats = ARRAY_SIZE(peb2466_dai_formats), 82962306a36Sopenharmony_ci}; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_cistatic struct snd_soc_dai_driver peb2466_dai_driver = { 83262306a36Sopenharmony_ci .name = "peb2466", 83362306a36Sopenharmony_ci .playback = { 83462306a36Sopenharmony_ci .stream_name = "Playback", 83562306a36Sopenharmony_ci .channels_min = 1, 83662306a36Sopenharmony_ci .channels_max = PEB2466_NB_CHANNEL, 83762306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000, 83862306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, 83962306a36Sopenharmony_ci }, 84062306a36Sopenharmony_ci .capture = { 84162306a36Sopenharmony_ci .stream_name = "Capture", 84262306a36Sopenharmony_ci .channels_min = 1, 84362306a36Sopenharmony_ci .channels_max = PEB2466_NB_CHANNEL, 84462306a36Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000, 84562306a36Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_MU_LAW | SNDRV_PCM_FMTBIT_A_LAW, 84662306a36Sopenharmony_ci }, 84762306a36Sopenharmony_ci .ops = &peb2466_dai_ops, 84862306a36Sopenharmony_ci}; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_cistatic int peb2466_reset_audio(struct peb2466 *peb2466) 85162306a36Sopenharmony_ci{ 85262306a36Sopenharmony_ci static const struct reg_sequence reg_reset[] = { 85362306a36Sopenharmony_ci { .reg = PEB2466_XR6, .def = 0x00 }, 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci { .reg = PEB2466_CR5(0), .def = 0x00 }, 85662306a36Sopenharmony_ci { .reg = PEB2466_CR4(0), .def = 0x00 }, 85762306a36Sopenharmony_ci { .reg = PEB2466_CR3(0), .def = 0x00 }, 85862306a36Sopenharmony_ci { .reg = PEB2466_CR2(0), .def = 0x00 }, 85962306a36Sopenharmony_ci { .reg = PEB2466_CR1(0), .def = 0x00 }, 86062306a36Sopenharmony_ci { .reg = PEB2466_CR0(0), .def = PEB2466_CR0_IMR1 }, 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci { .reg = PEB2466_CR5(1), .def = 0x00 }, 86362306a36Sopenharmony_ci { .reg = PEB2466_CR4(1), .def = 0x00 }, 86462306a36Sopenharmony_ci { .reg = PEB2466_CR3(1), .def = 0x00 }, 86562306a36Sopenharmony_ci { .reg = PEB2466_CR2(1), .def = 0x00 }, 86662306a36Sopenharmony_ci { .reg = PEB2466_CR1(1), .def = 0x00 }, 86762306a36Sopenharmony_ci { .reg = PEB2466_CR0(1), .def = PEB2466_CR0_IMR1 }, 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci { .reg = PEB2466_CR5(2), .def = 0x00 }, 87062306a36Sopenharmony_ci { .reg = PEB2466_CR4(2), .def = 0x00 }, 87162306a36Sopenharmony_ci { .reg = PEB2466_CR3(2), .def = 0x00 }, 87262306a36Sopenharmony_ci { .reg = PEB2466_CR2(2), .def = 0x00 }, 87362306a36Sopenharmony_ci { .reg = PEB2466_CR1(2), .def = 0x00 }, 87462306a36Sopenharmony_ci { .reg = PEB2466_CR0(2), .def = PEB2466_CR0_IMR1 }, 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci { .reg = PEB2466_CR5(3), .def = 0x00 }, 87762306a36Sopenharmony_ci { .reg = PEB2466_CR4(3), .def = 0x00 }, 87862306a36Sopenharmony_ci { .reg = PEB2466_CR3(3), .def = 0x00 }, 87962306a36Sopenharmony_ci { .reg = PEB2466_CR2(3), .def = 0x00 }, 88062306a36Sopenharmony_ci { .reg = PEB2466_CR1(3), .def = 0x00 }, 88162306a36Sopenharmony_ci { .reg = PEB2466_CR0(3), .def = PEB2466_CR0_IMR1 }, 88262306a36Sopenharmony_ci }; 88362306a36Sopenharmony_ci static const u8 imr1_p1[8] = {0x00, 0x90, 0x09, 0x00, 0x90, 0x09, 0x00, 0x00}; 88462306a36Sopenharmony_ci static const u8 imr1_p2[8] = {0x7F, 0xFF, 0x00, 0x00, 0x90, 0x14, 0x40, 0x08}; 88562306a36Sopenharmony_ci static const u8 zero[8] = {0}; 88662306a36Sopenharmony_ci int ret; 88762306a36Sopenharmony_ci int i; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 89062306a36Sopenharmony_ci peb2466->ch[i].tg1_freq_item = PEB2466_TONE_1000HZ; 89162306a36Sopenharmony_ci peb2466->ch[i].tg2_freq_item = PEB2466_TONE_1000HZ; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* 89462306a36Sopenharmony_ci * Even if not used, disabling IM/R1 filter is not recommended. 89562306a36Sopenharmony_ci * Instead, we must configure it with default coefficients and 89662306a36Sopenharmony_ci * enable it. 89762306a36Sopenharmony_ci * The filter will be enabled right after (in the following 89862306a36Sopenharmony_ci * regmap_multi_reg_write() call). 89962306a36Sopenharmony_ci */ 90062306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), imr1_p1, 8); 90162306a36Sopenharmony_ci if (ret) 90262306a36Sopenharmony_ci return ret; 90362306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), imr1_p2, 8); 90462306a36Sopenharmony_ci if (ret) 90562306a36Sopenharmony_ci return ret; 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci /* Set all other filters coefficients to zero */ 90862306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), zero, 8); 90962306a36Sopenharmony_ci if (ret) 91062306a36Sopenharmony_ci return ret; 91162306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), zero, 8); 91262306a36Sopenharmony_ci if (ret) 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), zero, 8); 91562306a36Sopenharmony_ci if (ret) 91662306a36Sopenharmony_ci return ret; 91762306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), zero, 8); 91862306a36Sopenharmony_ci if (ret) 91962306a36Sopenharmony_ci return ret; 92062306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), zero, 8); 92162306a36Sopenharmony_ci if (ret) 92262306a36Sopenharmony_ci return ret; 92362306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), zero, 4); 92462306a36Sopenharmony_ci if (ret) 92562306a36Sopenharmony_ci return ret; 92662306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), zero, 4); 92762306a36Sopenharmony_ci if (ret) 92862306a36Sopenharmony_ci return ret; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci return regmap_multi_reg_write(peb2466->regmap, reg_reset, ARRAY_SIZE(reg_reset)); 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_cistatic int peb2466_fw_parse_thfilter(struct snd_soc_component *component, 93562306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 93662306a36Sopenharmony_ci{ 93762306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 93862306a36Sopenharmony_ci u8 mask; 93962306a36Sopenharmony_ci int ret; 94062306a36Sopenharmony_ci int i; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci dev_info(component->dev, "fw TH filter: mask %x, %*phN\n", *data, 94362306a36Sopenharmony_ci lng - 1, data + 1); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* 94662306a36Sopenharmony_ci * TH_FILTER TLV data: 94762306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 94862306a36Sopenharmony_ci * - @1 8 bytes: TH-Filter coefficients part1 94962306a36Sopenharmony_ci * - @9 8 bytes: TH-Filter coefficients part2 95062306a36Sopenharmony_ci * - @17 8 bytes: TH-Filter coefficients part3 95162306a36Sopenharmony_ci */ 95262306a36Sopenharmony_ci mask = *data; 95362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 95462306a36Sopenharmony_ci if (!(mask & (1 << i))) 95562306a36Sopenharmony_ci continue; 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 95862306a36Sopenharmony_ci PEB2466_CR0_TH, 0); 95962306a36Sopenharmony_ci if (ret) 96062306a36Sopenharmony_ci return ret; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P1(i), data + 1, 8); 96362306a36Sopenharmony_ci if (ret) 96462306a36Sopenharmony_ci return ret; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P2(i), data + 9, 8); 96762306a36Sopenharmony_ci if (ret) 96862306a36Sopenharmony_ci return ret; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_TH_FILTER_P3(i), data + 17, 8); 97162306a36Sopenharmony_ci if (ret) 97262306a36Sopenharmony_ci return ret; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 97562306a36Sopenharmony_ci PEB2466_CR0_TH | PEB2466_CR0_THSEL_MASK, 97662306a36Sopenharmony_ci PEB2466_CR0_TH | PEB2466_CR0_THSEL(i)); 97762306a36Sopenharmony_ci if (ret) 97862306a36Sopenharmony_ci return ret; 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci return 0; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic int peb2466_fw_parse_imr1filter(struct snd_soc_component *component, 98462306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 98762306a36Sopenharmony_ci u8 mask; 98862306a36Sopenharmony_ci int ret; 98962306a36Sopenharmony_ci int i; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci dev_info(component->dev, "fw IM/R1 filter: mask %x, %*phN\n", *data, 99262306a36Sopenharmony_ci lng - 1, data + 1); 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci /* 99562306a36Sopenharmony_ci * IMR1_FILTER TLV data: 99662306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 99762306a36Sopenharmony_ci * - @1 8 bytes: IM/R1-Filter coefficients part1 99862306a36Sopenharmony_ci * - @9 8 bytes: IM/R1-Filter coefficients part2 99962306a36Sopenharmony_ci */ 100062306a36Sopenharmony_ci mask = *data; 100162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 100262306a36Sopenharmony_ci if (!(mask & (1 << i))) 100362306a36Sopenharmony_ci continue; 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 100662306a36Sopenharmony_ci PEB2466_CR0_IMR1, 0); 100762306a36Sopenharmony_ci if (ret) 100862306a36Sopenharmony_ci return ret; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P1(i), data + 1, 8); 101162306a36Sopenharmony_ci if (ret) 101262306a36Sopenharmony_ci return ret; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_IMR1_FILTER_P2(i), data + 9, 8); 101562306a36Sopenharmony_ci if (ret) 101662306a36Sopenharmony_ci return ret; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 101962306a36Sopenharmony_ci PEB2466_CR0_IMR1, PEB2466_CR0_IMR1); 102062306a36Sopenharmony_ci if (ret) 102162306a36Sopenharmony_ci return ret; 102262306a36Sopenharmony_ci } 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic int peb2466_fw_parse_frxfilter(struct snd_soc_component *component, 102762306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 102862306a36Sopenharmony_ci{ 102962306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 103062306a36Sopenharmony_ci u8 mask; 103162306a36Sopenharmony_ci int ret; 103262306a36Sopenharmony_ci int i; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci dev_info(component->dev, "fw FRX filter: mask %x, %*phN\n", *data, 103562306a36Sopenharmony_ci lng - 1, data + 1); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* 103862306a36Sopenharmony_ci * FRX_FILTER TLV data: 103962306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 104062306a36Sopenharmony_ci * - @1 8 bytes: FRX-Filter coefficients 104162306a36Sopenharmony_ci */ 104262306a36Sopenharmony_ci mask = *data; 104362306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 104462306a36Sopenharmony_ci if (!(mask & (1 << i))) 104562306a36Sopenharmony_ci continue; 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 104862306a36Sopenharmony_ci PEB2466_CR0_FRX, 0); 104962306a36Sopenharmony_ci if (ret) 105062306a36Sopenharmony_ci return ret; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_FRX_FILTER(i), data + 1, 8); 105362306a36Sopenharmony_ci if (ret) 105462306a36Sopenharmony_ci return ret; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 105762306a36Sopenharmony_ci PEB2466_CR0_FRX, PEB2466_CR0_FRX); 105862306a36Sopenharmony_ci if (ret) 105962306a36Sopenharmony_ci return ret; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci return 0; 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_cistatic int peb2466_fw_parse_frrfilter(struct snd_soc_component *component, 106562306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 106862306a36Sopenharmony_ci u8 mask; 106962306a36Sopenharmony_ci int ret; 107062306a36Sopenharmony_ci int i; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci dev_info(component->dev, "fw FRR filter: mask %x, %*phN\n", *data, 107362306a36Sopenharmony_ci lng - 1, data + 1); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci /* 107662306a36Sopenharmony_ci * FRR_FILTER TLV data: 107762306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 107862306a36Sopenharmony_ci * - @1 8 bytes: FRR-Filter coefficients 107962306a36Sopenharmony_ci */ 108062306a36Sopenharmony_ci mask = *data; 108162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 108262306a36Sopenharmony_ci if (!(mask & (1 << i))) 108362306a36Sopenharmony_ci continue; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 108662306a36Sopenharmony_ci PEB2466_CR0_FRR, 0); 108762306a36Sopenharmony_ci if (ret) 108862306a36Sopenharmony_ci return ret; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_FRR_FILTER(i), data + 1, 8); 109162306a36Sopenharmony_ci if (ret) 109262306a36Sopenharmony_ci return ret; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 109562306a36Sopenharmony_ci PEB2466_CR0_FRR, PEB2466_CR0_FRR); 109662306a36Sopenharmony_ci if (ret) 109762306a36Sopenharmony_ci return ret; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int peb2466_fw_parse_axfilter(struct snd_soc_component *component, 110362306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 110662306a36Sopenharmony_ci u8 mask; 110762306a36Sopenharmony_ci int ret; 110862306a36Sopenharmony_ci int i; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci dev_info(component->dev, "fw AX filter: mask %x, %*phN\n", *data, 111162306a36Sopenharmony_ci lng - 1, data + 1); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci /* 111462306a36Sopenharmony_ci * AX_FILTER TLV data: 111562306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 111662306a36Sopenharmony_ci * - @1 4 bytes: AX-Filter coefficients 111762306a36Sopenharmony_ci */ 111862306a36Sopenharmony_ci mask = *data; 111962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 112062306a36Sopenharmony_ci if (!(mask & (1 << i))) 112162306a36Sopenharmony_ci continue; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 112462306a36Sopenharmony_ci PEB2466_CR0_AX, 0); 112562306a36Sopenharmony_ci if (ret) 112662306a36Sopenharmony_ci return ret; 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), data + 1, 4); 112962306a36Sopenharmony_ci if (ret) 113062306a36Sopenharmony_ci return ret; 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 113362306a36Sopenharmony_ci PEB2466_CR0_AX, PEB2466_CR0_AX); 113462306a36Sopenharmony_ci if (ret) 113562306a36Sopenharmony_ci return ret; 113662306a36Sopenharmony_ci } 113762306a36Sopenharmony_ci return 0; 113862306a36Sopenharmony_ci} 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cistatic int peb2466_fw_parse_arfilter(struct snd_soc_component *component, 114162306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 114262306a36Sopenharmony_ci{ 114362306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 114462306a36Sopenharmony_ci u8 mask; 114562306a36Sopenharmony_ci int ret; 114662306a36Sopenharmony_ci int i; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci dev_info(component->dev, "fw AR filter: mask %x, %*phN\n", *data, 114962306a36Sopenharmony_ci lng - 1, data + 1); 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* 115262306a36Sopenharmony_ci * AR_FILTER TLV data: 115362306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 115462306a36Sopenharmony_ci * - @1 4 bytes: AR-Filter coefficients 115562306a36Sopenharmony_ci */ 115662306a36Sopenharmony_ci mask = *data; 115762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 115862306a36Sopenharmony_ci if (!(mask & (1 << i))) 115962306a36Sopenharmony_ci continue; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 116262306a36Sopenharmony_ci PEB2466_CR0_AR, 0); 116362306a36Sopenharmony_ci if (ret) 116462306a36Sopenharmony_ci return ret; 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), data + 1, 4); 116762306a36Sopenharmony_ci if (ret) 116862306a36Sopenharmony_ci return ret; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 117162306a36Sopenharmony_ci PEB2466_CR0_AR, PEB2466_CR0_AR); 117262306a36Sopenharmony_ci if (ret) 117362306a36Sopenharmony_ci return ret; 117462306a36Sopenharmony_ci } 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_cistatic const char * const peb2466_ax_ctrl_names[] = { 117962306a36Sopenharmony_ci "ADC0 Capture Volume", 118062306a36Sopenharmony_ci "ADC1 Capture Volume", 118162306a36Sopenharmony_ci "ADC2 Capture Volume", 118262306a36Sopenharmony_ci "ADC3 Capture Volume", 118362306a36Sopenharmony_ci}; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_cistatic int peb2466_fw_parse_axtable(struct snd_soc_component *component, 118662306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 118962306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl; 119062306a36Sopenharmony_ci struct peb2466_lookup *lookup; 119162306a36Sopenharmony_ci u8 (*table)[4]; 119262306a36Sopenharmony_ci u32 table_size; 119362306a36Sopenharmony_ci u32 init_index; 119462306a36Sopenharmony_ci s32 min_val; 119562306a36Sopenharmony_ci s32 step; 119662306a36Sopenharmony_ci u8 mask; 119762306a36Sopenharmony_ci int ret; 119862306a36Sopenharmony_ci int i; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * AX_TABLE TLV data: 120262306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 120362306a36Sopenharmony_ci * - @1 32bits signed: Min table value in centi dB (MinVal) 120462306a36Sopenharmony_ci * ie -300 means -3.0 dB 120562306a36Sopenharmony_ci * - @5 32bits signed: Step from on item to other item in centi dB (Step) 120662306a36Sopenharmony_ci * ie 25 means 0.25 dB) 120762306a36Sopenharmony_ci * - @9 32bits unsigned: Item index in the table to use for the initial 120862306a36Sopenharmony_ci * value 120962306a36Sopenharmony_ci * - @13 N*4 bytes: Table composed of 4 bytes items. 121062306a36Sopenharmony_ci * Each item correspond to an AX filter value. 121162306a36Sopenharmony_ci * 121262306a36Sopenharmony_ci * The conversion from raw value item in the table to/from the value in 121362306a36Sopenharmony_ci * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. 121462306a36Sopenharmony_ci */ 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* Check Lng and extract the table size. */ 121762306a36Sopenharmony_ci if (lng < 13 || ((lng - 13) % 4)) { 121862306a36Sopenharmony_ci dev_err(component->dev, "fw AX table lng %u invalid\n", lng); 121962306a36Sopenharmony_ci return -EINVAL; 122062306a36Sopenharmony_ci } 122162306a36Sopenharmony_ci table_size = lng - 13; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci min_val = get_unaligned_be32(data + 1); 122462306a36Sopenharmony_ci step = get_unaligned_be32(data + 5); 122562306a36Sopenharmony_ci init_index = get_unaligned_be32(data + 9); 122662306a36Sopenharmony_ci if (init_index >= (table_size / 4)) { 122762306a36Sopenharmony_ci dev_err(component->dev, "fw AX table index %u out of table[%u]\n", 122862306a36Sopenharmony_ci init_index, table_size / 4); 122962306a36Sopenharmony_ci return -EINVAL; 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci dev_info(component->dev, 123362306a36Sopenharmony_ci "fw AX table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n", 123462306a36Sopenharmony_ci *data, min_val, step, table_size / 4, init_index, 123562306a36Sopenharmony_ci 4, data + 13 + (init_index * 4)); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(*table) != 4); 123862306a36Sopenharmony_ci table = devm_kzalloc(&peb2466->spi->dev, table_size, GFP_KERNEL); 123962306a36Sopenharmony_ci if (!table) 124062306a36Sopenharmony_ci return -ENOMEM; 124162306a36Sopenharmony_ci memcpy(table, data + 13, table_size); 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci mask = *data; 124462306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(peb2466_ax_ctrl_names) != ARRAY_SIZE(peb2466->ch)); 124562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 124662306a36Sopenharmony_ci if (!(mask & (1 << i))) 124762306a36Sopenharmony_ci continue; 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci lookup = &peb2466->ch[i].ax_lookup; 125062306a36Sopenharmony_ci lookup->table = table; 125162306a36Sopenharmony_ci lookup->count = table_size / 4; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 125462306a36Sopenharmony_ci PEB2466_CR0_AX, 0); 125562306a36Sopenharmony_ci if (ret) 125662306a36Sopenharmony_ci return ret; 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AX_FILTER(i), 125962306a36Sopenharmony_ci lookup->table[init_index], 4); 126062306a36Sopenharmony_ci if (ret) 126162306a36Sopenharmony_ci return ret; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 126462306a36Sopenharmony_ci PEB2466_CR0_AX, PEB2466_CR0_AX); 126562306a36Sopenharmony_ci if (ret) 126662306a36Sopenharmony_ci return ret; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci lkup_ctrl = &peb2466->ch[i].ax_lkup_ctrl; 126962306a36Sopenharmony_ci lkup_ctrl->lookup = lookup; 127062306a36Sopenharmony_ci lkup_ctrl->reg = PEB2466_AX_FILTER(i); 127162306a36Sopenharmony_ci lkup_ctrl->index = init_index; 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, 127462306a36Sopenharmony_ci peb2466_ax_ctrl_names[i], 127562306a36Sopenharmony_ci min_val, step); 127662306a36Sopenharmony_ci if (ret) 127762306a36Sopenharmony_ci return ret; 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci return 0; 128062306a36Sopenharmony_ci} 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_cistatic const char * const peb2466_ar_ctrl_names[] = { 128362306a36Sopenharmony_ci "DAC0 Playback Volume", 128462306a36Sopenharmony_ci "DAC1 Playback Volume", 128562306a36Sopenharmony_ci "DAC2 Playback Volume", 128662306a36Sopenharmony_ci "DAC3 Playback Volume", 128762306a36Sopenharmony_ci}; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_cistatic int peb2466_fw_parse_artable(struct snd_soc_component *component, 129062306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data) 129162306a36Sopenharmony_ci{ 129262306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 129362306a36Sopenharmony_ci struct peb2466_lkup_ctrl *lkup_ctrl; 129462306a36Sopenharmony_ci struct peb2466_lookup *lookup; 129562306a36Sopenharmony_ci u8 (*table)[4]; 129662306a36Sopenharmony_ci u32 table_size; 129762306a36Sopenharmony_ci u32 init_index; 129862306a36Sopenharmony_ci s32 min_val; 129962306a36Sopenharmony_ci s32 step; 130062306a36Sopenharmony_ci u8 mask; 130162306a36Sopenharmony_ci int ret; 130262306a36Sopenharmony_ci int i; 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci /* 130562306a36Sopenharmony_ci * AR_TABLE TLV data: 130662306a36Sopenharmony_ci * - @0 1 byte: Chan mask (bit set means related channel is concerned) 130762306a36Sopenharmony_ci * - @1 32bits signed: Min table value in centi dB (MinVal) 130862306a36Sopenharmony_ci * ie -300 means -3.0 dB 130962306a36Sopenharmony_ci * - @5 32bits signed: Step from on item to other item in centi dB (Step) 131062306a36Sopenharmony_ci * ie 25 means 0.25 dB) 131162306a36Sopenharmony_ci * - @9 32bits unsigned: Item index in the table to use for the initial 131262306a36Sopenharmony_ci * value 131362306a36Sopenharmony_ci * - @13 N*4 bytes: Table composed of 4 bytes items. 131462306a36Sopenharmony_ci * Each item correspond to an AR filter value. 131562306a36Sopenharmony_ci * 131662306a36Sopenharmony_ci * The conversion from raw value item in the table to/from the value in 131762306a36Sopenharmony_ci * dB is: Raw value at index i <-> (MinVal + i * Step) in centi dB. 131862306a36Sopenharmony_ci */ 131962306a36Sopenharmony_ci 132062306a36Sopenharmony_ci /* Check Lng and extract the table size. */ 132162306a36Sopenharmony_ci if (lng < 13 || ((lng - 13) % 4)) { 132262306a36Sopenharmony_ci dev_err(component->dev, "fw AR table lng %u invalid\n", lng); 132362306a36Sopenharmony_ci return -EINVAL; 132462306a36Sopenharmony_ci } 132562306a36Sopenharmony_ci table_size = lng - 13; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci min_val = get_unaligned_be32(data + 1); 132862306a36Sopenharmony_ci step = get_unaligned_be32(data + 5); 132962306a36Sopenharmony_ci init_index = get_unaligned_be32(data + 9); 133062306a36Sopenharmony_ci if (init_index >= (table_size / 4)) { 133162306a36Sopenharmony_ci dev_err(component->dev, "fw AR table index %u out of table[%u]\n", 133262306a36Sopenharmony_ci init_index, table_size / 4); 133362306a36Sopenharmony_ci return -EINVAL; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci dev_info(component->dev, 133762306a36Sopenharmony_ci "fw AR table: mask %x, min %d, step %d, %u items, tbl[%u] %*phN\n", 133862306a36Sopenharmony_ci *data, min_val, step, table_size / 4, init_index, 133962306a36Sopenharmony_ci 4, data + 13 + (init_index * 4)); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(*table) != 4); 134262306a36Sopenharmony_ci table = devm_kzalloc(&peb2466->spi->dev, table_size, GFP_KERNEL); 134362306a36Sopenharmony_ci if (!table) 134462306a36Sopenharmony_ci return -ENOMEM; 134562306a36Sopenharmony_ci memcpy(table, data + 13, table_size); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci mask = *data; 134862306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(peb2466_ar_ctrl_names) != ARRAY_SIZE(peb2466->ch)); 134962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466->ch); i++) { 135062306a36Sopenharmony_ci if (!(mask & (1 << i))) 135162306a36Sopenharmony_ci continue; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci lookup = &peb2466->ch[i].ar_lookup; 135462306a36Sopenharmony_ci lookup->table = table; 135562306a36Sopenharmony_ci lookup->count = table_size / 4; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 135862306a36Sopenharmony_ci PEB2466_CR0_AR, 0); 135962306a36Sopenharmony_ci if (ret) 136062306a36Sopenharmony_ci return ret; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci ret = peb2466_write_buf(peb2466, PEB2466_AR_FILTER(i), 136362306a36Sopenharmony_ci lookup->table[init_index], 4); 136462306a36Sopenharmony_ci if (ret) 136562306a36Sopenharmony_ci return ret; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = regmap_update_bits(peb2466->regmap, PEB2466_CR0(i), 136862306a36Sopenharmony_ci PEB2466_CR0_AR, PEB2466_CR0_AR); 136962306a36Sopenharmony_ci if (ret) 137062306a36Sopenharmony_ci return ret; 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci lkup_ctrl = &peb2466->ch[i].ar_lkup_ctrl; 137362306a36Sopenharmony_ci lkup_ctrl->lookup = lookup; 137462306a36Sopenharmony_ci lkup_ctrl->reg = PEB2466_AR_FILTER(i); 137562306a36Sopenharmony_ci lkup_ctrl->index = init_index; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci ret = peb2466_add_lkup_ctrl(component, lkup_ctrl, 137862306a36Sopenharmony_ci peb2466_ar_ctrl_names[i], 137962306a36Sopenharmony_ci min_val, step); 138062306a36Sopenharmony_ci if (ret) 138162306a36Sopenharmony_ci return ret; 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci return 0; 138462306a36Sopenharmony_ci} 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_cistruct peb2466_fw_tag_def { 138762306a36Sopenharmony_ci u16 tag; 138862306a36Sopenharmony_ci u32 lng_min; 138962306a36Sopenharmony_ci u32 lng_max; 139062306a36Sopenharmony_ci int (*parse)(struct snd_soc_component *component, 139162306a36Sopenharmony_ci u16 tag, u32 lng, const u8 *data); 139262306a36Sopenharmony_ci}; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci#define PEB2466_TAG_DEF_LNG_EQ(__tag, __lng, __parse) { \ 139562306a36Sopenharmony_ci .tag = __tag, \ 139662306a36Sopenharmony_ci .lng_min = __lng, \ 139762306a36Sopenharmony_ci .lng_max = __lng, \ 139862306a36Sopenharmony_ci .parse = __parse, \ 139962306a36Sopenharmony_ci} 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci#define PEB2466_TAG_DEF_LNG_MIN(__tag, __lng_min, __parse) { \ 140262306a36Sopenharmony_ci .tag = __tag, \ 140362306a36Sopenharmony_ci .lng_min = __lng_min, \ 140462306a36Sopenharmony_ci .lng_max = U32_MAX, \ 140562306a36Sopenharmony_ci .parse = __parse, \ 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic const struct peb2466_fw_tag_def peb2466_fw_tag_defs[] = { 140962306a36Sopenharmony_ci /* TH FILTER */ 141062306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0001, 1 + 3 * 8, peb2466_fw_parse_thfilter), 141162306a36Sopenharmony_ci /* IMR1 FILTER */ 141262306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0002, 1 + 2 * 8, peb2466_fw_parse_imr1filter), 141362306a36Sopenharmony_ci /* FRX FILTER */ 141462306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0003, 1 + 8, peb2466_fw_parse_frxfilter), 141562306a36Sopenharmony_ci /* FRR FILTER */ 141662306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0004, 1 + 8, peb2466_fw_parse_frrfilter), 141762306a36Sopenharmony_ci /* AX FILTER */ 141862306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0005, 1 + 4, peb2466_fw_parse_axfilter), 141962306a36Sopenharmony_ci /* AR FILTER */ 142062306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_EQ(0x0006, 1 + 4, peb2466_fw_parse_arfilter), 142162306a36Sopenharmony_ci /* AX TABLE */ 142262306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_MIN(0x0105, 1 + 3 * 4, peb2466_fw_parse_axtable), 142362306a36Sopenharmony_ci /* AR TABLE */ 142462306a36Sopenharmony_ci PEB2466_TAG_DEF_LNG_MIN(0x0106, 1 + 3 * 4, peb2466_fw_parse_artable), 142562306a36Sopenharmony_ci}; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_cistatic const struct peb2466_fw_tag_def *peb2466_fw_get_tag_def(u16 tag) 142862306a36Sopenharmony_ci{ 142962306a36Sopenharmony_ci int i; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(peb2466_fw_tag_defs); i++) { 143262306a36Sopenharmony_ci if (peb2466_fw_tag_defs[i].tag == tag) 143362306a36Sopenharmony_ci return &peb2466_fw_tag_defs[i]; 143462306a36Sopenharmony_ci } 143562306a36Sopenharmony_ci return NULL; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic int peb2466_fw_parse(struct snd_soc_component *component, 143962306a36Sopenharmony_ci const u8 *data, size_t size) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci const struct peb2466_fw_tag_def *tag_def; 144262306a36Sopenharmony_ci size_t left; 144362306a36Sopenharmony_ci const u8 *buf; 144462306a36Sopenharmony_ci u16 val16; 144562306a36Sopenharmony_ci u16 tag; 144662306a36Sopenharmony_ci u32 lng; 144762306a36Sopenharmony_ci int ret; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci /* 145062306a36Sopenharmony_ci * Coefficients firmware binary structure (16bits and 32bits are 145162306a36Sopenharmony_ci * big-endian values). 145262306a36Sopenharmony_ci * 145362306a36Sopenharmony_ci * @0, 16bits: Magic (0x2466) 145462306a36Sopenharmony_ci * @2, 16bits: Version (0x0100 for version 1.0) 145562306a36Sopenharmony_ci * @4, 2+4+N bytes: TLV block 145662306a36Sopenharmony_ci * @4+(2+4+N) bytes: Next TLV block 145762306a36Sopenharmony_ci * ... 145862306a36Sopenharmony_ci * 145962306a36Sopenharmony_ci * Detail of a TLV block: 146062306a36Sopenharmony_ci * @0, 16bits: Tag 146162306a36Sopenharmony_ci * @2, 32bits: Lng 146262306a36Sopenharmony_ci * @6, lng bytes: Data 146362306a36Sopenharmony_ci * 146462306a36Sopenharmony_ci * The detail the Data for a given TLV Tag is provided in the related 146562306a36Sopenharmony_ci * parser. 146662306a36Sopenharmony_ci */ 146762306a36Sopenharmony_ci 146862306a36Sopenharmony_ci left = size; 146962306a36Sopenharmony_ci buf = data; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci if (left < 4) { 147262306a36Sopenharmony_ci dev_err(component->dev, "fw size %zu, exp at least 4\n", left); 147362306a36Sopenharmony_ci return -EINVAL; 147462306a36Sopenharmony_ci } 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci /* Check magic */ 147762306a36Sopenharmony_ci val16 = get_unaligned_be16(buf); 147862306a36Sopenharmony_ci if (val16 != 0x2466) { 147962306a36Sopenharmony_ci dev_err(component->dev, "fw magic 0x%04x exp 0x2466\n", val16); 148062306a36Sopenharmony_ci return -EINVAL; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci buf += 2; 148362306a36Sopenharmony_ci left -= 2; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci /* Check version */ 148662306a36Sopenharmony_ci val16 = get_unaligned_be16(buf); 148762306a36Sopenharmony_ci if (val16 != 0x0100) { 148862306a36Sopenharmony_ci dev_err(component->dev, "fw magic 0x%04x exp 0x0100\n", val16); 148962306a36Sopenharmony_ci return -EINVAL; 149062306a36Sopenharmony_ci } 149162306a36Sopenharmony_ci buf += 2; 149262306a36Sopenharmony_ci left -= 2; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci while (left) { 149562306a36Sopenharmony_ci if (left < 6) { 149662306a36Sopenharmony_ci dev_err(component->dev, "fw %td/%zu left %zu, exp at least 6\n", 149762306a36Sopenharmony_ci buf - data, size, left); 149862306a36Sopenharmony_ci return -EINVAL; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci /* Check tag and lng */ 150162306a36Sopenharmony_ci tag = get_unaligned_be16(buf); 150262306a36Sopenharmony_ci lng = get_unaligned_be32(buf + 2); 150362306a36Sopenharmony_ci tag_def = peb2466_fw_get_tag_def(tag); 150462306a36Sopenharmony_ci if (!tag_def) { 150562306a36Sopenharmony_ci dev_err(component->dev, "fw %td/%zu tag 0x%04x unknown\n", 150662306a36Sopenharmony_ci buf - data, size, tag); 150762306a36Sopenharmony_ci return -EINVAL; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci if (lng < tag_def->lng_min || lng > tag_def->lng_max) { 151062306a36Sopenharmony_ci dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, exp [%u;%u]\n", 151162306a36Sopenharmony_ci buf - data, size, tag, lng, tag_def->lng_min, tag_def->lng_max); 151262306a36Sopenharmony_ci return -EINVAL; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci buf += 6; 151562306a36Sopenharmony_ci left -= 6; 151662306a36Sopenharmony_ci if (left < lng) { 151762306a36Sopenharmony_ci dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u, left %zu\n", 151862306a36Sopenharmony_ci buf - data, size, tag, lng, left); 151962306a36Sopenharmony_ci return -EINVAL; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci /* TLV block is valid -> parse the data part */ 152362306a36Sopenharmony_ci ret = tag_def->parse(component, tag, lng, buf); 152462306a36Sopenharmony_ci if (ret) { 152562306a36Sopenharmony_ci dev_err(component->dev, "fw %td/%zu tag 0x%04x lng %u parse failed\n", 152662306a36Sopenharmony_ci buf - data, size, tag, lng); 152762306a36Sopenharmony_ci return ret; 152862306a36Sopenharmony_ci } 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci buf += lng; 153162306a36Sopenharmony_ci left -= lng; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci return 0; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic int peb2466_load_coeffs(struct snd_soc_component *component, const char *fw_name) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci const struct firmware *fw; 153962306a36Sopenharmony_ci int ret; 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ci ret = request_firmware(&fw, fw_name, component->dev); 154262306a36Sopenharmony_ci if (ret) 154362306a36Sopenharmony_ci return ret; 154462306a36Sopenharmony_ci 154562306a36Sopenharmony_ci ret = peb2466_fw_parse(component, fw->data, fw->size); 154662306a36Sopenharmony_ci release_firmware(fw); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci return ret; 154962306a36Sopenharmony_ci} 155062306a36Sopenharmony_ci 155162306a36Sopenharmony_cistatic int peb2466_component_probe(struct snd_soc_component *component) 155262306a36Sopenharmony_ci{ 155362306a36Sopenharmony_ci struct peb2466 *peb2466 = snd_soc_component_get_drvdata(component); 155462306a36Sopenharmony_ci const char *firmware_name; 155562306a36Sopenharmony_ci int ret; 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci /* reset peb2466 audio part */ 155862306a36Sopenharmony_ci ret = peb2466_reset_audio(peb2466); 155962306a36Sopenharmony_ci if (ret) 156062306a36Sopenharmony_ci return ret; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci ret = of_property_read_string(peb2466->spi->dev.of_node, 156362306a36Sopenharmony_ci "firmware-name", &firmware_name); 156462306a36Sopenharmony_ci if (ret) 156562306a36Sopenharmony_ci return (ret == -EINVAL) ? 0 : ret; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci return peb2466_load_coeffs(component, firmware_name); 156862306a36Sopenharmony_ci} 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cistatic const struct snd_soc_component_driver peb2466_component_driver = { 157162306a36Sopenharmony_ci .probe = peb2466_component_probe, 157262306a36Sopenharmony_ci .controls = peb2466_controls, 157362306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(peb2466_controls), 157462306a36Sopenharmony_ci .dapm_widgets = peb2466_dapm_widgets, 157562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(peb2466_dapm_widgets), 157662306a36Sopenharmony_ci .dapm_routes = peb2466_dapm_routes, 157762306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(peb2466_dapm_routes), 157862306a36Sopenharmony_ci .endianness = 1, 157962306a36Sopenharmony_ci}; 158062306a36Sopenharmony_ci 158162306a36Sopenharmony_ci/* 158262306a36Sopenharmony_ci * The mapping used for the relationship between the gpio offset and the 158362306a36Sopenharmony_ci * physical pin is the following: 158462306a36Sopenharmony_ci * 158562306a36Sopenharmony_ci * offset pin 158662306a36Sopenharmony_ci * 0 SI1_0 158762306a36Sopenharmony_ci * 1 SI1_1 158862306a36Sopenharmony_ci * 2 SI2_0 158962306a36Sopenharmony_ci * 3 SI2_1 159062306a36Sopenharmony_ci * 4 SI3_0 159162306a36Sopenharmony_ci * 5 SI3_1 159262306a36Sopenharmony_ci * 6 SI4_0 159362306a36Sopenharmony_ci * 7 SI4_1 159462306a36Sopenharmony_ci * 8 SO1_0 159562306a36Sopenharmony_ci * 9 SO1_1 159662306a36Sopenharmony_ci * 10 SO2_0 159762306a36Sopenharmony_ci * 11 SO2_1 159862306a36Sopenharmony_ci * 12 SO3_0 159962306a36Sopenharmony_ci * 13 SO3_1 160062306a36Sopenharmony_ci * 14 SO4_0 160162306a36Sopenharmony_ci * 15 SO4_1 160262306a36Sopenharmony_ci * 16 SB1_0 160362306a36Sopenharmony_ci * 17 SB1_1 160462306a36Sopenharmony_ci * 18 SB2_0 160562306a36Sopenharmony_ci * 19 SB2_1 160662306a36Sopenharmony_ci * 20 SB3_0 160762306a36Sopenharmony_ci * 21 SB3_1 160862306a36Sopenharmony_ci * 22 SB4_0 160962306a36Sopenharmony_ci * 23 SB4_1 161062306a36Sopenharmony_ci * 24 SB1_2 161162306a36Sopenharmony_ci * 25 SB2_2 161262306a36Sopenharmony_ci * 26 SB3_2 161362306a36Sopenharmony_ci * 27 SB4_2 161462306a36Sopenharmony_ci */ 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic int peb2466_chip_gpio_offset_to_data_regmask(unsigned int offset, 161762306a36Sopenharmony_ci unsigned int *xr_reg, 161862306a36Sopenharmony_ci unsigned int *mask) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci if (offset < 16) { 162162306a36Sopenharmony_ci /* 162262306a36Sopenharmony_ci * SIx_{0,1} and SOx_{0,1} 162362306a36Sopenharmony_ci * Read accesses read SIx_{0,1} values 162462306a36Sopenharmony_ci * Write accesses write SOx_{0,1} values 162562306a36Sopenharmony_ci */ 162662306a36Sopenharmony_ci *xr_reg = PEB2466_XR0; 162762306a36Sopenharmony_ci *mask = (1 << (offset % 8)); 162862306a36Sopenharmony_ci return 0; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci if (offset < 24) { 163162306a36Sopenharmony_ci /* SBx_{0,1} */ 163262306a36Sopenharmony_ci *xr_reg = PEB2466_XR1; 163362306a36Sopenharmony_ci *mask = (1 << (offset - 16)); 163462306a36Sopenharmony_ci return 0; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci if (offset < 28) { 163762306a36Sopenharmony_ci /* SBx_2 */ 163862306a36Sopenharmony_ci *xr_reg = PEB2466_XR3; 163962306a36Sopenharmony_ci *mask = (1 << (offset - 24 + 4)); 164062306a36Sopenharmony_ci return 0; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci return -EINVAL; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic int peb2466_chip_gpio_offset_to_dir_regmask(unsigned int offset, 164662306a36Sopenharmony_ci unsigned int *xr_reg, 164762306a36Sopenharmony_ci unsigned int *mask) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci if (offset < 16) { 165062306a36Sopenharmony_ci /* Direction cannot be changed for these GPIOs */ 165162306a36Sopenharmony_ci return -EINVAL; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci if (offset < 24) { 165462306a36Sopenharmony_ci *xr_reg = PEB2466_XR2; 165562306a36Sopenharmony_ci *mask = (1 << (offset - 16)); 165662306a36Sopenharmony_ci return 0; 165762306a36Sopenharmony_ci } 165862306a36Sopenharmony_ci if (offset < 28) { 165962306a36Sopenharmony_ci *xr_reg = PEB2466_XR3; 166062306a36Sopenharmony_ci *mask = (1 << (offset - 24)); 166162306a36Sopenharmony_ci return 0; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci return -EINVAL; 166462306a36Sopenharmony_ci} 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_cistatic unsigned int *peb2466_chip_gpio_get_cache(struct peb2466 *peb2466, 166762306a36Sopenharmony_ci unsigned int xr_reg) 166862306a36Sopenharmony_ci{ 166962306a36Sopenharmony_ci unsigned int *cache; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci switch (xr_reg) { 167262306a36Sopenharmony_ci case PEB2466_XR0: 167362306a36Sopenharmony_ci cache = &peb2466->gpio.cache.xr0; 167462306a36Sopenharmony_ci break; 167562306a36Sopenharmony_ci case PEB2466_XR1: 167662306a36Sopenharmony_ci cache = &peb2466->gpio.cache.xr1; 167762306a36Sopenharmony_ci break; 167862306a36Sopenharmony_ci case PEB2466_XR2: 167962306a36Sopenharmony_ci cache = &peb2466->gpio.cache.xr2; 168062306a36Sopenharmony_ci break; 168162306a36Sopenharmony_ci case PEB2466_XR3: 168262306a36Sopenharmony_ci cache = &peb2466->gpio.cache.xr3; 168362306a36Sopenharmony_ci break; 168462306a36Sopenharmony_ci default: 168562306a36Sopenharmony_ci cache = NULL; 168662306a36Sopenharmony_ci break; 168762306a36Sopenharmony_ci } 168862306a36Sopenharmony_ci return cache; 168962306a36Sopenharmony_ci} 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_cistatic int peb2466_chip_gpio_update_bits(struct peb2466 *peb2466, unsigned int xr_reg, 169262306a36Sopenharmony_ci unsigned int mask, unsigned int val) 169362306a36Sopenharmony_ci{ 169462306a36Sopenharmony_ci unsigned int tmp; 169562306a36Sopenharmony_ci unsigned int *cache; 169662306a36Sopenharmony_ci int ret; 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci /* 169962306a36Sopenharmony_ci * Read and write accesses use different peb2466 internal signals (input 170062306a36Sopenharmony_ci * signals on reads and output signals on writes). regmap_update_bits 170162306a36Sopenharmony_ci * cannot be used to read/modify/write the value. 170262306a36Sopenharmony_ci * So, a specific cache value is used. 170362306a36Sopenharmony_ci */ 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_ci mutex_lock(&peb2466->gpio.lock); 170662306a36Sopenharmony_ci 170762306a36Sopenharmony_ci cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); 170862306a36Sopenharmony_ci if (!cache) { 170962306a36Sopenharmony_ci ret = -EINVAL; 171062306a36Sopenharmony_ci goto end; 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci tmp = *cache; 171462306a36Sopenharmony_ci tmp &= ~mask; 171562306a36Sopenharmony_ci tmp |= val; 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci ret = regmap_write(peb2466->regmap, xr_reg, tmp); 171862306a36Sopenharmony_ci if (ret) 171962306a36Sopenharmony_ci goto end; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci *cache = tmp; 172262306a36Sopenharmony_ci ret = 0; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ciend: 172562306a36Sopenharmony_ci mutex_unlock(&peb2466->gpio.lock); 172662306a36Sopenharmony_ci return ret; 172762306a36Sopenharmony_ci} 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_cistatic void peb2466_chip_gpio_set(struct gpio_chip *c, unsigned int offset, int val) 173062306a36Sopenharmony_ci{ 173162306a36Sopenharmony_ci struct peb2466 *peb2466 = gpiochip_get_data(c); 173262306a36Sopenharmony_ci unsigned int xr_reg; 173362306a36Sopenharmony_ci unsigned int mask; 173462306a36Sopenharmony_ci int ret; 173562306a36Sopenharmony_ci 173662306a36Sopenharmony_ci if (offset < 8) { 173762306a36Sopenharmony_ci /* 173862306a36Sopenharmony_ci * SIx_{0,1} signals cannot be set and writing the related 173962306a36Sopenharmony_ci * register will change the SOx_{0,1} signals 174062306a36Sopenharmony_ci */ 174162306a36Sopenharmony_ci dev_warn(&peb2466->spi->dev, "cannot set gpio %d (read-only)\n", 174262306a36Sopenharmony_ci offset); 174362306a36Sopenharmony_ci return; 174462306a36Sopenharmony_ci } 174562306a36Sopenharmony_ci 174662306a36Sopenharmony_ci ret = peb2466_chip_gpio_offset_to_data_regmask(offset, &xr_reg, &mask); 174762306a36Sopenharmony_ci if (ret) { 174862306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "cannot set gpio %d (%d)\n", 174962306a36Sopenharmony_ci offset, ret); 175062306a36Sopenharmony_ci return; 175162306a36Sopenharmony_ci } 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, val ? mask : 0); 175462306a36Sopenharmony_ci if (ret) { 175562306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "set gpio %d (0x%x, 0x%x) failed (%d)\n", 175662306a36Sopenharmony_ci offset, xr_reg, mask, ret); 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci} 175962306a36Sopenharmony_ci 176062306a36Sopenharmony_cistatic int peb2466_chip_gpio_get(struct gpio_chip *c, unsigned int offset) 176162306a36Sopenharmony_ci{ 176262306a36Sopenharmony_ci struct peb2466 *peb2466 = gpiochip_get_data(c); 176362306a36Sopenharmony_ci bool use_cache = false; 176462306a36Sopenharmony_ci unsigned int *cache; 176562306a36Sopenharmony_ci unsigned int xr_reg; 176662306a36Sopenharmony_ci unsigned int mask; 176762306a36Sopenharmony_ci unsigned int val; 176862306a36Sopenharmony_ci int ret; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci if (offset >= 8 && offset < 16) { 177162306a36Sopenharmony_ci /* 177262306a36Sopenharmony_ci * SOx_{0,1} signals cannot be read. Reading the related 177362306a36Sopenharmony_ci * register will read the SIx_{0,1} signals. 177462306a36Sopenharmony_ci * Use the cache to get value; 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci use_cache = true; 177762306a36Sopenharmony_ci } 177862306a36Sopenharmony_ci 177962306a36Sopenharmony_ci ret = peb2466_chip_gpio_offset_to_data_regmask(offset, &xr_reg, &mask); 178062306a36Sopenharmony_ci if (ret) { 178162306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "cannot get gpio %d (%d)\n", 178262306a36Sopenharmony_ci offset, ret); 178362306a36Sopenharmony_ci return -EINVAL; 178462306a36Sopenharmony_ci } 178562306a36Sopenharmony_ci 178662306a36Sopenharmony_ci if (use_cache) { 178762306a36Sopenharmony_ci cache = peb2466_chip_gpio_get_cache(peb2466, xr_reg); 178862306a36Sopenharmony_ci if (!cache) 178962306a36Sopenharmony_ci return -EINVAL; 179062306a36Sopenharmony_ci val = *cache; 179162306a36Sopenharmony_ci } else { 179262306a36Sopenharmony_ci ret = regmap_read(peb2466->regmap, xr_reg, &val); 179362306a36Sopenharmony_ci if (ret) { 179462306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "get gpio %d (0x%x, 0x%x) failed (%d)\n", 179562306a36Sopenharmony_ci offset, xr_reg, mask, ret); 179662306a36Sopenharmony_ci return ret; 179762306a36Sopenharmony_ci } 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci return !!(val & mask); 180162306a36Sopenharmony_ci} 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_cistatic int peb2466_chip_get_direction(struct gpio_chip *c, unsigned int offset) 180462306a36Sopenharmony_ci{ 180562306a36Sopenharmony_ci struct peb2466 *peb2466 = gpiochip_get_data(c); 180662306a36Sopenharmony_ci unsigned int xr_reg; 180762306a36Sopenharmony_ci unsigned int mask; 180862306a36Sopenharmony_ci unsigned int val; 180962306a36Sopenharmony_ci int ret; 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_ci if (offset < 8) { 181262306a36Sopenharmony_ci /* SIx_{0,1} */ 181362306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci if (offset < 16) { 181662306a36Sopenharmony_ci /* SOx_{0,1} */ 181762306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 181862306a36Sopenharmony_ci } 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_ci ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 182162306a36Sopenharmony_ci if (ret) { 182262306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "cannot get gpio %d direction (%d)\n", 182362306a36Sopenharmony_ci offset, ret); 182462306a36Sopenharmony_ci return ret; 182562306a36Sopenharmony_ci } 182662306a36Sopenharmony_ci 182762306a36Sopenharmony_ci ret = regmap_read(peb2466->regmap, xr_reg, &val); 182862306a36Sopenharmony_ci if (ret) { 182962306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "get dir gpio %d (0x%x, 0x%x) failed (%d)\n", 183062306a36Sopenharmony_ci offset, xr_reg, mask, ret); 183162306a36Sopenharmony_ci return ret; 183262306a36Sopenharmony_ci } 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci return val & mask ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN; 183562306a36Sopenharmony_ci} 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_cistatic int peb2466_chip_direction_input(struct gpio_chip *c, unsigned int offset) 183862306a36Sopenharmony_ci{ 183962306a36Sopenharmony_ci struct peb2466 *peb2466 = gpiochip_get_data(c); 184062306a36Sopenharmony_ci unsigned int xr_reg; 184162306a36Sopenharmony_ci unsigned int mask; 184262306a36Sopenharmony_ci int ret; 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci if (offset < 8) { 184562306a36Sopenharmony_ci /* SIx_{0,1} */ 184662306a36Sopenharmony_ci return 0; 184762306a36Sopenharmony_ci } 184862306a36Sopenharmony_ci if (offset < 16) { 184962306a36Sopenharmony_ci /* SOx_{0,1} */ 185062306a36Sopenharmony_ci return -EINVAL; 185162306a36Sopenharmony_ci } 185262306a36Sopenharmony_ci 185362306a36Sopenharmony_ci ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 185462306a36Sopenharmony_ci if (ret) { 185562306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n", 185662306a36Sopenharmony_ci offset, ret); 185762306a36Sopenharmony_ci return ret; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, 0); 186162306a36Sopenharmony_ci if (ret) { 186262306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n", 186362306a36Sopenharmony_ci offset, xr_reg, mask, ret); 186462306a36Sopenharmony_ci return ret; 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return 0; 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_cistatic int peb2466_chip_direction_output(struct gpio_chip *c, unsigned int offset, int val) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci struct peb2466 *peb2466 = gpiochip_get_data(c); 187362306a36Sopenharmony_ci unsigned int xr_reg; 187462306a36Sopenharmony_ci unsigned int mask; 187562306a36Sopenharmony_ci int ret; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci if (offset < 8) { 187862306a36Sopenharmony_ci /* SIx_{0,1} */ 187962306a36Sopenharmony_ci return -EINVAL; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_ci peb2466_chip_gpio_set(c, offset, val); 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci if (offset < 16) { 188562306a36Sopenharmony_ci /* SOx_{0,1} */ 188662306a36Sopenharmony_ci return 0; 188762306a36Sopenharmony_ci } 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci ret = peb2466_chip_gpio_offset_to_dir_regmask(offset, &xr_reg, &mask); 189062306a36Sopenharmony_ci if (ret) { 189162306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "cannot set gpio %d direction (%d)\n", 189262306a36Sopenharmony_ci offset, ret); 189362306a36Sopenharmony_ci return ret; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci 189662306a36Sopenharmony_ci ret = peb2466_chip_gpio_update_bits(peb2466, xr_reg, mask, mask); 189762306a36Sopenharmony_ci if (ret) { 189862306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Set dir in gpio %d (0x%x, 0x%x) failed (%d)\n", 189962306a36Sopenharmony_ci offset, xr_reg, mask, ret); 190062306a36Sopenharmony_ci return ret; 190162306a36Sopenharmony_ci } 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci return 0; 190462306a36Sopenharmony_ci} 190562306a36Sopenharmony_ci 190662306a36Sopenharmony_cistatic int peb2466_reset_gpio(struct peb2466 *peb2466) 190762306a36Sopenharmony_ci{ 190862306a36Sopenharmony_ci static const struct reg_sequence reg_reset[] = { 190962306a36Sopenharmony_ci /* Output pins at 0, input/output pins as input */ 191062306a36Sopenharmony_ci { .reg = PEB2466_XR0, .def = 0 }, 191162306a36Sopenharmony_ci { .reg = PEB2466_XR1, .def = 0 }, 191262306a36Sopenharmony_ci { .reg = PEB2466_XR2, .def = 0 }, 191362306a36Sopenharmony_ci { .reg = PEB2466_XR3, .def = 0 }, 191462306a36Sopenharmony_ci }; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci peb2466->gpio.cache.xr0 = 0; 191762306a36Sopenharmony_ci peb2466->gpio.cache.xr1 = 0; 191862306a36Sopenharmony_ci peb2466->gpio.cache.xr2 = 0; 191962306a36Sopenharmony_ci peb2466->gpio.cache.xr3 = 0; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci return regmap_multi_reg_write(peb2466->regmap, reg_reset, ARRAY_SIZE(reg_reset)); 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic int peb2466_gpio_init(struct peb2466 *peb2466) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci int ret; 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci mutex_init(&peb2466->gpio.lock); 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci ret = peb2466_reset_gpio(peb2466); 193162306a36Sopenharmony_ci if (ret) 193262306a36Sopenharmony_ci return ret; 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci peb2466->gpio.gpio_chip.owner = THIS_MODULE; 193562306a36Sopenharmony_ci peb2466->gpio.gpio_chip.label = dev_name(&peb2466->spi->dev); 193662306a36Sopenharmony_ci peb2466->gpio.gpio_chip.parent = &peb2466->spi->dev; 193762306a36Sopenharmony_ci peb2466->gpio.gpio_chip.base = -1; 193862306a36Sopenharmony_ci peb2466->gpio.gpio_chip.ngpio = 28; 193962306a36Sopenharmony_ci peb2466->gpio.gpio_chip.get_direction = peb2466_chip_get_direction; 194062306a36Sopenharmony_ci peb2466->gpio.gpio_chip.direction_input = peb2466_chip_direction_input; 194162306a36Sopenharmony_ci peb2466->gpio.gpio_chip.direction_output = peb2466_chip_direction_output; 194262306a36Sopenharmony_ci peb2466->gpio.gpio_chip.get = peb2466_chip_gpio_get; 194362306a36Sopenharmony_ci peb2466->gpio.gpio_chip.set = peb2466_chip_gpio_set; 194462306a36Sopenharmony_ci peb2466->gpio.gpio_chip.can_sleep = true; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci return devm_gpiochip_add_data(&peb2466->spi->dev, &peb2466->gpio.gpio_chip, 194762306a36Sopenharmony_ci peb2466); 194862306a36Sopenharmony_ci} 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_cistatic int peb2466_spi_probe(struct spi_device *spi) 195162306a36Sopenharmony_ci{ 195262306a36Sopenharmony_ci struct peb2466 *peb2466; 195362306a36Sopenharmony_ci unsigned long mclk_rate; 195462306a36Sopenharmony_ci int ret; 195562306a36Sopenharmony_ci u8 xr5; 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_ci spi->bits_per_word = 8; 195862306a36Sopenharmony_ci ret = spi_setup(spi); 195962306a36Sopenharmony_ci if (ret < 0) 196062306a36Sopenharmony_ci return ret; 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci peb2466 = devm_kzalloc(&spi->dev, sizeof(*peb2466), GFP_KERNEL); 196362306a36Sopenharmony_ci if (!peb2466) 196462306a36Sopenharmony_ci return -ENOMEM; 196562306a36Sopenharmony_ci 196662306a36Sopenharmony_ci peb2466->spi = spi; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci peb2466->regmap = devm_regmap_init(&peb2466->spi->dev, NULL, peb2466, 196962306a36Sopenharmony_ci &peb2466_regmap_config); 197062306a36Sopenharmony_ci if (IS_ERR(peb2466->regmap)) 197162306a36Sopenharmony_ci return PTR_ERR(peb2466->regmap); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci peb2466->reset_gpio = devm_gpiod_get_optional(&peb2466->spi->dev, 197462306a36Sopenharmony_ci "reset", GPIOD_OUT_LOW); 197562306a36Sopenharmony_ci if (IS_ERR(peb2466->reset_gpio)) 197662306a36Sopenharmony_ci return PTR_ERR(peb2466->reset_gpio); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci peb2466->mclk = devm_clk_get(&peb2466->spi->dev, "mclk"); 197962306a36Sopenharmony_ci if (IS_ERR(peb2466->mclk)) 198062306a36Sopenharmony_ci return PTR_ERR(peb2466->mclk); 198162306a36Sopenharmony_ci ret = clk_prepare_enable(peb2466->mclk); 198262306a36Sopenharmony_ci if (ret) 198362306a36Sopenharmony_ci return ret; 198462306a36Sopenharmony_ci 198562306a36Sopenharmony_ci if (peb2466->reset_gpio) { 198662306a36Sopenharmony_ci gpiod_set_value_cansleep(peb2466->reset_gpio, 1); 198762306a36Sopenharmony_ci udelay(4); 198862306a36Sopenharmony_ci gpiod_set_value_cansleep(peb2466->reset_gpio, 0); 198962306a36Sopenharmony_ci udelay(4); 199062306a36Sopenharmony_ci } 199162306a36Sopenharmony_ci 199262306a36Sopenharmony_ci spi_set_drvdata(spi, peb2466); 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci mclk_rate = clk_get_rate(peb2466->mclk); 199562306a36Sopenharmony_ci switch (mclk_rate) { 199662306a36Sopenharmony_ci case 1536000: 199762306a36Sopenharmony_ci xr5 = PEB2466_XR5_MCLK_1536; 199862306a36Sopenharmony_ci break; 199962306a36Sopenharmony_ci case 2048000: 200062306a36Sopenharmony_ci xr5 = PEB2466_XR5_MCLK_2048; 200162306a36Sopenharmony_ci break; 200262306a36Sopenharmony_ci case 4096000: 200362306a36Sopenharmony_ci xr5 = PEB2466_XR5_MCLK_4096; 200462306a36Sopenharmony_ci break; 200562306a36Sopenharmony_ci case 8192000: 200662306a36Sopenharmony_ci xr5 = PEB2466_XR5_MCLK_8192; 200762306a36Sopenharmony_ci break; 200862306a36Sopenharmony_ci default: 200962306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Unsupported clock rate %lu\n", 201062306a36Sopenharmony_ci mclk_rate); 201162306a36Sopenharmony_ci ret = -EINVAL; 201262306a36Sopenharmony_ci goto failed; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci ret = regmap_write(peb2466->regmap, PEB2466_XR5, xr5); 201562306a36Sopenharmony_ci if (ret) { 201662306a36Sopenharmony_ci dev_err(&peb2466->spi->dev, "Setting MCLK failed (%d)\n", ret); 201762306a36Sopenharmony_ci goto failed; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&spi->dev, &peb2466_component_driver, 202162306a36Sopenharmony_ci &peb2466_dai_driver, 1); 202262306a36Sopenharmony_ci if (ret) 202362306a36Sopenharmony_ci goto failed; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_GPIOLIB)) { 202662306a36Sopenharmony_ci ret = peb2466_gpio_init(peb2466); 202762306a36Sopenharmony_ci if (ret) 202862306a36Sopenharmony_ci goto failed; 202962306a36Sopenharmony_ci } 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci return 0; 203262306a36Sopenharmony_ci 203362306a36Sopenharmony_cifailed: 203462306a36Sopenharmony_ci clk_disable_unprepare(peb2466->mclk); 203562306a36Sopenharmony_ci return ret; 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_cistatic void peb2466_spi_remove(struct spi_device *spi) 203962306a36Sopenharmony_ci{ 204062306a36Sopenharmony_ci struct peb2466 *peb2466 = spi_get_drvdata(spi); 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci clk_disable_unprepare(peb2466->mclk); 204362306a36Sopenharmony_ci} 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_cistatic const struct of_device_id peb2466_of_match[] = { 204662306a36Sopenharmony_ci { .compatible = "infineon,peb2466", }, 204762306a36Sopenharmony_ci { } 204862306a36Sopenharmony_ci}; 204962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, peb2466_of_match); 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_cistatic const struct spi_device_id peb2466_id_table[] = { 205262306a36Sopenharmony_ci { "peb2466", 0 }, 205362306a36Sopenharmony_ci { } 205462306a36Sopenharmony_ci}; 205562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, peb2466_id_table); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_cistatic struct spi_driver peb2466_spi_driver = { 205862306a36Sopenharmony_ci .driver = { 205962306a36Sopenharmony_ci .name = "peb2466", 206062306a36Sopenharmony_ci .of_match_table = peb2466_of_match, 206162306a36Sopenharmony_ci }, 206262306a36Sopenharmony_ci .id_table = peb2466_id_table, 206362306a36Sopenharmony_ci .probe = peb2466_spi_probe, 206462306a36Sopenharmony_ci .remove = peb2466_spi_remove, 206562306a36Sopenharmony_ci}; 206662306a36Sopenharmony_ci 206762306a36Sopenharmony_cimodule_spi_driver(peb2466_spi_driver); 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ciMODULE_AUTHOR("Herve Codina <herve.codina@bootlin.com>"); 207062306a36Sopenharmony_ciMODULE_DESCRIPTION("PEB2466 ALSA SoC driver"); 207162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2072