162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// Copyright (c) 2018 BayLibre, SAS. 462306a36Sopenharmony_ci// Author: Jerome Brunet <jbrunet@baylibre.com> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/bitfield.h> 762306a36Sopenharmony_ci#include <linux/clk.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/of_platform.h> 1062306a36Sopenharmony_ci#include <linux/regmap.h> 1162306a36Sopenharmony_ci#include <sound/soc.h> 1262306a36Sopenharmony_ci#include <sound/soc-dai.h> 1362306a36Sopenharmony_ci#include <sound/pcm_params.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define SPDIFIN_CTRL0 0x00 1662306a36Sopenharmony_ci#define SPDIFIN_CTRL0_EN BIT(31) 1762306a36Sopenharmony_ci#define SPDIFIN_CTRL0_RST_OUT BIT(29) 1862306a36Sopenharmony_ci#define SPDIFIN_CTRL0_RST_IN BIT(28) 1962306a36Sopenharmony_ci#define SPDIFIN_CTRL0_WIDTH_SEL BIT(24) 2062306a36Sopenharmony_ci#define SPDIFIN_CTRL0_STATUS_CH_SHIFT 11 2162306a36Sopenharmony_ci#define SPDIFIN_CTRL0_STATUS_SEL GENMASK(10, 8) 2262306a36Sopenharmony_ci#define SPDIFIN_CTRL0_SRC_SEL GENMASK(5, 4) 2362306a36Sopenharmony_ci#define SPDIFIN_CTRL0_CHK_VALID BIT(3) 2462306a36Sopenharmony_ci#define SPDIFIN_CTRL1 0x04 2562306a36Sopenharmony_ci#define SPDIFIN_CTRL1_BASE_TIMER GENMASK(19, 0) 2662306a36Sopenharmony_ci#define SPDIFIN_CTRL1_IRQ_MASK GENMASK(27, 20) 2762306a36Sopenharmony_ci#define SPDIFIN_CTRL2 0x08 2862306a36Sopenharmony_ci#define SPDIFIN_THRES_PER_REG 3 2962306a36Sopenharmony_ci#define SPDIFIN_THRES_WIDTH 10 3062306a36Sopenharmony_ci#define SPDIFIN_CTRL3 0x0c 3162306a36Sopenharmony_ci#define SPDIFIN_CTRL4 0x10 3262306a36Sopenharmony_ci#define SPDIFIN_TIMER_PER_REG 4 3362306a36Sopenharmony_ci#define SPDIFIN_TIMER_WIDTH 8 3462306a36Sopenharmony_ci#define SPDIFIN_CTRL5 0x14 3562306a36Sopenharmony_ci#define SPDIFIN_CTRL6 0x18 3662306a36Sopenharmony_ci#define SPDIFIN_STAT0 0x1c 3762306a36Sopenharmony_ci#define SPDIFIN_STAT0_MODE GENMASK(30, 28) 3862306a36Sopenharmony_ci#define SPDIFIN_STAT0_MAXW GENMASK(17, 8) 3962306a36Sopenharmony_ci#define SPDIFIN_STAT0_IRQ GENMASK(7, 0) 4062306a36Sopenharmony_ci#define SPDIFIN_IRQ_MODE_CHANGED BIT(2) 4162306a36Sopenharmony_ci#define SPDIFIN_STAT1 0x20 4262306a36Sopenharmony_ci#define SPDIFIN_STAT2 0x24 4362306a36Sopenharmony_ci#define SPDIFIN_MUTE_VAL 0x28 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SPDIFIN_MODE_NUM 7 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistruct axg_spdifin_cfg { 4862306a36Sopenharmony_ci const unsigned int *mode_rates; 4962306a36Sopenharmony_ci unsigned int ref_rate; 5062306a36Sopenharmony_ci}; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistruct axg_spdifin { 5362306a36Sopenharmony_ci const struct axg_spdifin_cfg *conf; 5462306a36Sopenharmony_ci struct regmap *map; 5562306a36Sopenharmony_ci struct clk *refclk; 5662306a36Sopenharmony_ci struct clk *pclk; 5762306a36Sopenharmony_ci}; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci/* 6062306a36Sopenharmony_ci * TODO: 6162306a36Sopenharmony_ci * It would have been nice to check the actual rate against the sample rate 6262306a36Sopenharmony_ci * requested in hw_params(). Unfortunately, I was not able to make the mode 6362306a36Sopenharmony_ci * detection and IRQ work reliably: 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * 1. IRQs are generated on mode change only, so there is no notification 6662306a36Sopenharmony_ci * on transition between no signal and mode 0 (32kHz). 6762306a36Sopenharmony_ci * 2. Mode detection very often has glitches, and may detects the 6862306a36Sopenharmony_ci * lowest or the highest mode before zeroing in on the actual mode. 6962306a36Sopenharmony_ci * 7062306a36Sopenharmony_ci * This makes calling snd_pcm_stop() difficult to get right. Even notifying 7162306a36Sopenharmony_ci * the kcontrol would be very unreliable at this point. 7262306a36Sopenharmony_ci * Let's keep things simple until the magic spell that makes this work is 7362306a36Sopenharmony_ci * found. 7462306a36Sopenharmony_ci */ 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic unsigned int axg_spdifin_get_rate(struct axg_spdifin *priv) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci unsigned int stat, mode, rate = 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci regmap_read(priv->map, SPDIFIN_STAT0, &stat); 8162306a36Sopenharmony_ci mode = FIELD_GET(SPDIFIN_STAT0_MODE, stat); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * If max width is zero, we are not capturing anything. 8562306a36Sopenharmony_ci * Also Sometimes, when the capture is on but there is no data, 8662306a36Sopenharmony_ci * mode is SPDIFIN_MODE_NUM, but not always ... 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci if (FIELD_GET(SPDIFIN_STAT0_MAXW, stat) && 8962306a36Sopenharmony_ci mode < SPDIFIN_MODE_NUM) 9062306a36Sopenharmony_ci rate = priv->conf->mode_rates[mode]; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return rate; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int axg_spdifin_prepare(struct snd_pcm_substream *substream, 9662306a36Sopenharmony_ci struct snd_soc_dai *dai) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci /* Apply both reset */ 10162306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, 10262306a36Sopenharmony_ci SPDIFIN_CTRL0_RST_OUT | 10362306a36Sopenharmony_ci SPDIFIN_CTRL0_RST_IN, 10462306a36Sopenharmony_ci 0); 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* Clear out reset before in reset */ 10762306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, 10862306a36Sopenharmony_ci SPDIFIN_CTRL0_RST_OUT, SPDIFIN_CTRL0_RST_OUT); 10962306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, 11062306a36Sopenharmony_ci SPDIFIN_CTRL0_RST_IN, SPDIFIN_CTRL0_RST_IN); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci return 0; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void axg_spdifin_write_mode_param(struct regmap *map, int mode, 11662306a36Sopenharmony_ci unsigned int val, 11762306a36Sopenharmony_ci unsigned int num_per_reg, 11862306a36Sopenharmony_ci unsigned int base_reg, 11962306a36Sopenharmony_ci unsigned int width) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci uint64_t offset = mode; 12262306a36Sopenharmony_ci unsigned int reg, shift, rem; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci rem = do_div(offset, num_per_reg); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci reg = offset * regmap_get_reg_stride(map) + base_reg; 12762306a36Sopenharmony_ci shift = width * (num_per_reg - 1 - rem); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci regmap_update_bits(map, reg, GENMASK(width - 1, 0) << shift, 13062306a36Sopenharmony_ci val << shift); 13162306a36Sopenharmony_ci} 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic void axg_spdifin_write_timer(struct regmap *map, int mode, 13462306a36Sopenharmony_ci unsigned int val) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_TIMER_PER_REG, 13762306a36Sopenharmony_ci SPDIFIN_CTRL4, SPDIFIN_TIMER_WIDTH); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void axg_spdifin_write_threshold(struct regmap *map, int mode, 14162306a36Sopenharmony_ci unsigned int val) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci axg_spdifin_write_mode_param(map, mode, val, SPDIFIN_THRES_PER_REG, 14462306a36Sopenharmony_ci SPDIFIN_CTRL2, SPDIFIN_THRES_WIDTH); 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic unsigned int axg_spdifin_mode_timer(struct axg_spdifin *priv, 14862306a36Sopenharmony_ci int mode, 14962306a36Sopenharmony_ci unsigned int rate) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci /* 15262306a36Sopenharmony_ci * Number of period of the reference clock during a period of the 15362306a36Sopenharmony_ci * input signal reference clock 15462306a36Sopenharmony_ci */ 15562306a36Sopenharmony_ci return rate / (128 * priv->conf->mode_rates[mode]); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic int axg_spdifin_sample_mode_config(struct snd_soc_dai *dai, 15962306a36Sopenharmony_ci struct axg_spdifin *priv) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci unsigned int rate, t_next; 16262306a36Sopenharmony_ci int ret, i = SPDIFIN_MODE_NUM - 1; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Set spdif input reference clock */ 16562306a36Sopenharmony_ci ret = clk_set_rate(priv->refclk, priv->conf->ref_rate); 16662306a36Sopenharmony_ci if (ret) { 16762306a36Sopenharmony_ci dev_err(dai->dev, "reference clock rate set failed\n"); 16862306a36Sopenharmony_ci return ret; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci /* 17262306a36Sopenharmony_ci * The rate actually set might be slightly different, get 17362306a36Sopenharmony_ci * the actual rate for the following mode calculation 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci rate = clk_get_rate(priv->refclk); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci /* HW will update mode every 1ms */ 17862306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL1, 17962306a36Sopenharmony_ci SPDIFIN_CTRL1_BASE_TIMER, 18062306a36Sopenharmony_ci FIELD_PREP(SPDIFIN_CTRL1_BASE_TIMER, rate / 1000)); 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* Threshold based on the minimum width between two edges */ 18362306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, 18462306a36Sopenharmony_ci SPDIFIN_CTRL0_WIDTH_SEL, SPDIFIN_CTRL0_WIDTH_SEL); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci /* Calculate the last timer which has no threshold */ 18762306a36Sopenharmony_ci t_next = axg_spdifin_mode_timer(priv, i, rate); 18862306a36Sopenharmony_ci axg_spdifin_write_timer(priv->map, i, t_next); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci do { 19162306a36Sopenharmony_ci unsigned int t; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci i -= 1; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* Calculate the timer */ 19662306a36Sopenharmony_ci t = axg_spdifin_mode_timer(priv, i, rate); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci /* Set the timer value */ 19962306a36Sopenharmony_ci axg_spdifin_write_timer(priv->map, i, t); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci /* Set the threshold value */ 20262306a36Sopenharmony_ci axg_spdifin_write_threshold(priv->map, i, t + t_next); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Save the current timer for the next threshold calculation */ 20562306a36Sopenharmony_ci t_next = t; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci } while (i > 0); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int axg_spdifin_dai_probe(struct snd_soc_dai *dai) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); 21562306a36Sopenharmony_ci int ret; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = clk_prepare_enable(priv->pclk); 21862306a36Sopenharmony_ci if (ret) { 21962306a36Sopenharmony_ci dev_err(dai->dev, "failed to enable pclk\n"); 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci ret = axg_spdifin_sample_mode_config(dai, priv); 22462306a36Sopenharmony_ci if (ret) { 22562306a36Sopenharmony_ci dev_err(dai->dev, "mode configuration failed\n"); 22662306a36Sopenharmony_ci goto pclk_err; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci ret = clk_prepare_enable(priv->refclk); 23062306a36Sopenharmony_ci if (ret) { 23162306a36Sopenharmony_ci dev_err(dai->dev, 23262306a36Sopenharmony_ci "failed to enable spdifin reference clock\n"); 23362306a36Sopenharmony_ci goto pclk_err; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 23762306a36Sopenharmony_ci SPDIFIN_CTRL0_EN); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cipclk_err: 24262306a36Sopenharmony_ci clk_disable_unprepare(priv->pclk); 24362306a36Sopenharmony_ci return ret; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic int axg_spdifin_dai_remove(struct snd_soc_dai *dai) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci struct axg_spdifin *priv = snd_soc_dai_get_drvdata(dai); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, SPDIFIN_CTRL0_EN, 0); 25162306a36Sopenharmony_ci clk_disable_unprepare(priv->refclk); 25262306a36Sopenharmony_ci clk_disable_unprepare(priv->pclk); 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci} 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_cistatic const struct snd_soc_dai_ops axg_spdifin_ops = { 25762306a36Sopenharmony_ci .probe = axg_spdifin_dai_probe, 25862306a36Sopenharmony_ci .remove = axg_spdifin_dai_remove, 25962306a36Sopenharmony_ci .prepare = axg_spdifin_prepare, 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic int axg_spdifin_iec958_info(struct snd_kcontrol *kcontrol, 26362306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 26662306a36Sopenharmony_ci uinfo->count = 1; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic int axg_spdifin_get_status_mask(struct snd_kcontrol *kcontrol, 27262306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci int i; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci for (i = 0; i < 24; i++) 27762306a36Sopenharmony_ci ucontrol->value.iec958.status[i] = 0xff; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci return 0; 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic int axg_spdifin_get_status(struct snd_kcontrol *kcontrol, 28362306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); 28662306a36Sopenharmony_ci struct axg_spdifin *priv = snd_soc_component_get_drvdata(c); 28762306a36Sopenharmony_ci int i, j; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 29062306a36Sopenharmony_ci unsigned int val; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci regmap_update_bits(priv->map, SPDIFIN_CTRL0, 29362306a36Sopenharmony_ci SPDIFIN_CTRL0_STATUS_SEL, 29462306a36Sopenharmony_ci FIELD_PREP(SPDIFIN_CTRL0_STATUS_SEL, i)); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci regmap_read(priv->map, SPDIFIN_STAT1, &val); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci for (j = 0; j < 4; j++) { 29962306a36Sopenharmony_ci unsigned int offset = i * 4 + j; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci ucontrol->value.iec958.status[offset] = 30262306a36Sopenharmony_ci (val >> (j * 8)) & 0xff; 30362306a36Sopenharmony_ci } 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#define AXG_SPDIFIN_IEC958_MASK \ 31062306a36Sopenharmony_ci { \ 31162306a36Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, \ 31262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ 31362306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), \ 31462306a36Sopenharmony_ci .info = axg_spdifin_iec958_info, \ 31562306a36Sopenharmony_ci .get = axg_spdifin_get_status_mask, \ 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#define AXG_SPDIFIN_IEC958_STATUS \ 31962306a36Sopenharmony_ci { \ 32062306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READ | \ 32162306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE), \ 32262306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ 32362306a36Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE), \ 32462306a36Sopenharmony_ci .info = axg_spdifin_iec958_info, \ 32562306a36Sopenharmony_ci .get = axg_spdifin_get_status, \ 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic const char * const spdifin_chsts_src_texts[] = { 32962306a36Sopenharmony_ci "A", "B", 33062306a36Sopenharmony_ci}; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(axg_spdifin_chsts_src_enum, SPDIFIN_CTRL0, 33362306a36Sopenharmony_ci SPDIFIN_CTRL0_STATUS_CH_SHIFT, 33462306a36Sopenharmony_ci spdifin_chsts_src_texts); 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int axg_spdifin_rate_lock_info(struct snd_kcontrol *kcontrol, 33762306a36Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 34062306a36Sopenharmony_ci uinfo->count = 1; 34162306a36Sopenharmony_ci uinfo->value.integer.min = 0; 34262306a36Sopenharmony_ci uinfo->value.integer.max = 192000; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci return 0; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int axg_spdifin_rate_lock_get(struct snd_kcontrol *kcontrol, 34862306a36Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci struct snd_soc_component *c = snd_kcontrol_chip(kcontrol); 35162306a36Sopenharmony_ci struct axg_spdifin *priv = snd_soc_component_get_drvdata(c); 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ucontrol->value.integer.value[0] = axg_spdifin_get_rate(priv); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci#define AXG_SPDIFIN_LOCK_RATE(xname) \ 35962306a36Sopenharmony_ci { \ 36062306a36Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ 36162306a36Sopenharmony_ci .access = (SNDRV_CTL_ELEM_ACCESS_READ | \ 36262306a36Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE), \ 36362306a36Sopenharmony_ci .get = axg_spdifin_rate_lock_get, \ 36462306a36Sopenharmony_ci .info = axg_spdifin_rate_lock_info, \ 36562306a36Sopenharmony_ci .name = xname, \ 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic const struct snd_kcontrol_new axg_spdifin_controls[] = { 36962306a36Sopenharmony_ci AXG_SPDIFIN_LOCK_RATE("Capture Rate Lock"), 37062306a36Sopenharmony_ci SOC_DOUBLE("Capture Switch", SPDIFIN_CTRL0, 7, 6, 1, 1), 37162306a36Sopenharmony_ci SOC_ENUM(SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Src", 37262306a36Sopenharmony_ci axg_spdifin_chsts_src_enum), 37362306a36Sopenharmony_ci AXG_SPDIFIN_IEC958_MASK, 37462306a36Sopenharmony_ci AXG_SPDIFIN_IEC958_STATUS, 37562306a36Sopenharmony_ci}; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_cistatic const struct snd_soc_component_driver axg_spdifin_component_drv = { 37862306a36Sopenharmony_ci .controls = axg_spdifin_controls, 37962306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(axg_spdifin_controls), 38062306a36Sopenharmony_ci .legacy_dai_naming = 1, 38162306a36Sopenharmony_ci}; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic const struct regmap_config axg_spdifin_regmap_cfg = { 38462306a36Sopenharmony_ci .reg_bits = 32, 38562306a36Sopenharmony_ci .val_bits = 32, 38662306a36Sopenharmony_ci .reg_stride = 4, 38762306a36Sopenharmony_ci .max_register = SPDIFIN_MUTE_VAL, 38862306a36Sopenharmony_ci}; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic const unsigned int axg_spdifin_mode_rates[SPDIFIN_MODE_NUM] = { 39162306a36Sopenharmony_ci 32000, 44100, 48000, 88200, 96000, 176400, 192000, 39262306a36Sopenharmony_ci}; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic const struct axg_spdifin_cfg axg_cfg = { 39562306a36Sopenharmony_ci .mode_rates = axg_spdifin_mode_rates, 39662306a36Sopenharmony_ci .ref_rate = 333333333, 39762306a36Sopenharmony_ci}; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic const struct of_device_id axg_spdifin_of_match[] = { 40062306a36Sopenharmony_ci { 40162306a36Sopenharmony_ci .compatible = "amlogic,axg-spdifin", 40262306a36Sopenharmony_ci .data = &axg_cfg, 40362306a36Sopenharmony_ci }, {} 40462306a36Sopenharmony_ci}; 40562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, axg_spdifin_of_match); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic struct snd_soc_dai_driver * 40862306a36Sopenharmony_ciaxg_spdifin_get_dai_drv(struct device *dev, struct axg_spdifin *priv) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct snd_soc_dai_driver *drv; 41162306a36Sopenharmony_ci int i; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); 41462306a36Sopenharmony_ci if (!drv) 41562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci drv->name = "SPDIF Input"; 41862306a36Sopenharmony_ci drv->ops = &axg_spdifin_ops; 41962306a36Sopenharmony_ci drv->capture.stream_name = "Capture"; 42062306a36Sopenharmony_ci drv->capture.channels_min = 1; 42162306a36Sopenharmony_ci drv->capture.channels_max = 2; 42262306a36Sopenharmony_ci drv->capture.formats = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci for (i = 0; i < SPDIFIN_MODE_NUM; i++) { 42562306a36Sopenharmony_ci unsigned int rb = 42662306a36Sopenharmony_ci snd_pcm_rate_to_rate_bit(priv->conf->mode_rates[i]); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci if (rb == SNDRV_PCM_RATE_KNOT) 42962306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci drv->capture.rates |= rb; 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci return drv; 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic int axg_spdifin_probe(struct platform_device *pdev) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 44062306a36Sopenharmony_ci struct axg_spdifin *priv; 44162306a36Sopenharmony_ci struct snd_soc_dai_driver *dai_drv; 44262306a36Sopenharmony_ci void __iomem *regs; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 44562306a36Sopenharmony_ci if (!priv) 44662306a36Sopenharmony_ci return -ENOMEM; 44762306a36Sopenharmony_ci platform_set_drvdata(pdev, priv); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci priv->conf = of_device_get_match_data(dev); 45062306a36Sopenharmony_ci if (!priv->conf) { 45162306a36Sopenharmony_ci dev_err(dev, "failed to match device\n"); 45262306a36Sopenharmony_ci return -ENODEV; 45362306a36Sopenharmony_ci } 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci regs = devm_platform_ioremap_resource(pdev, 0); 45662306a36Sopenharmony_ci if (IS_ERR(regs)) 45762306a36Sopenharmony_ci return PTR_ERR(regs); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci priv->map = devm_regmap_init_mmio(dev, regs, &axg_spdifin_regmap_cfg); 46062306a36Sopenharmony_ci if (IS_ERR(priv->map)) { 46162306a36Sopenharmony_ci dev_err(dev, "failed to init regmap: %ld\n", 46262306a36Sopenharmony_ci PTR_ERR(priv->map)); 46362306a36Sopenharmony_ci return PTR_ERR(priv->map); 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci priv->pclk = devm_clk_get(dev, "pclk"); 46762306a36Sopenharmony_ci if (IS_ERR(priv->pclk)) 46862306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->pclk), "failed to get pclk\n"); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci priv->refclk = devm_clk_get(dev, "refclk"); 47162306a36Sopenharmony_ci if (IS_ERR(priv->refclk)) 47262306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->refclk), "failed to get mclk\n"); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci dai_drv = axg_spdifin_get_dai_drv(dev, priv); 47562306a36Sopenharmony_ci if (IS_ERR(dai_drv)) { 47662306a36Sopenharmony_ci dev_err(dev, "failed to get dai driver: %ld\n", 47762306a36Sopenharmony_ci PTR_ERR(dai_drv)); 47862306a36Sopenharmony_ci return PTR_ERR(dai_drv); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci return devm_snd_soc_register_component(dev, &axg_spdifin_component_drv, 48262306a36Sopenharmony_ci dai_drv, 1); 48362306a36Sopenharmony_ci} 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_cistatic struct platform_driver axg_spdifin_pdrv = { 48662306a36Sopenharmony_ci .probe = axg_spdifin_probe, 48762306a36Sopenharmony_ci .driver = { 48862306a36Sopenharmony_ci .name = "axg-spdifin", 48962306a36Sopenharmony_ci .of_match_table = axg_spdifin_of_match, 49062306a36Sopenharmony_ci }, 49162306a36Sopenharmony_ci}; 49262306a36Sopenharmony_cimodule_platform_driver(axg_spdifin_pdrv); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciMODULE_DESCRIPTION("Amlogic AXG SPDIF Input driver"); 49562306a36Sopenharmony_ciMODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>"); 49662306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 497