18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * STK1160 driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2012 Ezequiel Garcia 68c2ecf20Sopenharmony_ci * <elezegarcia--a.t--gmail.com> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Copyright (C) 2016 Marcel Hasler 98c2ecf20Sopenharmony_ci * <mahasler--a.t--gmail.com> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Based on Easycap driver by R.M. Thomas 128c2ecf20Sopenharmony_ci * Copyright (C) 2010 R.M. Thomas 138c2ecf20Sopenharmony_ci * <rmthomas--a.t--sciolus.org> 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <linux/delay.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "stk1160.h" 198c2ecf20Sopenharmony_ci#include "stk1160-reg.h" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistatic int stk1160_ac97_wait_transfer_complete(struct stk1160 *dev) 228c2ecf20Sopenharmony_ci{ 238c2ecf20Sopenharmony_ci unsigned long timeout = jiffies + msecs_to_jiffies(STK1160_AC97_TIMEOUT); 248c2ecf20Sopenharmony_ci u8 value; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci /* Wait for AC97 transfer to complete */ 278c2ecf20Sopenharmony_ci while (time_is_after_jiffies(timeout)) { 288c2ecf20Sopenharmony_ci stk1160_read_reg(dev, STK1160_AC97CTL_0, &value); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci if (!(value & (STK1160_AC97CTL_0_CR | STK1160_AC97CTL_0_CW))) 318c2ecf20Sopenharmony_ci return 0; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci usleep_range(50, 100); 348c2ecf20Sopenharmony_ci } 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci stk1160_err("AC97 transfer took too long, this should never happen!"); 378c2ecf20Sopenharmony_ci return -EBUSY; 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void stk1160_write_ac97(struct stk1160 *dev, u16 reg, u16 value) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci /* Set codec register address */ 438c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci /* Set codec command */ 468c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97_CMD, value & 0xff); 478c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97_CMD + 1, (value & 0xff00) >> 8); 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci /* Set command write bit to initiate write operation */ 508c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Wait for command write bit to be cleared */ 538c2ecf20Sopenharmony_ci stk1160_ac97_wait_transfer_complete(dev); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#ifdef DEBUG 578c2ecf20Sopenharmony_cistatic u16 stk1160_read_ac97(struct stk1160 *dev, u16 reg) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci u8 vall = 0; 608c2ecf20Sopenharmony_ci u8 valh = 0; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* Set codec register address */ 638c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97_ADDR, reg); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* Set command read bit to initiate read operation */ 668c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8b); 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* Wait for command read bit to be cleared */ 698c2ecf20Sopenharmony_ci if (stk1160_ac97_wait_transfer_complete(dev) < 0) 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* Retrieve register value */ 748c2ecf20Sopenharmony_ci stk1160_read_reg(dev, STK1160_AC97_CMD, &vall); 758c2ecf20Sopenharmony_ci stk1160_read_reg(dev, STK1160_AC97_CMD + 1, &valh); 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci return (valh << 8) | vall; 788c2ecf20Sopenharmony_ci} 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_civoid stk1160_ac97_dump_regs(struct stk1160 *dev) 818c2ecf20Sopenharmony_ci{ 828c2ecf20Sopenharmony_ci u16 value; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x12); /* CD volume */ 858c2ecf20Sopenharmony_ci stk1160_dbg("0x12 == 0x%04x", value); 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x10); /* Line-in volume */ 888c2ecf20Sopenharmony_ci stk1160_dbg("0x10 == 0x%04x", value); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x0e); /* MIC volume (mono) */ 918c2ecf20Sopenharmony_ci stk1160_dbg("0x0e == 0x%04x", value); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x16); /* Aux volume */ 948c2ecf20Sopenharmony_ci stk1160_dbg("0x16 == 0x%04x", value); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x1a); /* Record select */ 978c2ecf20Sopenharmony_ci stk1160_dbg("0x1a == 0x%04x", value); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x02); /* Master volume */ 1008c2ecf20Sopenharmony_ci stk1160_dbg("0x02 == 0x%04x", value); 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci value = stk1160_read_ac97(dev, 0x1c); /* Record gain */ 1038c2ecf20Sopenharmony_ci stk1160_dbg("0x1c == 0x%04x", value); 1048c2ecf20Sopenharmony_ci} 1058c2ecf20Sopenharmony_ci#endif 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int stk1160_has_audio(struct stk1160 *dev) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci u8 value; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci stk1160_read_reg(dev, STK1160_POSV_L, &value); 1128c2ecf20Sopenharmony_ci return !(value & STK1160_POSV_L_ACDOUT); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int stk1160_has_ac97(struct stk1160 *dev) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci u8 value; 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci stk1160_read_reg(dev, STK1160_POSV_L, &value); 1208c2ecf20Sopenharmony_ci return !(value & STK1160_POSV_L_ACSYNC); 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_civoid stk1160_ac97_setup(struct stk1160 *dev) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci if (!stk1160_has_audio(dev)) { 1268c2ecf20Sopenharmony_ci stk1160_info("Device doesn't support audio, skipping AC97 setup."); 1278c2ecf20Sopenharmony_ci return; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci if (!stk1160_has_ac97(dev)) { 1318c2ecf20Sopenharmony_ci stk1160_info("Device uses internal 8-bit ADC, skipping AC97 setup."); 1328c2ecf20Sopenharmony_ci return; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* Two-step reset AC97 interface and hardware codec */ 1368c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x94); 1378c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_0, 0x8c); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci /* Set 16-bit audio data and choose L&R channel*/ 1408c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_1 + 2, 0x01); 1418c2ecf20Sopenharmony_ci stk1160_write_reg(dev, STK1160_AC97CTL_1 + 3, 0x00); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Setup channels */ 1448c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x12, 0x8808); /* CD volume */ 1458c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x10, 0x0808); /* Line-in volume */ 1468c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x0e, 0x0008); /* MIC volume (mono) */ 1478c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x16, 0x0808); /* Aux volume */ 1488c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x1a, 0x0404); /* Record select */ 1498c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x02, 0x0000); /* Master volume */ 1508c2ecf20Sopenharmony_ci stk1160_write_ac97(dev, 0x1c, 0x0808); /* Record gain */ 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci#ifdef DEBUG 1538c2ecf20Sopenharmony_ci stk1160_ac97_dump_regs(dev); 1548c2ecf20Sopenharmony_ci#endif 1558c2ecf20Sopenharmony_ci} 156