162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// ak4613.c -- Asahi Kasei ALSA Soc Audio driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright (C) 2015 Renesas Electronics Corporation 662306a36Sopenharmony_ci// Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci// Based on ak4642.c by Kuninori Morimoto 962306a36Sopenharmony_ci// Based on wm8731.c by Richard Purdie 1062306a36Sopenharmony_ci// Based on ak4535.c by Richard Purdie 1162306a36Sopenharmony_ci// Based on wm8753.c by Liam Girdwood 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci/* 1462306a36Sopenharmony_ci * +-------+ 1562306a36Sopenharmony_ci * |AK4613 | 1662306a36Sopenharmony_ci * SDTO1 <-| | 1762306a36Sopenharmony_ci * | | 1862306a36Sopenharmony_ci * SDTI1 ->| | 1962306a36Sopenharmony_ci * SDTI2 ->| | 2062306a36Sopenharmony_ci * SDTI3 ->| | 2162306a36Sopenharmony_ci * +-------+ 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * +---+ 2462306a36Sopenharmony_ci * clk | |___________________________________________... 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * [TDM512] 2762306a36Sopenharmony_ci * SDTO1 [L1][R1][L2][R2] 2862306a36Sopenharmony_ci * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4][L5][R5][L6][R6] 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * [TDM256] 3162306a36Sopenharmony_ci * SDTO1 [L1][R1][L2][R2] 3262306a36Sopenharmony_ci * SDTI1 [L1][R1][L2][R2][L3][R3][L4][R4] 3362306a36Sopenharmony_ci * SDTI2 [L5][R5][L6][R6] 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * [TDM128] 3662306a36Sopenharmony_ci * SDTO1 [L1][R1][L2][R2] 3762306a36Sopenharmony_ci * SDTI1 [L1][R1][L2][R2] 3862306a36Sopenharmony_ci * SDTI2 [L3][R3][L4][R4] 3962306a36Sopenharmony_ci * SDTI3 [L5][R5][L6][R6] 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * [STEREO] 4262306a36Sopenharmony_ci * Playback 2ch : SDTI1 4362306a36Sopenharmony_ci * Capture 2ch : SDTO1 4462306a36Sopenharmony_ci * 4562306a36Sopenharmony_ci * [TDM512] 4662306a36Sopenharmony_ci * Playback 12ch : SDTI1 4762306a36Sopenharmony_ci * Capture 4ch : SDTO1 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * [TDM256] 5062306a36Sopenharmony_ci * Playback 12ch : SDTI1 + SDTI2 5162306a36Sopenharmony_ci * Playback 8ch : SDTI1 5262306a36Sopenharmony_ci * Capture 4ch : SDTO1 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * [TDM128] 5562306a36Sopenharmony_ci * Playback 12ch : SDTI1 + SDTI2 + SDTI3 5662306a36Sopenharmony_ci * Playback 8ch : SDTI1 + SDTI2 5762306a36Sopenharmony_ci * Playback 4ch : SDTI1 5862306a36Sopenharmony_ci * Capture 4ch : SDTO1 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * 6162306a36Sopenharmony_ci * !!! NOTE !!! 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Renesas is the only user of ak4613 on upstream so far, 6462306a36Sopenharmony_ci * but the chip connection is like below. 6562306a36Sopenharmony_ci * Thus, Renesas can't test all connection case. 6662306a36Sopenharmony_ci * Tested TDM is very limited. 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * +-----+ +-----------+ 6962306a36Sopenharmony_ci * | SoC | | AK4613 | 7062306a36Sopenharmony_ci * | |<-----|SDTO1 IN1|<-- Mic 7162306a36Sopenharmony_ci * | | | IN2| 7262306a36Sopenharmony_ci * | | | | 7362306a36Sopenharmony_ci * | |----->|SDTI1 OUT1|--> Headphone 7462306a36Sopenharmony_ci * +-----+ |SDTI2 OUT2| 7562306a36Sopenharmony_ci * |SDTI3 OUT3| 7662306a36Sopenharmony_ci * | OUT4| 7762306a36Sopenharmony_ci * | OUT5| 7862306a36Sopenharmony_ci * | OUT6| 7962306a36Sopenharmony_ci * +-----------+ 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * Renesas SoC can handle [2, 6,8] channels. 8262306a36Sopenharmony_ci * Ak4613 can handle [2,4, 8,12] channels. 8362306a36Sopenharmony_ci * 8462306a36Sopenharmony_ci * Because of above HW connection and available channels number, 8562306a36Sopenharmony_ci * Renesas could test are ... 8662306a36Sopenharmony_ci * 8762306a36Sopenharmony_ci * [STEREO] Playback 2ch : SDTI1 8862306a36Sopenharmony_ci * Capture 2ch : SDTO1 8962306a36Sopenharmony_ci * [TDM256] Playback 8ch : SDTI1 (*) 9062306a36Sopenharmony_ci * 9162306a36Sopenharmony_ci * (*) it used 8ch data between SoC <-> AK4613 on TDM256 mode, 9262306a36Sopenharmony_ci * but could confirm is only first 2ch because only 1 9362306a36Sopenharmony_ci * Headphone is connected. 9462306a36Sopenharmony_ci * 9562306a36Sopenharmony_ci * see 9662306a36Sopenharmony_ci * AK4613_ENABLE_TDM_TEST 9762306a36Sopenharmony_ci */ 9862306a36Sopenharmony_ci#include <linux/clk.h> 9962306a36Sopenharmony_ci#include <linux/delay.h> 10062306a36Sopenharmony_ci#include <linux/i2c.h> 10162306a36Sopenharmony_ci#include <linux/slab.h> 10262306a36Sopenharmony_ci#include <linux/of_device.h> 10362306a36Sopenharmony_ci#include <linux/of_graph.h> 10462306a36Sopenharmony_ci#include <linux/module.h> 10562306a36Sopenharmony_ci#include <linux/regmap.h> 10662306a36Sopenharmony_ci#include <sound/soc.h> 10762306a36Sopenharmony_ci#include <sound/pcm_params.h> 10862306a36Sopenharmony_ci#include <sound/tlv.h> 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci#define PW_MGMT1 0x00 /* Power Management 1 */ 11162306a36Sopenharmony_ci#define PW_MGMT2 0x01 /* Power Management 2 */ 11262306a36Sopenharmony_ci#define PW_MGMT3 0x02 /* Power Management 3 */ 11362306a36Sopenharmony_ci#define CTRL1 0x03 /* Control 1 */ 11462306a36Sopenharmony_ci#define CTRL2 0x04 /* Control 2 */ 11562306a36Sopenharmony_ci#define DEMP1 0x05 /* De-emphasis1 */ 11662306a36Sopenharmony_ci#define DEMP2 0x06 /* De-emphasis2 */ 11762306a36Sopenharmony_ci#define OFD 0x07 /* Overflow Detect */ 11862306a36Sopenharmony_ci#define ZRD 0x08 /* Zero Detect */ 11962306a36Sopenharmony_ci#define ICTRL 0x09 /* Input Control */ 12062306a36Sopenharmony_ci#define OCTRL 0x0a /* Output Control */ 12162306a36Sopenharmony_ci#define LOUT1 0x0b /* LOUT1 Volume Control */ 12262306a36Sopenharmony_ci#define ROUT1 0x0c /* ROUT1 Volume Control */ 12362306a36Sopenharmony_ci#define LOUT2 0x0d /* LOUT2 Volume Control */ 12462306a36Sopenharmony_ci#define ROUT2 0x0e /* ROUT2 Volume Control */ 12562306a36Sopenharmony_ci#define LOUT3 0x0f /* LOUT3 Volume Control */ 12662306a36Sopenharmony_ci#define ROUT3 0x10 /* ROUT3 Volume Control */ 12762306a36Sopenharmony_ci#define LOUT4 0x11 /* LOUT4 Volume Control */ 12862306a36Sopenharmony_ci#define ROUT4 0x12 /* ROUT4 Volume Control */ 12962306a36Sopenharmony_ci#define LOUT5 0x13 /* LOUT5 Volume Control */ 13062306a36Sopenharmony_ci#define ROUT5 0x14 /* ROUT5 Volume Control */ 13162306a36Sopenharmony_ci#define LOUT6 0x15 /* LOUT6 Volume Control */ 13262306a36Sopenharmony_ci#define ROUT6 0x16 /* ROUT6 Volume Control */ 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* PW_MGMT1 */ 13562306a36Sopenharmony_ci#define RSTN BIT(0) 13662306a36Sopenharmony_ci#define PMDAC BIT(1) 13762306a36Sopenharmony_ci#define PMADC BIT(2) 13862306a36Sopenharmony_ci#define PMVR BIT(3) 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* PW_MGMT2 */ 14162306a36Sopenharmony_ci#define PMAD_ALL 0x7 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* PW_MGMT3 */ 14462306a36Sopenharmony_ci#define PMDA_ALL 0x3f 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* CTRL1 */ 14762306a36Sopenharmony_ci#define DIF0 BIT(3) 14862306a36Sopenharmony_ci#define DIF1 BIT(4) 14962306a36Sopenharmony_ci#define DIF2 BIT(5) 15062306a36Sopenharmony_ci#define TDM0 BIT(6) 15162306a36Sopenharmony_ci#define TDM1 BIT(7) 15262306a36Sopenharmony_ci#define NO_FMT (0xff) 15362306a36Sopenharmony_ci#define FMT_MASK (0xf8) 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/* CTRL2 */ 15662306a36Sopenharmony_ci#define DFS_MASK (3 << 2) 15762306a36Sopenharmony_ci#define DFS_NORMAL_SPEED (0 << 2) 15862306a36Sopenharmony_ci#define DFS_DOUBLE_SPEED (1 << 2) 15962306a36Sopenharmony_ci#define DFS_QUAD_SPEED (2 << 2) 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci/* ICTRL */ 16262306a36Sopenharmony_ci#define ICTRL_MASK (0x3) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* OCTRL */ 16562306a36Sopenharmony_ci#define OCTRL_MASK (0x3F) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* 16862306a36Sopenharmony_ci * configs 16962306a36Sopenharmony_ci * 17062306a36Sopenharmony_ci * 0x000000BA 17162306a36Sopenharmony_ci * 17262306a36Sopenharmony_ci * B : AK4613_CONFIG_SDTI_x 17362306a36Sopenharmony_ci * A : AK4613_CONFIG_MODE_x 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci#define AK4613_CONFIG_SET(priv, x) priv->configs |= AK4613_CONFIG_##x 17662306a36Sopenharmony_ci#define AK4613_CONFIG_GET(priv, x) (priv->configs & AK4613_CONFIG_##x##_MASK) 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * AK4613_CONFIG_SDTI_x 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * It indicates how many SDTIx is connected. 18262306a36Sopenharmony_ci */ 18362306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_MASK (0xF << 4) 18462306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI(x) (((x) & 0xF) << 4) 18562306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_set(priv, x) AK4613_CONFIG_SET(priv, SDTI(x)) 18662306a36Sopenharmony_ci#define AK4613_CONFIG_SDTI_get(priv) ((AK4613_CONFIG_GET(priv, SDTI) >> 4) & 0xF) 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/* 18962306a36Sopenharmony_ci * AK4613_CONFIG_MODE_x 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * Same as Ctrl1 :: TDM1/TDM0 19262306a36Sopenharmony_ci * No shift is requested 19362306a36Sopenharmony_ci * see 19462306a36Sopenharmony_ci * AK4613_CTRL1_TO_MODE() 19562306a36Sopenharmony_ci * Table 11/12/13/14 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_MASK (0xF) 19862306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_STEREO (0x0) 19962306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM512 (0x1) 20062306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM256 (0x2) 20162306a36Sopenharmony_ci#define AK4613_CONFIG_MODE_TDM128 (0x3) 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci/* 20462306a36Sopenharmony_ci * !!!! FIXME !!!! 20562306a36Sopenharmony_ci * 20662306a36Sopenharmony_ci * Because of testable HW limitation, TDM256 8ch TDM was only tested. 20762306a36Sopenharmony_ci * This driver uses AK4613_ENABLE_TDM_TEST instead of new DT property so far. 20862306a36Sopenharmony_ci * Don't hesitate to update driver, you don't need to care compatible 20962306a36Sopenharmony_ci * with Renesas. 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * #define AK4613_ENABLE_TDM_TEST 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistruct ak4613_interface { 21562306a36Sopenharmony_ci unsigned int width; 21662306a36Sopenharmony_ci unsigned int fmt; 21762306a36Sopenharmony_ci u8 dif; 21862306a36Sopenharmony_ci}; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistruct ak4613_priv { 22162306a36Sopenharmony_ci struct mutex lock; 22262306a36Sopenharmony_ci struct snd_pcm_hw_constraint_list constraint_rates; 22362306a36Sopenharmony_ci struct snd_pcm_hw_constraint_list constraint_channels; 22462306a36Sopenharmony_ci struct work_struct dummy_write_work; 22562306a36Sopenharmony_ci struct snd_soc_component *component; 22662306a36Sopenharmony_ci unsigned int rate; 22762306a36Sopenharmony_ci unsigned int sysclk; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci unsigned int fmt; 23062306a36Sopenharmony_ci unsigned int configs; 23162306a36Sopenharmony_ci int cnt; 23262306a36Sopenharmony_ci u8 ctrl1; 23362306a36Sopenharmony_ci u8 oc; 23462306a36Sopenharmony_ci u8 ic; 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * Playback Volume 23962306a36Sopenharmony_ci * 24062306a36Sopenharmony_ci * max : 0x00 : 0 dB 24162306a36Sopenharmony_ci * ( 0.5 dB step ) 24262306a36Sopenharmony_ci * min : 0xFE : -127.0 dB 24362306a36Sopenharmony_ci * mute: 0xFF 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(out_tlv, -12750, 50, 1); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic const struct snd_kcontrol_new ak4613_snd_controls[] = { 24862306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume1", LOUT1, ROUT1, 24962306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 25062306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume2", LOUT2, ROUT2, 25162306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 25262306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume3", LOUT3, ROUT3, 25362306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 25462306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume4", LOUT4, ROUT4, 25562306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 25662306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume5", LOUT5, ROUT5, 25762306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 25862306a36Sopenharmony_ci SOC_DOUBLE_R_TLV("Digital Playback Volume6", LOUT6, ROUT6, 25962306a36Sopenharmony_ci 0, 0xFF, 1, out_tlv), 26062306a36Sopenharmony_ci}; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_cistatic const struct reg_default ak4613_reg[] = { 26362306a36Sopenharmony_ci { 0x0, 0x0f }, { 0x1, 0x07 }, { 0x2, 0x3f }, { 0x3, 0x20 }, 26462306a36Sopenharmony_ci { 0x4, 0x20 }, { 0x5, 0x55 }, { 0x6, 0x05 }, { 0x7, 0x07 }, 26562306a36Sopenharmony_ci { 0x8, 0x0f }, { 0x9, 0x07 }, { 0xa, 0x3f }, { 0xb, 0x00 }, 26662306a36Sopenharmony_ci { 0xc, 0x00 }, { 0xd, 0x00 }, { 0xe, 0x00 }, { 0xf, 0x00 }, 26762306a36Sopenharmony_ci { 0x10, 0x00 }, { 0x11, 0x00 }, { 0x12, 0x00 }, { 0x13, 0x00 }, 26862306a36Sopenharmony_ci { 0x14, 0x00 }, { 0x15, 0x00 }, { 0x16, 0x00 }, 26962306a36Sopenharmony_ci}; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci/* 27262306a36Sopenharmony_ci * CTRL1 register 27362306a36Sopenharmony_ci * see 27462306a36Sopenharmony_ci * Table 11/12/13/14 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci#define AUDIO_IFACE(_dif, _width, _fmt) \ 27762306a36Sopenharmony_ci { \ 27862306a36Sopenharmony_ci .dif = _dif, \ 27962306a36Sopenharmony_ci .width = _width, \ 28062306a36Sopenharmony_ci .fmt = SND_SOC_DAIFMT_##_fmt,\ 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_cistatic const struct ak4613_interface ak4613_iface[] = { 28362306a36Sopenharmony_ci /* It doesn't support asymmetric format */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci AUDIO_IFACE(0x03, 24, LEFT_J), 28662306a36Sopenharmony_ci AUDIO_IFACE(0x04, 24, I2S), 28762306a36Sopenharmony_ci}; 28862306a36Sopenharmony_ci#define AK4613_CTRL1_TO_MODE(priv) ((priv)->ctrl1 >> 6) /* AK4613_CONFIG_MODE_x */ 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic const struct regmap_config ak4613_regmap_cfg = { 29162306a36Sopenharmony_ci .reg_bits = 8, 29262306a36Sopenharmony_ci .val_bits = 8, 29362306a36Sopenharmony_ci .max_register = 0x16, 29462306a36Sopenharmony_ci .reg_defaults = ak4613_reg, 29562306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(ak4613_reg), 29662306a36Sopenharmony_ci .cache_type = REGCACHE_RBTREE, 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic const struct of_device_id ak4613_of_match[] = { 30062306a36Sopenharmony_ci { .compatible = "asahi-kasei,ak4613", .data = &ak4613_regmap_cfg }, 30162306a36Sopenharmony_ci {}, 30262306a36Sopenharmony_ci}; 30362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, ak4613_of_match); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic const struct i2c_device_id ak4613_i2c_id[] = { 30662306a36Sopenharmony_ci { "ak4613", (kernel_ulong_t)&ak4613_regmap_cfg }, 30762306a36Sopenharmony_ci { } 30862306a36Sopenharmony_ci}; 30962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(i2c, ak4613_i2c_id); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic const struct snd_soc_dapm_widget ak4613_dapm_widgets[] = { 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Outputs */ 31462306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT1"), 31562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT2"), 31662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT3"), 31762306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT4"), 31862306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT5"), 31962306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("LOUT6"), 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT1"), 32262306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT2"), 32362306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT3"), 32462306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT4"), 32562306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT5"), 32662306a36Sopenharmony_ci SND_SOC_DAPM_OUTPUT("ROUT6"), 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Inputs */ 32962306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("LIN1"), 33062306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("LIN2"), 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("RIN1"), 33362306a36Sopenharmony_ci SND_SOC_DAPM_INPUT("RIN2"), 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* DAC */ 33662306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC1", NULL, PW_MGMT3, 0, 0), 33762306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC2", NULL, PW_MGMT3, 1, 0), 33862306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC3", NULL, PW_MGMT3, 2, 0), 33962306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC4", NULL, PW_MGMT3, 3, 0), 34062306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC5", NULL, PW_MGMT3, 4, 0), 34162306a36Sopenharmony_ci SND_SOC_DAPM_DAC("DAC6", NULL, PW_MGMT3, 5, 0), 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci /* ADC */ 34462306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC1", NULL, PW_MGMT2, 0, 0), 34562306a36Sopenharmony_ci SND_SOC_DAPM_ADC("ADC2", NULL, PW_MGMT2, 1, 0), 34662306a36Sopenharmony_ci}; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic const struct snd_soc_dapm_route ak4613_intercon[] = { 34962306a36Sopenharmony_ci {"LOUT1", NULL, "DAC1"}, 35062306a36Sopenharmony_ci {"LOUT2", NULL, "DAC2"}, 35162306a36Sopenharmony_ci {"LOUT3", NULL, "DAC3"}, 35262306a36Sopenharmony_ci {"LOUT4", NULL, "DAC4"}, 35362306a36Sopenharmony_ci {"LOUT5", NULL, "DAC5"}, 35462306a36Sopenharmony_ci {"LOUT6", NULL, "DAC6"}, 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci {"ROUT1", NULL, "DAC1"}, 35762306a36Sopenharmony_ci {"ROUT2", NULL, "DAC2"}, 35862306a36Sopenharmony_ci {"ROUT3", NULL, "DAC3"}, 35962306a36Sopenharmony_ci {"ROUT4", NULL, "DAC4"}, 36062306a36Sopenharmony_ci {"ROUT5", NULL, "DAC5"}, 36162306a36Sopenharmony_ci {"ROUT6", NULL, "DAC6"}, 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci {"DAC1", NULL, "Playback"}, 36462306a36Sopenharmony_ci {"DAC2", NULL, "Playback"}, 36562306a36Sopenharmony_ci {"DAC3", NULL, "Playback"}, 36662306a36Sopenharmony_ci {"DAC4", NULL, "Playback"}, 36762306a36Sopenharmony_ci {"DAC5", NULL, "Playback"}, 36862306a36Sopenharmony_ci {"DAC6", NULL, "Playback"}, 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci {"Capture", NULL, "ADC1"}, 37162306a36Sopenharmony_ci {"Capture", NULL, "ADC2"}, 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci {"ADC1", NULL, "LIN1"}, 37462306a36Sopenharmony_ci {"ADC2", NULL, "LIN2"}, 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci {"ADC1", NULL, "RIN1"}, 37762306a36Sopenharmony_ci {"ADC2", NULL, "RIN2"}, 37862306a36Sopenharmony_ci}; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic void ak4613_dai_shutdown(struct snd_pcm_substream *substream, 38162306a36Sopenharmony_ci struct snd_soc_dai *dai) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 38462306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 38562306a36Sopenharmony_ci struct device *dev = component->dev; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci mutex_lock(&priv->lock); 38862306a36Sopenharmony_ci priv->cnt--; 38962306a36Sopenharmony_ci if (priv->cnt < 0) { 39062306a36Sopenharmony_ci dev_err(dev, "unexpected counter error\n"); 39162306a36Sopenharmony_ci priv->cnt = 0; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci if (!priv->cnt) 39462306a36Sopenharmony_ci priv->ctrl1 = 0; 39562306a36Sopenharmony_ci mutex_unlock(&priv->lock); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic void ak4613_hw_constraints(struct ak4613_priv *priv, 39962306a36Sopenharmony_ci struct snd_pcm_substream *substream) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 40262306a36Sopenharmony_ci static const unsigned int ak4613_rates[] = { 40362306a36Sopenharmony_ci 32000, 40462306a36Sopenharmony_ci 44100, 40562306a36Sopenharmony_ci 48000, 40662306a36Sopenharmony_ci 64000, 40762306a36Sopenharmony_ci 88200, 40862306a36Sopenharmony_ci 96000, 40962306a36Sopenharmony_ci 176400, 41062306a36Sopenharmony_ci 192000, 41162306a36Sopenharmony_ci }; 41262306a36Sopenharmony_ci#define AK4613_CHANNEL_2 0 41362306a36Sopenharmony_ci#define AK4613_CHANNEL_4 1 41462306a36Sopenharmony_ci#define AK4613_CHANNEL_8 2 41562306a36Sopenharmony_ci#define AK4613_CHANNEL_12 3 41662306a36Sopenharmony_ci#define AK4613_CHANNEL_NONE -1 41762306a36Sopenharmony_ci static const unsigned int ak4613_channels[] = { 41862306a36Sopenharmony_ci [AK4613_CHANNEL_2] = 2, 41962306a36Sopenharmony_ci [AK4613_CHANNEL_4] = 4, 42062306a36Sopenharmony_ci [AK4613_CHANNEL_8] = 8, 42162306a36Sopenharmony_ci [AK4613_CHANNEL_12] = 12, 42262306a36Sopenharmony_ci }; 42362306a36Sopenharmony_ci#define MODE_MAX 4 42462306a36Sopenharmony_ci#define SDTx_MAX 4 42562306a36Sopenharmony_ci#define MASK(x) (1 << AK4613_CHANNEL_##x) 42662306a36Sopenharmony_ci static const int mask_list[MODE_MAX][SDTx_MAX] = { 42762306a36Sopenharmony_ci /* SDTO SDTIx1 SDTIx2 SDTIx3 */ 42862306a36Sopenharmony_ci [AK4613_CONFIG_MODE_STEREO] = { MASK(2), MASK(2), MASK(2), MASK(2)}, 42962306a36Sopenharmony_ci [AK4613_CONFIG_MODE_TDM512] = { MASK(4), MASK(12), MASK(12), MASK(12)}, 43062306a36Sopenharmony_ci [AK4613_CONFIG_MODE_TDM256] = { MASK(4), MASK(8), MASK(8)|MASK(12), MASK(8)|MASK(12)}, 43162306a36Sopenharmony_ci [AK4613_CONFIG_MODE_TDM128] = { MASK(4), MASK(4), MASK(4)|MASK(8), MASK(4)|MASK(8)|MASK(12)}, 43262306a36Sopenharmony_ci }; 43362306a36Sopenharmony_ci struct snd_pcm_hw_constraint_list *constraint; 43462306a36Sopenharmony_ci unsigned int mask; 43562306a36Sopenharmony_ci unsigned int mode; 43662306a36Sopenharmony_ci unsigned int fs; 43762306a36Sopenharmony_ci int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 43862306a36Sopenharmony_ci int sdti_num; 43962306a36Sopenharmony_ci int i; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci constraint = &priv->constraint_rates; 44262306a36Sopenharmony_ci constraint->list = ak4613_rates; 44362306a36Sopenharmony_ci constraint->mask = 0; 44462306a36Sopenharmony_ci constraint->count = 0; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* 44762306a36Sopenharmony_ci * Slave Mode 44862306a36Sopenharmony_ci * Normal: [32kHz, 48kHz] : 256fs,384fs or 512fs 44962306a36Sopenharmony_ci * Double: [64kHz, 96kHz] : 256fs 45062306a36Sopenharmony_ci * Quad : [128kHz,192kHz]: 128fs 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * Master mode 45362306a36Sopenharmony_ci * Normal: [32kHz, 48kHz] : 256fs or 512fs 45462306a36Sopenharmony_ci * Double: [64kHz, 96kHz] : 256fs 45562306a36Sopenharmony_ci * Quad : [128kHz,192kHz]: 128fs 45662306a36Sopenharmony_ci */ 45762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ak4613_rates); i++) { 45862306a36Sopenharmony_ci /* minimum fs on each range */ 45962306a36Sopenharmony_ci fs = (ak4613_rates[i] <= 96000) ? 256 : 128; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci if (priv->sysclk >= ak4613_rates[i] * fs) 46262306a36Sopenharmony_ci constraint->count = i + 1; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, 46662306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, constraint); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci sdti_num = AK4613_CONFIG_SDTI_get(priv); 47062306a36Sopenharmony_ci if (WARN_ON(sdti_num >= SDTx_MAX)) 47162306a36Sopenharmony_ci return; 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (priv->cnt) { 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * If it was already working, 47662306a36Sopenharmony_ci * the constraint is same as working mode. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci mode = AK4613_CTRL1_TO_MODE(priv); 47962306a36Sopenharmony_ci mask = 0; /* no default */ 48062306a36Sopenharmony_ci } else { 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * It is not yet working, 48362306a36Sopenharmony_ci * the constraint is based on board configs. 48462306a36Sopenharmony_ci * STEREO mask is default 48562306a36Sopenharmony_ci */ 48662306a36Sopenharmony_ci mode = AK4613_CONFIG_GET(priv, MODE); 48762306a36Sopenharmony_ci mask = mask_list[AK4613_CONFIG_MODE_STEREO][is_play * sdti_num]; 48862306a36Sopenharmony_ci } 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (WARN_ON(mode >= MODE_MAX)) 49162306a36Sopenharmony_ci return; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* add each mode mask */ 49462306a36Sopenharmony_ci mask |= mask_list[mode][is_play * sdti_num]; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci constraint = &priv->constraint_channels; 49762306a36Sopenharmony_ci constraint->list = ak4613_channels; 49862306a36Sopenharmony_ci constraint->mask = mask; 49962306a36Sopenharmony_ci constraint->count = sizeof(ak4613_channels); 50062306a36Sopenharmony_ci snd_pcm_hw_constraint_list(runtime, 0, 50162306a36Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, constraint); 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic int ak4613_dai_startup(struct snd_pcm_substream *substream, 50562306a36Sopenharmony_ci struct snd_soc_dai *dai) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 50862306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci mutex_lock(&priv->lock); 51162306a36Sopenharmony_ci ak4613_hw_constraints(priv, substream); 51262306a36Sopenharmony_ci priv->cnt++; 51362306a36Sopenharmony_ci mutex_unlock(&priv->lock); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return 0; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic int ak4613_dai_set_sysclk(struct snd_soc_dai *codec_dai, 51962306a36Sopenharmony_ci int clk_id, unsigned int freq, int dir) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct snd_soc_component *component = codec_dai->component; 52262306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci priv->sysclk = freq; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci} 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int ak4613_dai_set_fmt(struct snd_soc_dai *dai, unsigned int format) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 53262306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 53362306a36Sopenharmony_ci unsigned int fmt; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci fmt = format & SND_SOC_DAIFMT_FORMAT_MASK; 53662306a36Sopenharmony_ci switch (fmt) { 53762306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 53862306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 53962306a36Sopenharmony_ci priv->fmt = fmt; 54062306a36Sopenharmony_ci break; 54162306a36Sopenharmony_ci default: 54262306a36Sopenharmony_ci return -EINVAL; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci fmt = format & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK; 54662306a36Sopenharmony_ci switch (fmt) { 54762306a36Sopenharmony_ci case SND_SOC_DAIFMT_CBC_CFC: 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci default: 55062306a36Sopenharmony_ci /* 55162306a36Sopenharmony_ci * SUPPORTME 55262306a36Sopenharmony_ci * 55362306a36Sopenharmony_ci * "clock provider" is not yet supperted 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci return -EINVAL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci} 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_cistatic int ak4613_dai_hw_params(struct snd_pcm_substream *substream, 56262306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 56362306a36Sopenharmony_ci struct snd_soc_dai *dai) 56462306a36Sopenharmony_ci{ 56562306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 56662306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 56762306a36Sopenharmony_ci struct device *dev = component->dev; 56862306a36Sopenharmony_ci unsigned int width = params_width(params); 56962306a36Sopenharmony_ci unsigned int fmt = priv->fmt; 57062306a36Sopenharmony_ci unsigned int rate; 57162306a36Sopenharmony_ci int i, ret; 57262306a36Sopenharmony_ci u8 ctrl2; 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci rate = params_rate(params); 57562306a36Sopenharmony_ci switch (rate) { 57662306a36Sopenharmony_ci case 32000: 57762306a36Sopenharmony_ci case 44100: 57862306a36Sopenharmony_ci case 48000: 57962306a36Sopenharmony_ci ctrl2 = DFS_NORMAL_SPEED; 58062306a36Sopenharmony_ci break; 58162306a36Sopenharmony_ci case 64000: 58262306a36Sopenharmony_ci case 88200: 58362306a36Sopenharmony_ci case 96000: 58462306a36Sopenharmony_ci ctrl2 = DFS_DOUBLE_SPEED; 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case 176400: 58762306a36Sopenharmony_ci case 192000: 58862306a36Sopenharmony_ci ctrl2 = DFS_QUAD_SPEED; 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci default: 59162306a36Sopenharmony_ci return -EINVAL; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci priv->rate = rate; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci /* 59662306a36Sopenharmony_ci * FIXME 59762306a36Sopenharmony_ci * 59862306a36Sopenharmony_ci * It doesn't have full TDM suppert yet 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_ci ret = -EINVAL; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci mutex_lock(&priv->lock); 60362306a36Sopenharmony_ci if (priv->cnt > 1) { 60462306a36Sopenharmony_ci /* 60562306a36Sopenharmony_ci * If it was already working, use current priv->ctrl1 60662306a36Sopenharmony_ci */ 60762306a36Sopenharmony_ci ret = 0; 60862306a36Sopenharmony_ci } else { 60962306a36Sopenharmony_ci /* 61062306a36Sopenharmony_ci * It is not yet working, 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci unsigned int channel = params_channels(params); 61362306a36Sopenharmony_ci u8 tdm; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* STEREO or TDM */ 61662306a36Sopenharmony_ci if (channel == 2) 61762306a36Sopenharmony_ci tdm = AK4613_CONFIG_MODE_STEREO; 61862306a36Sopenharmony_ci else 61962306a36Sopenharmony_ci tdm = AK4613_CONFIG_GET(priv, MODE); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci for (i = ARRAY_SIZE(ak4613_iface) - 1; i >= 0; i--) { 62262306a36Sopenharmony_ci const struct ak4613_interface *iface = ak4613_iface + i; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci if ((iface->fmt == fmt) && (iface->width == width)) { 62562306a36Sopenharmony_ci /* 62662306a36Sopenharmony_ci * Ctrl1 62762306a36Sopenharmony_ci * | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | 62862306a36Sopenharmony_ci * |TDM1|TDM0|DIF2|DIF1|DIF0|ATS1|ATS0|SMUTE| 62962306a36Sopenharmony_ci * < tdm > < iface->dif > 63062306a36Sopenharmony_ci */ 63162306a36Sopenharmony_ci priv->ctrl1 = (tdm << 6) | (iface->dif << 3); 63262306a36Sopenharmony_ci ret = 0; 63362306a36Sopenharmony_ci break; 63462306a36Sopenharmony_ci } 63562306a36Sopenharmony_ci } 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci mutex_unlock(&priv->lock); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (ret < 0) 64062306a36Sopenharmony_ci goto hw_params_end; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci snd_soc_component_update_bits(component, CTRL1, FMT_MASK, priv->ctrl1); 64362306a36Sopenharmony_ci snd_soc_component_update_bits(component, CTRL2, DFS_MASK, ctrl2); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci snd_soc_component_update_bits(component, ICTRL, ICTRL_MASK, priv->ic); 64662306a36Sopenharmony_ci snd_soc_component_update_bits(component, OCTRL, OCTRL_MASK, priv->oc); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cihw_params_end: 64962306a36Sopenharmony_ci if (ret < 0) 65062306a36Sopenharmony_ci dev_warn(dev, "unsupported data width/format combination\n"); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int ak4613_set_bias_level(struct snd_soc_component *component, 65662306a36Sopenharmony_ci enum snd_soc_bias_level level) 65762306a36Sopenharmony_ci{ 65862306a36Sopenharmony_ci u8 mgmt1 = 0; 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci switch (level) { 66162306a36Sopenharmony_ci case SND_SOC_BIAS_ON: 66262306a36Sopenharmony_ci mgmt1 |= RSTN; 66362306a36Sopenharmony_ci fallthrough; 66462306a36Sopenharmony_ci case SND_SOC_BIAS_PREPARE: 66562306a36Sopenharmony_ci mgmt1 |= PMADC | PMDAC; 66662306a36Sopenharmony_ci fallthrough; 66762306a36Sopenharmony_ci case SND_SOC_BIAS_STANDBY: 66862306a36Sopenharmony_ci mgmt1 |= PMVR; 66962306a36Sopenharmony_ci fallthrough; 67062306a36Sopenharmony_ci case SND_SOC_BIAS_OFF: 67162306a36Sopenharmony_ci default: 67262306a36Sopenharmony_ci break; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci snd_soc_component_write(component, PW_MGMT1, mgmt1); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci return 0; 67862306a36Sopenharmony_ci} 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic void ak4613_dummy_write(struct work_struct *work) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci struct ak4613_priv *priv = container_of(work, 68362306a36Sopenharmony_ci struct ak4613_priv, 68462306a36Sopenharmony_ci dummy_write_work); 68562306a36Sopenharmony_ci struct snd_soc_component *component = priv->component; 68662306a36Sopenharmony_ci unsigned int mgmt1; 68762306a36Sopenharmony_ci unsigned int mgmt3; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* 69062306a36Sopenharmony_ci * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks 69162306a36Sopenharmony_ci * 69262306a36Sopenharmony_ci * Note 69362306a36Sopenharmony_ci * 69462306a36Sopenharmony_ci * To avoid extra delay, we want to avoid preemption here, 69562306a36Sopenharmony_ci * but we can't. Because it uses I2C access which is using IRQ 69662306a36Sopenharmony_ci * and sleep. Thus, delay might be more than 5 LR clocks 69762306a36Sopenharmony_ci * see also 69862306a36Sopenharmony_ci * ak4613_dai_trigger() 69962306a36Sopenharmony_ci */ 70062306a36Sopenharmony_ci udelay(5000000 / priv->rate); 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci mgmt1 = snd_soc_component_read(component, PW_MGMT1); 70362306a36Sopenharmony_ci mgmt3 = snd_soc_component_read(component, PW_MGMT3); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci snd_soc_component_write(component, PW_MGMT1, mgmt1); 70662306a36Sopenharmony_ci snd_soc_component_write(component, PW_MGMT3, mgmt3); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic int ak4613_dai_trigger(struct snd_pcm_substream *substream, int cmd, 71062306a36Sopenharmony_ci struct snd_soc_dai *dai) 71162306a36Sopenharmony_ci{ 71262306a36Sopenharmony_ci struct snd_soc_component *component = dai->component; 71362306a36Sopenharmony_ci struct ak4613_priv *priv = snd_soc_component_get_drvdata(component); 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* 71662306a36Sopenharmony_ci * FIXME 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * PW_MGMT1 / PW_MGMT3 needs dummy write at least after 5 LR clocks 71962306a36Sopenharmony_ci * from Power Down Release. Otherwise, Playback volume will be 0dB. 72062306a36Sopenharmony_ci * To avoid complex multiple delay/dummy_write method from 72162306a36Sopenharmony_ci * ak4613_set_bias_level() / SND_SOC_DAPM_DAC_E("DACx", ...), 72262306a36Sopenharmony_ci * call it once here. 72362306a36Sopenharmony_ci * 72462306a36Sopenharmony_ci * But, unfortunately, we can't "write" here because here is atomic 72562306a36Sopenharmony_ci * context (It uses I2C access for writing). 72662306a36Sopenharmony_ci * Thus, use schedule_work() to switching to normal context 72762306a36Sopenharmony_ci * immediately. 72862306a36Sopenharmony_ci * 72962306a36Sopenharmony_ci * Note 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * Calling ak4613_dummy_write() function might be delayed. 73262306a36Sopenharmony_ci * In such case, ak4613 volume might be temporarily 0dB when 73362306a36Sopenharmony_ci * beggining of playback. 73462306a36Sopenharmony_ci * see also 73562306a36Sopenharmony_ci * ak4613_dummy_write() 73662306a36Sopenharmony_ci */ 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if ((cmd != SNDRV_PCM_TRIGGER_START) && 73962306a36Sopenharmony_ci (cmd != SNDRV_PCM_TRIGGER_RESUME)) 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK) 74362306a36Sopenharmony_ci return 0; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci priv->component = component; 74662306a36Sopenharmony_ci schedule_work(&priv->dummy_write_work); 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return 0; 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* 75262306a36Sopenharmony_ci * Select below from Sound Card, not Auto 75362306a36Sopenharmony_ci * SND_SOC_DAIFMT_CBC_CFC 75462306a36Sopenharmony_ci * SND_SOC_DAIFMT_CBP_CFP 75562306a36Sopenharmony_ci */ 75662306a36Sopenharmony_cistatic u64 ak4613_dai_formats = 75762306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_I2S | 75862306a36Sopenharmony_ci SND_SOC_POSSIBLE_DAIFMT_LEFT_J; 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic const struct snd_soc_dai_ops ak4613_dai_ops = { 76162306a36Sopenharmony_ci .startup = ak4613_dai_startup, 76262306a36Sopenharmony_ci .shutdown = ak4613_dai_shutdown, 76362306a36Sopenharmony_ci .set_sysclk = ak4613_dai_set_sysclk, 76462306a36Sopenharmony_ci .set_fmt = ak4613_dai_set_fmt, 76562306a36Sopenharmony_ci .trigger = ak4613_dai_trigger, 76662306a36Sopenharmony_ci .hw_params = ak4613_dai_hw_params, 76762306a36Sopenharmony_ci .auto_selectable_formats = &ak4613_dai_formats, 76862306a36Sopenharmony_ci .num_auto_selectable_formats = 1, 76962306a36Sopenharmony_ci}; 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci#define AK4613_PCM_RATE (SNDRV_PCM_RATE_32000 |\ 77262306a36Sopenharmony_ci SNDRV_PCM_RATE_44100 |\ 77362306a36Sopenharmony_ci SNDRV_PCM_RATE_48000 |\ 77462306a36Sopenharmony_ci SNDRV_PCM_RATE_64000 |\ 77562306a36Sopenharmony_ci SNDRV_PCM_RATE_88200 |\ 77662306a36Sopenharmony_ci SNDRV_PCM_RATE_96000 |\ 77762306a36Sopenharmony_ci SNDRV_PCM_RATE_176400 |\ 77862306a36Sopenharmony_ci SNDRV_PCM_RATE_192000) 77962306a36Sopenharmony_ci#define AK4613_PCM_FMTBIT (SNDRV_PCM_FMTBIT_S24_LE) 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic struct snd_soc_dai_driver ak4613_dai = { 78262306a36Sopenharmony_ci .name = "ak4613-hifi", 78362306a36Sopenharmony_ci .playback = { 78462306a36Sopenharmony_ci .stream_name = "Playback", 78562306a36Sopenharmony_ci .channels_min = 2, 78662306a36Sopenharmony_ci .channels_max = 12, 78762306a36Sopenharmony_ci .rates = AK4613_PCM_RATE, 78862306a36Sopenharmony_ci .formats = AK4613_PCM_FMTBIT, 78962306a36Sopenharmony_ci }, 79062306a36Sopenharmony_ci .capture = { 79162306a36Sopenharmony_ci .stream_name = "Capture", 79262306a36Sopenharmony_ci .channels_min = 2, 79362306a36Sopenharmony_ci .channels_max = 4, 79462306a36Sopenharmony_ci .rates = AK4613_PCM_RATE, 79562306a36Sopenharmony_ci .formats = AK4613_PCM_FMTBIT, 79662306a36Sopenharmony_ci }, 79762306a36Sopenharmony_ci .ops = &ak4613_dai_ops, 79862306a36Sopenharmony_ci .symmetric_rate = 1, 79962306a36Sopenharmony_ci}; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic int ak4613_suspend(struct snd_soc_component *component) 80262306a36Sopenharmony_ci{ 80362306a36Sopenharmony_ci struct regmap *regmap = dev_get_regmap(component->dev, NULL); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci regcache_cache_only(regmap, true); 80662306a36Sopenharmony_ci regcache_mark_dirty(regmap); 80762306a36Sopenharmony_ci return 0; 80862306a36Sopenharmony_ci} 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_cistatic int ak4613_resume(struct snd_soc_component *component) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci struct regmap *regmap = dev_get_regmap(component->dev, NULL); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci regcache_cache_only(regmap, false); 81562306a36Sopenharmony_ci return regcache_sync(regmap); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic const struct snd_soc_component_driver soc_component_dev_ak4613 = { 81962306a36Sopenharmony_ci .suspend = ak4613_suspend, 82062306a36Sopenharmony_ci .resume = ak4613_resume, 82162306a36Sopenharmony_ci .set_bias_level = ak4613_set_bias_level, 82262306a36Sopenharmony_ci .controls = ak4613_snd_controls, 82362306a36Sopenharmony_ci .num_controls = ARRAY_SIZE(ak4613_snd_controls), 82462306a36Sopenharmony_ci .dapm_widgets = ak4613_dapm_widgets, 82562306a36Sopenharmony_ci .num_dapm_widgets = ARRAY_SIZE(ak4613_dapm_widgets), 82662306a36Sopenharmony_ci .dapm_routes = ak4613_intercon, 82762306a36Sopenharmony_ci .num_dapm_routes = ARRAY_SIZE(ak4613_intercon), 82862306a36Sopenharmony_ci .idle_bias_on = 1, 82962306a36Sopenharmony_ci .endianness = 1, 83062306a36Sopenharmony_ci}; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic void ak4613_parse_of(struct ak4613_priv *priv, 83362306a36Sopenharmony_ci struct device *dev) 83462306a36Sopenharmony_ci{ 83562306a36Sopenharmony_ci struct device_node *np = dev->of_node; 83662306a36Sopenharmony_ci char prop[32]; 83762306a36Sopenharmony_ci int sdti_num; 83862306a36Sopenharmony_ci int i; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Input 1 - 2 */ 84162306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 84262306a36Sopenharmony_ci snprintf(prop, sizeof(prop), "asahi-kasei,in%d-single-end", i + 1); 84362306a36Sopenharmony_ci if (!of_get_property(np, prop, NULL)) 84462306a36Sopenharmony_ci priv->ic |= 1 << i; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci /* Output 1 - 6 */ 84862306a36Sopenharmony_ci for (i = 0; i < 6; i++) { 84962306a36Sopenharmony_ci snprintf(prop, sizeof(prop), "asahi-kasei,out%d-single-end", i + 1); 85062306a36Sopenharmony_ci if (!of_get_property(np, prop, NULL)) 85162306a36Sopenharmony_ci priv->oc |= 1 << i; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci /* 85562306a36Sopenharmony_ci * enable TDM256 test 85662306a36Sopenharmony_ci * 85762306a36Sopenharmony_ci * !!! FIXME !!! 85862306a36Sopenharmony_ci * 85962306a36Sopenharmony_ci * It should be configured by DT or other way 86062306a36Sopenharmony_ci * if it was full supported. 86162306a36Sopenharmony_ci * But it is using ifdef style for now for test 86262306a36Sopenharmony_ci * purpose. 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_ci#if defined(AK4613_ENABLE_TDM_TEST) 86562306a36Sopenharmony_ci AK4613_CONFIG_SET(priv, MODE_TDM256); 86662306a36Sopenharmony_ci#endif 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci /* 86962306a36Sopenharmony_ci * connected STDI 87062306a36Sopenharmony_ci * TDM support is assuming it is probed via Audio-Graph-Card style here. 87162306a36Sopenharmony_ci * Default is SDTIx1 if it was probed via Simple-Audio-Card for now. 87262306a36Sopenharmony_ci */ 87362306a36Sopenharmony_ci sdti_num = of_graph_get_endpoint_count(np); 87462306a36Sopenharmony_ci if ((sdti_num >= SDTx_MAX) || (sdti_num < 1)) 87562306a36Sopenharmony_ci sdti_num = 1; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci AK4613_CONFIG_SDTI_set(priv, sdti_num); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_cistatic int ak4613_i2c_probe(struct i2c_client *i2c) 88162306a36Sopenharmony_ci{ 88262306a36Sopenharmony_ci struct device *dev = &i2c->dev; 88362306a36Sopenharmony_ci const struct regmap_config *regmap_cfg; 88462306a36Sopenharmony_ci struct regmap *regmap; 88562306a36Sopenharmony_ci struct ak4613_priv *priv; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci regmap_cfg = i2c_get_match_data(i2c); 88862306a36Sopenharmony_ci if (!regmap_cfg) 88962306a36Sopenharmony_ci return -EINVAL; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 89262306a36Sopenharmony_ci if (!priv) 89362306a36Sopenharmony_ci return -ENOMEM; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci ak4613_parse_of(priv, dev); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci priv->ctrl1 = 0; 89862306a36Sopenharmony_ci priv->cnt = 0; 89962306a36Sopenharmony_ci priv->sysclk = 0; 90062306a36Sopenharmony_ci INIT_WORK(&priv->dummy_write_work, ak4613_dummy_write); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci mutex_init(&priv->lock); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci i2c_set_clientdata(i2c, priv); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci regmap = devm_regmap_init_i2c(i2c, regmap_cfg); 90762306a36Sopenharmony_ci if (IS_ERR(regmap)) 90862306a36Sopenharmony_ci return PTR_ERR(regmap); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci return devm_snd_soc_register_component(dev, &soc_component_dev_ak4613, 91162306a36Sopenharmony_ci &ak4613_dai, 1); 91262306a36Sopenharmony_ci} 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_cistatic struct i2c_driver ak4613_i2c_driver = { 91562306a36Sopenharmony_ci .driver = { 91662306a36Sopenharmony_ci .name = "ak4613-codec", 91762306a36Sopenharmony_ci .of_match_table = ak4613_of_match, 91862306a36Sopenharmony_ci }, 91962306a36Sopenharmony_ci .probe = ak4613_i2c_probe, 92062306a36Sopenharmony_ci .id_table = ak4613_i2c_id, 92162306a36Sopenharmony_ci}; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cimodule_i2c_driver(ak4613_i2c_driver); 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ciMODULE_DESCRIPTION("Soc AK4613 driver"); 92662306a36Sopenharmony_ciMODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>"); 92762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 928