515_sound.patch 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. diff --git a/sound/soc/sunxi/sun8i-codec-analog.c b/sound/soc/sunxi/sun8i-codec-analog.c
  2. index be872eefa61e..ca5f4e43476b 100644
  3. --- a/sound/soc/sunxi/sun8i-codec-analog.c
  4. +++ b/sound/soc/sunxi/sun8i-codec-analog.c
  5. @@ -19,6 +19,8 @@
  6. #include <sound/tlv.h>
  7. #include "sun8i-adda-pr-regmap.h"
  8. +#include <linux/gpio.h>
  9. +#include <linux/gpio/consumer.h>
  10. /* Codec analog control register offsets and bit fields */
  11. #define SUN8I_ADDA_HP_VOLC 0x00
  12. @@ -113,6 +115,81 @@
  13. #define SUN8I_ADDA_ADC_AP_EN_ADCLEN 6
  14. #define SUN8I_ADDA_ADC_AP_EN_ADCG 0
  15. +/* Analog control register access bits */
  16. +#define ADDA_PR 0x0 /* PRCM base + 0x1c0 */
  17. +#define ADDA_PR_RESET BIT(28)
  18. +#define ADDA_PR_WRITE BIT(24)
  19. +#define ADDA_PR_ADDR_SHIFT 16
  20. +#define ADDA_PR_ADDR_MASK GENMASK(4, 0)
  21. +#define ADDA_PR_DATA_IN_SHIFT 8
  22. +#define ADDA_PR_DATA_IN_MASK GENMASK(7, 0)
  23. +#define ADDA_PR_DATA_OUT_SHIFT 0
  24. +#define ADDA_PR_DATA_OUT_MASK GENMASK(7, 0)
  25. +
  26. +/* regmap access bits */
  27. +static int adda_reg_read(void *context, unsigned int reg, unsigned int *val)
  28. +{
  29. + void __iomem *base = (void __iomem *)context;
  30. + u32 tmp;
  31. +
  32. + /* De-assert reset */
  33. + writel(readl(base) | ADDA_PR_RESET, base);
  34. +
  35. + /* Clear write bit */
  36. + writel(readl(base) & ~ADDA_PR_WRITE, base);
  37. +
  38. + /* Set register address */
  39. + tmp = readl(base);
  40. + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
  41. + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
  42. + writel(tmp, base);
  43. +
  44. + /* Read back value */
  45. + *val = readl(base) & ADDA_PR_DATA_OUT_MASK;
  46. +
  47. + return 0;
  48. +}
  49. +
  50. +static int adda_reg_write(void *context, unsigned int reg, unsigned int val)
  51. +{
  52. + void __iomem *base = (void __iomem *)context;
  53. + u32 tmp;
  54. +
  55. + /* De-assert reset */
  56. + writel(readl(base) | ADDA_PR_RESET, base);
  57. +
  58. + /* Set register address */
  59. + tmp = readl(base);
  60. + tmp &= ~(ADDA_PR_ADDR_MASK << ADDA_PR_ADDR_SHIFT);
  61. + tmp |= (reg & ADDA_PR_ADDR_MASK) << ADDA_PR_ADDR_SHIFT;
  62. + writel(tmp, base);
  63. +
  64. + /* Set data to write */
  65. + tmp = readl(base);
  66. + tmp &= ~(ADDA_PR_DATA_IN_MASK << ADDA_PR_DATA_IN_SHIFT);
  67. + tmp |= (val & ADDA_PR_DATA_IN_MASK) << ADDA_PR_DATA_IN_SHIFT;
  68. + writel(tmp, base);
  69. +
  70. + /* Set write bit to signal a write */
  71. + writel(readl(base) | ADDA_PR_WRITE, base);
  72. +
  73. + /* Clear write bit */
  74. + writel(readl(base) & ~ADDA_PR_WRITE, base);
  75. +
  76. + return 0;
  77. +}
  78. +
  79. +static const struct regmap_config adda_pr_regmap_cfg = {
  80. + .name = "adda-pr",
  81. + .reg_bits = 5,
  82. + .reg_stride = 1,
  83. + .val_bits = 8,
  84. + .reg_read = adda_reg_read,
  85. + .reg_write = adda_reg_write,
  86. + .fast_io = true,
  87. + .max_register = 24,
  88. +};
  89. +
  90. /* mixer controls */
  91. static const struct snd_kcontrol_new sun8i_codec_mixer_controls[] = {
  92. SOC_DAPM_DOUBLE_R("DAC Playback Switch",
  93. @@ -316,7 +393,7 @@ static const struct snd_soc_dapm_route sun8i_codec_mixer_routes[] = {
  94. /* headphone specific controls, widgets, and routes */
  95. static const DECLARE_TLV_DB_SCALE(sun8i_codec_hp_vol_scale, -6300, 100, 1);
  96. static const struct snd_kcontrol_new sun8i_codec_headphone_controls[] = {
  97. - SOC_SINGLE_TLV("Headphone Playback Volume",
  98. + SOC_SINGLE_TLV("Master Playback Volume",
  99. SUN8I_ADDA_HP_VOLC,
  100. SUN8I_ADDA_HP_VOLC_HP_VOL, 0x3f, 0,
  101. sun8i_codec_hp_vol_scale),
  102. @@ -673,7 +750,7 @@ struct sun8i_codec_analog_quirks {
  103. static const struct sun8i_codec_analog_quirks sun8i_a23_quirks = {
  104. .has_headphone = true,
  105. - .has_hmic = true,
  106. +// .has_hmic = true,
  107. .has_linein = true,
  108. .has_mbias = true,
  109. .has_mic2 = true,
  110. @@ -817,10 +894,148 @@ static const struct of_device_id sun8i_codec_analog_of_match[] = {
  111. };
  112. MODULE_DEVICE_TABLE(of, sun8i_codec_analog_of_match);
  113. +#define SUNXI_HMIC_ENABLE (0x4)
  114. +#define SUNXI_HMIC_CTL (0x8)
  115. +#define SUNXI_HMIC_DATA (0xc)
  116. +
  117. +/*
  118. +* SUNXI_HMIC_CTL
  119. +*HMIC Control Register
  120. +*CONFIG_ARCH_SUN8IW5:0x1c8
  121. +*/
  122. +#define HMIC_M (28)
  123. +#define HMIC_N (24)
  124. +#define HMIC_DIRQ (23)
  125. +#define HMIC_TH1_HYS (21)
  126. +#define HMIC_EARPHONE_OUT_IRQ_EN (20)
  127. +#define HMIC_EARPHONE_IN_IRQ_EN (19)
  128. +#define HMIC_KEY_UP_IRQ_EN (18)
  129. +#define HMIC_KEY_DOWN_IRQ_EN (17)
  130. +#define HMIC_DATA_IRQ_EN (16)
  131. +#define HMIC_DS_SAMP (14)
  132. +#define HMIC_TH2_HYS (13)
  133. +#define HMIC_TH2_KEY (8)
  134. +#define HMIC_SF_SMOOTH_FIL (6)
  135. +#define KEY_UP_IRQ_PEND (5)
  136. +#define HMIC_TH1_EARPHONE (0)
  137. +
  138. +/*
  139. +* SUNXI_HMIC_DATA
  140. +*HMIC Data Register
  141. +*
  142. +*CONFIG_ARCH_SUN8IW5:0x1cc
  143. +*/
  144. +#define HMIC_EARPHONE_OUT_IRQ_PEND (20)
  145. +#define HMIC_EARPHONE_IN_IRQ_PEND (19)
  146. +#define HMIC_KEY_UP_IRQ_PEND (18)
  147. +#define HMIC_KEY_DOWN_IRQ_PEND (17)
  148. +#define HMIC_DATA_IRQ_PEND (16)
  149. +#define HMIC_ADC_DATA (0)
  150. +
  151. +#define HP_VOLC (0x00)
  152. +#define LOMIXSC (0x01)
  153. +#define ROMIXSC (0x02)
  154. +#define DAC_PA_SRC (0x03)
  155. +#define PAEN_HP_CTRL (0x07)
  156. +#define ADDA_APT2 (0x12)
  157. +#define MIC1G_MICBIAS_CTRL (0x0B)
  158. +#define PA_ANTI_POP_REG_CTRL (0x0E)
  159. +#define PA_SLOPE_SELECT (3)
  160. +#define PA_ANTI_POP_EN (0)
  161. +
  162. +static void __iomem *sun8i_codec_analog_base;
  163. +static struct gpio_desc * speaker_amplifier_gpio;
  164. +
  165. +static int hmic_wrreg_prcm_bits(unsigned short reg, unsigned int mask, unsigned int value)
  166. +{
  167. + unsigned int old, new;
  168. +
  169. + adda_reg_read(sun8i_codec_analog_base, reg, &old);
  170. + new = (old & ~mask) | value;
  171. + adda_reg_write(sun8i_codec_analog_base, reg,new);
  172. +
  173. + return 0;
  174. +}
  175. +
  176. +static int hmic_wr_prcm_control(u32 reg, u32 mask, u32 shift, u32 val)
  177. +{
  178. + u32 reg_val;
  179. + reg_val = val << shift;
  180. + mask = mask << shift;
  181. + hmic_wrreg_prcm_bits(reg, mask, reg_val);
  182. + return 0;
  183. +}
  184. +
  185. +static int hmic_wrreg_bits(unsigned short reg, unsigned int mask, unsigned int value)
  186. +{
  187. + unsigned int old, new;
  188. +
  189. + old = readl(sun8i_codec_analog_base + reg);
  190. + new = (old & ~mask) | value;
  191. +
  192. + writel(new, sun8i_codec_analog_base + reg);
  193. +
  194. + return 0;
  195. +}
  196. +
  197. +static int hmic_wr_control(u32 reg, u32 mask, u32 shift, u32 val)
  198. +{
  199. + u32 reg_val;
  200. + reg_val = val << shift;
  201. + mask = mask << shift;
  202. + hmic_wrreg_bits(reg, mask, reg_val);
  203. + return 0;
  204. +}
  205. +
  206. +static irqreturn_t sunxi_codec_analog_irq(int irq, void *dev_id)
  207. +{
  208. + u32 tmp;
  209. +
  210. + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_DOWN_IRQ_PEND, 0x1);
  211. + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_IN_IRQ_PEND, 0x1);
  212. + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_KEY_UP_IRQ_PEND, 0x1);
  213. + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_EARPHONE_OUT_IRQ_PEND, 0x1);
  214. + hmic_wr_control(SUNXI_HMIC_DATA, 0x1, HMIC_DATA_IRQ_PEND, 0x1);
  215. +
  216. + tmp = readl(sun8i_codec_analog_base + SUNXI_HMIC_DATA);
  217. + if(tmp & 0x1f)
  218. + gpiod_set_value(speaker_amplifier_gpio, 0);
  219. + else
  220. + gpiod_set_value(speaker_amplifier_gpio, 1);
  221. +
  222. + return IRQ_HANDLED;
  223. +}
  224. +
  225. +static void sunxi_hppa_enable(void) {
  226. + /*fix the resume blaze blaze noise*/
  227. + hmic_wr_prcm_control(ADDA_APT2, 0x1, PA_SLOPE_SELECT, 0x0);
  228. + hmic_wr_prcm_control(SUN8I_ADDA_PAEN_HP_CTRL, 0x3, SUN8I_ADDA_PAEN_HP_CTRL_PA_ANTI_POP_CTRL, 0x1);
  229. + hmic_wr_prcm_control(PA_ANTI_POP_REG_CTRL, 0x7, PA_ANTI_POP_EN, 0x2);
  230. + usleep_range(100,200);
  231. + /*enable pa*/
  232. + hmic_wr_prcm_control(SUN8I_ADDA_PAEN_HP_CTRL, 0x1, SUN8I_ADDA_PAEN_HP_CTRL_HPPAEN, 0x1);
  233. +}
  234. +
  235. +static void sunxi_hbias_enable(void) {
  236. + /*audio codec hardware bug. the HBIASADCEN bit must be enable in init*/
  237. + hmic_wr_prcm_control(SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 0x1, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIAS_MODE, 0x1);
  238. + hmic_wr_prcm_control(SUN8I_ADDA_MIC1G_MICBIAS_CTRL, 0x1, SUN8I_ADDA_MIC1G_MICBIAS_CTRL_HMICBIASEN, 0x1);
  239. +}
  240. +
  241. +static void codec_init_events(void)
  242. +{
  243. + /*fix the resume blaze blaze noise*/
  244. + sunxi_hppa_enable();
  245. + msleep(450);
  246. + /*audio codec hardware bug. the HBIASADCEN bit must be enable in init*/
  247. + sunxi_hbias_enable();
  248. +}
  249. +
  250. static int sun8i_codec_analog_probe(struct platform_device *pdev)
  251. {
  252. struct regmap *regmap;
  253. void __iomem *base;
  254. + int irq, ret;
  255. base = devm_platform_ioremap_resource(pdev, 0);
  256. if (IS_ERR(base)) {
  257. @@ -828,6 +1043,38 @@ static int sun8i_codec_analog_probe(struct platform_device *pdev)
  258. return PTR_ERR(base);
  259. }
  260. + sun8i_codec_analog_base = base;
  261. + speaker_amplifier_gpio = devm_gpiod_get_optional(&pdev->dev, "speaker-amplifier", GPIOD_OUT_HIGH);
  262. + if (!IS_ERR_OR_NULL(speaker_amplifier_gpio)) {
  263. +
  264. + hmic_wr_control(SUNXI_HMIC_CTL, 0xf, HMIC_M, 0x0); /*0xf should be get from hw_debug 28*/
  265. + hmic_wr_control(SUNXI_HMIC_CTL, 0xf, HMIC_N, 0x0); /*0xf should be get from hw_debug 24 0xf*/
  266. +// hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DIRQ, 0x1); /*23*/
  267. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_EARPHONE_OUT_IRQ_EN, 0x1); /*20*/
  268. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_EARPHONE_IN_IRQ_EN, 0x1); /*19*/
  269. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_KEY_UP_IRQ_EN, 0x1); /*18*/
  270. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_KEY_DOWN_IRQ_EN, 0x1); /*17*/
  271. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1, HMIC_DATA_IRQ_EN, 0x1); /*16*/
  272. + hmic_wr_control(SUNXI_HMIC_CTL, 0x3, HMIC_DS_SAMP, 0x0); /*14 */
  273. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1f, HMIC_TH2_KEY, 0x0); /*0xf should be get from hw_debug 8*/
  274. + hmic_wr_control(SUNXI_HMIC_CTL, 0x1f, HMIC_TH1_EARPHONE, 0x1); /*0x1 should be get from hw_debug 0*/
  275. +
  276. + irq = platform_get_irq(pdev, 0);
  277. + if (irq < 0) {
  278. + dev_err(&pdev->dev, "Can't retrieve our interrupt\n");
  279. + return irq;
  280. + }
  281. +
  282. + ret = devm_request_irq(&pdev->dev, irq, sunxi_codec_analog_irq, 0, "audio_hmic_irq", NULL);
  283. + if (ret) {
  284. + dev_err(&pdev->dev, "can't register interrupt handler irq %d: %d\n",
  285. + irq, ret);
  286. + return ret;
  287. + }
  288. +
  289. + codec_init_events();
  290. + }
  291. +
  292. regmap = sun8i_adda_pr_regmap_init(&pdev->dev, base);
  293. if (IS_ERR(regmap)) {
  294. dev_err(&pdev->dev, "Failed to create regmap\n");
  295. diff --git a/sound/soc/sunxi/sun8i-codec.c b/sound/soc/sunxi/sun8i-codec.c
  296. index 518bfb724a5b..b6a90e33f20a 100644
  297. --- a/sound/soc/sunxi/sun8i-codec.c
  298. +++ b/sound/soc/sunxi/sun8i-codec.c
  299. @@ -257,6 +257,9 @@ static int sun8i_codec_update_sample_rate(struct sun8i_codec *scodec)
  300. regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
  301. SUN8I_SYS_SR_CTRL_AIF1_FS_MASK,
  302. hw_rate << SUN8I_SYS_SR_CTRL_AIF1_FS);
  303. + regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL,
  304. + SUN8I_SYS_SR_CTRL_AIF2_FS_MASK,
  305. + hw_rate << SUN8I_SYS_SR_CTRL_AIF2_FS);
  306. return 0;
  307. }
  308. @@ -288,6 +291,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  309. SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_MASK,
  310. SUN8I_AIF3_CLK_CTRL_AIF3_CLK_SRC_AIF2);
  311. } else {
  312. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  313. + BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
  314. + value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
  315. regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
  316. BIT(SUN8I_AIF_CLK_CTRL_MSTR_MOD),
  317. value << SUN8I_AIF_CLK_CTRL_MSTR_MOD);
  318. @@ -321,6 +327,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  319. if (format != 3)
  320. return -EINVAL;
  321. } else {
  322. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  323. + SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
  324. + format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
  325. regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
  326. SUN8I_AIF_CLK_CTRL_DATA_FMT_MASK,
  327. format << SUN8I_AIF_CLK_CTRL_DATA_FMT);
  328. @@ -365,6 +374,9 @@ static int sun8i_codec_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
  329. invert ^= scodec->quirks->lrck_inversion;
  330. }
  331. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  332. + SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
  333. + invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
  334. regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
  335. SUN8I_AIF_CLK_CTRL_CLK_INV_MASK,
  336. invert << SUN8I_AIF_CLK_CTRL_CLK_INV);
  337. @@ -519,6 +531,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
  338. return -EINVAL;
  339. }
  340. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  341. + SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
  342. + word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
  343. regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id),
  344. SUN8I_AIF_CLK_CTRL_WORD_SIZ_MASK,
  345. word_size << SUN8I_AIF_CLK_CTRL_WORD_SIZ);
  346. @@ -548,6 +563,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
  347. clk_reg = SUN8I_AIF_CLK_CTRL(dai->id);
  348. }
  349. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  350. + SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
  351. + (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
  352. regmap_update_bits(scodec->regmap, clk_reg,
  353. SUN8I_AIF_CLK_CTRL_LRCK_DIV_MASK,
  354. (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV);
  355. @@ -557,6 +575,9 @@ static int sun8i_codec_hw_params(struct snd_pcm_substream *substream,
  356. if (bclk_div < 0)
  357. return bclk_div;
  358. + regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(SUN8I_CODEC_AIF1),
  359. + SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
  360. + bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
  361. regmap_update_bits(scodec->regmap, clk_reg,
  362. SUN8I_AIF_CLK_CTRL_BCLK_DIV_MASK,
  363. bclk_div << SUN8I_AIF_CLK_CTRL_BCLK_DIV);
  364. @@ -1226,6 +1247,7 @@ static const struct snd_soc_component_driver sun8i_soc_component = {
  365. };
  366. static const struct regmap_config sun8i_codec_regmap_config = {
  367. + .name = "sun8i_codec",
  368. .reg_bits = 32,
  369. .reg_stride = 4,
  370. .val_bits = 32,