162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci// 362306a36Sopenharmony_ci// rt711-sdw.c -- rt711 ALSA SoC audio driver 462306a36Sopenharmony_ci// 562306a36Sopenharmony_ci// Copyright(c) 2019 Realtek Semiconductor Corp. 662306a36Sopenharmony_ci// 762306a36Sopenharmony_ci// 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1262306a36Sopenharmony_ci#include <linux/soundwire/sdw.h> 1362306a36Sopenharmony_ci#include <linux/soundwire/sdw_type.h> 1462306a36Sopenharmony_ci#include <linux/soundwire/sdw_registers.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <sound/soc.h> 1962306a36Sopenharmony_ci#include "rt711.h" 2062306a36Sopenharmony_ci#include "rt711-sdw.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_cistatic bool rt711_readable_register(struct device *dev, unsigned int reg) 2362306a36Sopenharmony_ci{ 2462306a36Sopenharmony_ci switch (reg) { 2562306a36Sopenharmony_ci case 0x00e0: 2662306a36Sopenharmony_ci case 0x00f0: 2762306a36Sopenharmony_ci case 0x2012 ... 0x2016: 2862306a36Sopenharmony_ci case 0x201a ... 0x2027: 2962306a36Sopenharmony_ci case 0x2029 ... 0x202a: 3062306a36Sopenharmony_ci case 0x202d ... 0x2034: 3162306a36Sopenharmony_ci case 0x2201 ... 0x2204: 3262306a36Sopenharmony_ci case 0x2206 ... 0x2212: 3362306a36Sopenharmony_ci case 0x2220 ... 0x2223: 3462306a36Sopenharmony_ci case 0x2230 ... 0x2239: 3562306a36Sopenharmony_ci case 0x2f01 ... 0x2f0f: 3662306a36Sopenharmony_ci case 0x3000 ... 0x3fff: 3762306a36Sopenharmony_ci case 0x7000 ... 0x7fff: 3862306a36Sopenharmony_ci case 0x8300 ... 0x83ff: 3962306a36Sopenharmony_ci case 0x9c00 ... 0x9cff: 4062306a36Sopenharmony_ci case 0xb900 ... 0xb9ff: 4162306a36Sopenharmony_ci case 0x752009: 4262306a36Sopenharmony_ci case 0x752011: 4362306a36Sopenharmony_ci case 0x75201a: 4462306a36Sopenharmony_ci case 0x752045: 4562306a36Sopenharmony_ci case 0x752046: 4662306a36Sopenharmony_ci case 0x752048: 4762306a36Sopenharmony_ci case 0x75204a: 4862306a36Sopenharmony_ci case 0x75206b: 4962306a36Sopenharmony_ci case 0x75206f: 5062306a36Sopenharmony_ci case 0x752080: 5162306a36Sopenharmony_ci case 0x752081: 5262306a36Sopenharmony_ci case 0x752091: 5362306a36Sopenharmony_ci case 0x755800: 5462306a36Sopenharmony_ci return true; 5562306a36Sopenharmony_ci default: 5662306a36Sopenharmony_ci return false; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic bool rt711_volatile_register(struct device *dev, unsigned int reg) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci switch (reg) { 6362306a36Sopenharmony_ci case 0x2016: 6462306a36Sopenharmony_ci case 0x201b: 6562306a36Sopenharmony_ci case 0x201c: 6662306a36Sopenharmony_ci case 0x201d: 6762306a36Sopenharmony_ci case 0x201f: 6862306a36Sopenharmony_ci case 0x2021: 6962306a36Sopenharmony_ci case 0x2023: 7062306a36Sopenharmony_ci case 0x2230: 7162306a36Sopenharmony_ci case 0x2012 ... 0x2015: /* HD-A read */ 7262306a36Sopenharmony_ci case 0x202d ... 0x202f: /* BRA */ 7362306a36Sopenharmony_ci case 0x2201 ... 0x2212: /* i2c debug */ 7462306a36Sopenharmony_ci case 0x2220 ... 0x2223: /* decoded HD-A */ 7562306a36Sopenharmony_ci case 0x9c00 ... 0x9cff: 7662306a36Sopenharmony_ci case 0xb900 ... 0xb9ff: 7762306a36Sopenharmony_ci case 0xff01: 7862306a36Sopenharmony_ci case 0x75201a: 7962306a36Sopenharmony_ci case 0x752046: 8062306a36Sopenharmony_ci case 0x752080: 8162306a36Sopenharmony_ci case 0x752081: 8262306a36Sopenharmony_ci case 0x755800: 8362306a36Sopenharmony_ci return true; 8462306a36Sopenharmony_ci default: 8562306a36Sopenharmony_ci return false; 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int rt711_sdw_read(void *context, unsigned int reg, unsigned int *val) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct device *dev = context; 9262306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 9362306a36Sopenharmony_ci unsigned int sdw_data_3, sdw_data_2, sdw_data_1, sdw_data_0; 9462306a36Sopenharmony_ci unsigned int reg2 = 0, reg3 = 0, reg4 = 0, mask, nid, val2; 9562306a36Sopenharmony_ci unsigned int is_hda_reg = 1, is_index_reg = 0; 9662306a36Sopenharmony_ci int ret; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci if (reg > 0xffff) 9962306a36Sopenharmony_ci is_index_reg = 1; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci mask = reg & 0xf000; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci if (is_index_reg) { /* index registers */ 10462306a36Sopenharmony_ci val2 = reg & 0xff; 10562306a36Sopenharmony_ci reg = reg >> 8; 10662306a36Sopenharmony_ci nid = reg & 0xff; 10762306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, 0); 10862306a36Sopenharmony_ci if (ret < 0) 10962306a36Sopenharmony_ci return ret; 11062306a36Sopenharmony_ci reg2 = reg + 0x1000; 11162306a36Sopenharmony_ci reg2 |= 0x80; 11262306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg2, val2); 11362306a36Sopenharmony_ci if (ret < 0) 11462306a36Sopenharmony_ci return ret; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci reg3 = RT711_PRIV_DATA_R_H | nid; 11762306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 11862306a36Sopenharmony_ci reg3, ((*val >> 8) & 0xff)); 11962306a36Sopenharmony_ci if (ret < 0) 12062306a36Sopenharmony_ci return ret; 12162306a36Sopenharmony_ci reg4 = reg3 + 0x1000; 12262306a36Sopenharmony_ci reg4 |= 0x80; 12362306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg4, (*val & 0xff)); 12462306a36Sopenharmony_ci if (ret < 0) 12562306a36Sopenharmony_ci return ret; 12662306a36Sopenharmony_ci } else if (mask == 0x3000) { 12762306a36Sopenharmony_ci reg += 0x8000; 12862306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, *val); 12962306a36Sopenharmony_ci if (ret < 0) 13062306a36Sopenharmony_ci return ret; 13162306a36Sopenharmony_ci } else if (mask == 0x7000) { 13262306a36Sopenharmony_ci reg += 0x2000; 13362306a36Sopenharmony_ci reg |= 0x800; 13462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 13562306a36Sopenharmony_ci reg, ((*val >> 8) & 0xff)); 13662306a36Sopenharmony_ci if (ret < 0) 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci reg2 = reg + 0x1000; 13962306a36Sopenharmony_ci reg2 |= 0x80; 14062306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg2, (*val & 0xff)); 14162306a36Sopenharmony_ci if (ret < 0) 14262306a36Sopenharmony_ci return ret; 14362306a36Sopenharmony_ci } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ 14462306a36Sopenharmony_ci reg2 = reg - 0x1000; 14562306a36Sopenharmony_ci reg2 &= ~0x80; 14662306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 14762306a36Sopenharmony_ci reg2, ((*val >> 8) & 0xff)); 14862306a36Sopenharmony_ci if (ret < 0) 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, (*val & 0xff)); 15162306a36Sopenharmony_ci if (ret < 0) 15262306a36Sopenharmony_ci return ret; 15362306a36Sopenharmony_ci } else if (mask == 0x9000) { 15462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 15562306a36Sopenharmony_ci reg, ((*val >> 8) & 0xff)); 15662306a36Sopenharmony_ci if (ret < 0) 15762306a36Sopenharmony_ci return ret; 15862306a36Sopenharmony_ci reg2 = reg + 0x1000; 15962306a36Sopenharmony_ci reg2 |= 0x80; 16062306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg2, (*val & 0xff)); 16162306a36Sopenharmony_ci if (ret < 0) 16262306a36Sopenharmony_ci return ret; 16362306a36Sopenharmony_ci } else if (mask == 0xb000) { 16462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, *val); 16562306a36Sopenharmony_ci if (ret < 0) 16662306a36Sopenharmony_ci return ret; 16762306a36Sopenharmony_ci } else { 16862306a36Sopenharmony_ci ret = regmap_read(rt711->sdw_regmap, reg, val); 16962306a36Sopenharmony_ci if (ret < 0) 17062306a36Sopenharmony_ci return ret; 17162306a36Sopenharmony_ci is_hda_reg = 0; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci if (is_hda_reg || is_index_reg) { 17562306a36Sopenharmony_ci sdw_data_3 = 0; 17662306a36Sopenharmony_ci sdw_data_2 = 0; 17762306a36Sopenharmony_ci sdw_data_1 = 0; 17862306a36Sopenharmony_ci sdw_data_0 = 0; 17962306a36Sopenharmony_ci ret = regmap_read(rt711->sdw_regmap, 18062306a36Sopenharmony_ci RT711_READ_HDA_3, &sdw_data_3); 18162306a36Sopenharmony_ci if (ret < 0) 18262306a36Sopenharmony_ci return ret; 18362306a36Sopenharmony_ci ret = regmap_read(rt711->sdw_regmap, 18462306a36Sopenharmony_ci RT711_READ_HDA_2, &sdw_data_2); 18562306a36Sopenharmony_ci if (ret < 0) 18662306a36Sopenharmony_ci return ret; 18762306a36Sopenharmony_ci ret = regmap_read(rt711->sdw_regmap, 18862306a36Sopenharmony_ci RT711_READ_HDA_1, &sdw_data_1); 18962306a36Sopenharmony_ci if (ret < 0) 19062306a36Sopenharmony_ci return ret; 19162306a36Sopenharmony_ci ret = regmap_read(rt711->sdw_regmap, 19262306a36Sopenharmony_ci RT711_READ_HDA_0, &sdw_data_0); 19362306a36Sopenharmony_ci if (ret < 0) 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci *val = ((sdw_data_3 & 0xff) << 24) | 19662306a36Sopenharmony_ci ((sdw_data_2 & 0xff) << 16) | 19762306a36Sopenharmony_ci ((sdw_data_1 & 0xff) << 8) | (sdw_data_0 & 0xff); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (is_hda_reg == 0) 20162306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x => %08x\n", __func__, reg, *val); 20262306a36Sopenharmony_ci else if (is_index_reg) 20362306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x %04x %04x %04x => %08x\n", 20462306a36Sopenharmony_ci __func__, reg, reg2, reg3, reg4, *val); 20562306a36Sopenharmony_ci else 20662306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x %04x => %08x\n", 20762306a36Sopenharmony_ci __func__, reg, reg2, *val); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return 0; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_cistatic int rt711_sdw_write(void *context, unsigned int reg, unsigned int val) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci struct device *dev = context; 21562306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 21662306a36Sopenharmony_ci unsigned int reg2 = 0, reg3, reg4, nid, mask, val2; 21762306a36Sopenharmony_ci unsigned int is_index_reg = 0; 21862306a36Sopenharmony_ci int ret; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci if (reg > 0xffff) 22162306a36Sopenharmony_ci is_index_reg = 1; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci mask = reg & 0xf000; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (is_index_reg) { /* index registers */ 22662306a36Sopenharmony_ci val2 = reg & 0xff; 22762306a36Sopenharmony_ci reg = reg >> 8; 22862306a36Sopenharmony_ci nid = reg & 0xff; 22962306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, 0); 23062306a36Sopenharmony_ci if (ret < 0) 23162306a36Sopenharmony_ci return ret; 23262306a36Sopenharmony_ci reg2 = reg + 0x1000; 23362306a36Sopenharmony_ci reg2 |= 0x80; 23462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg2, val2); 23562306a36Sopenharmony_ci if (ret < 0) 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci reg3 = RT711_PRIV_DATA_W_H | nid; 23962306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 24062306a36Sopenharmony_ci reg3, ((val >> 8) & 0xff)); 24162306a36Sopenharmony_ci if (ret < 0) 24262306a36Sopenharmony_ci return ret; 24362306a36Sopenharmony_ci reg4 = reg3 + 0x1000; 24462306a36Sopenharmony_ci reg4 |= 0x80; 24562306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg4, (val & 0xff)); 24662306a36Sopenharmony_ci if (ret < 0) 24762306a36Sopenharmony_ci return ret; 24862306a36Sopenharmony_ci is_index_reg = 1; 24962306a36Sopenharmony_ci } else if (reg < 0x4fff) { 25062306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, val); 25162306a36Sopenharmony_ci if (ret < 0) 25262306a36Sopenharmony_ci return ret; 25362306a36Sopenharmony_ci } else if (reg == RT711_FUNC_RESET) { 25462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, val); 25562306a36Sopenharmony_ci if (ret < 0) 25662306a36Sopenharmony_ci return ret; 25762306a36Sopenharmony_ci } else if (mask == 0x7000) { 25862306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 25962306a36Sopenharmony_ci reg, ((val >> 8) & 0xff)); 26062306a36Sopenharmony_ci if (ret < 0) 26162306a36Sopenharmony_ci return ret; 26262306a36Sopenharmony_ci reg2 = reg + 0x1000; 26362306a36Sopenharmony_ci reg2 |= 0x80; 26462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg2, (val & 0xff)); 26562306a36Sopenharmony_ci if (ret < 0) 26662306a36Sopenharmony_ci return ret; 26762306a36Sopenharmony_ci } else if ((reg & 0xff00) == 0x8300) { /* for R channel */ 26862306a36Sopenharmony_ci reg2 = reg - 0x1000; 26962306a36Sopenharmony_ci reg2 &= ~0x80; 27062306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, 27162306a36Sopenharmony_ci reg2, ((val >> 8) & 0xff)); 27262306a36Sopenharmony_ci if (ret < 0) 27362306a36Sopenharmony_ci return ret; 27462306a36Sopenharmony_ci ret = regmap_write(rt711->sdw_regmap, reg, (val & 0xff)); 27562306a36Sopenharmony_ci if (ret < 0) 27662306a36Sopenharmony_ci return ret; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (reg2 == 0) 28062306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x <= %04x\n", __func__, reg, val); 28162306a36Sopenharmony_ci else if (is_index_reg) 28262306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x %04x %04x %04x <= %04x %04x\n", 28362306a36Sopenharmony_ci __func__, reg, reg2, reg3, reg4, val2, val); 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci dev_dbg(dev, "[%s] %04x %04x <= %04x\n", 28662306a36Sopenharmony_ci __func__, reg, reg2, val); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic const struct regmap_config rt711_regmap = { 29262306a36Sopenharmony_ci .reg_bits = 24, 29362306a36Sopenharmony_ci .val_bits = 32, 29462306a36Sopenharmony_ci .readable_reg = rt711_readable_register, 29562306a36Sopenharmony_ci .volatile_reg = rt711_volatile_register, 29662306a36Sopenharmony_ci .max_register = 0x755800, 29762306a36Sopenharmony_ci .reg_defaults = rt711_reg_defaults, 29862306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(rt711_reg_defaults), 29962306a36Sopenharmony_ci .cache_type = REGCACHE_MAPLE, 30062306a36Sopenharmony_ci .use_single_read = true, 30162306a36Sopenharmony_ci .use_single_write = true, 30262306a36Sopenharmony_ci .reg_read = rt711_sdw_read, 30362306a36Sopenharmony_ci .reg_write = rt711_sdw_write, 30462306a36Sopenharmony_ci}; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic const struct regmap_config rt711_sdw_regmap = { 30762306a36Sopenharmony_ci .name = "sdw", 30862306a36Sopenharmony_ci .reg_bits = 32, 30962306a36Sopenharmony_ci .val_bits = 8, 31062306a36Sopenharmony_ci .readable_reg = rt711_readable_register, 31162306a36Sopenharmony_ci .max_register = 0xff01, 31262306a36Sopenharmony_ci .cache_type = REGCACHE_NONE, 31362306a36Sopenharmony_ci .use_single_read = true, 31462306a36Sopenharmony_ci .use_single_write = true, 31562306a36Sopenharmony_ci}; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic int rt711_update_status(struct sdw_slave *slave, 31862306a36Sopenharmony_ci enum sdw_slave_status status) 31962306a36Sopenharmony_ci{ 32062306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci if (status == SDW_SLAVE_UNATTACHED) 32362306a36Sopenharmony_ci rt711->hw_init = false; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci /* 32662306a36Sopenharmony_ci * Perform initialization only if slave status is present and 32762306a36Sopenharmony_ci * hw_init flag is false 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci if (rt711->hw_init || status != SDW_SLAVE_ATTACHED) 33062306a36Sopenharmony_ci return 0; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* perform I/O transfers required for Slave initialization */ 33362306a36Sopenharmony_ci return rt711_io_init(&slave->dev, slave); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic int rt711_read_prop(struct sdw_slave *slave) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct sdw_slave_prop *prop = &slave->prop; 33962306a36Sopenharmony_ci int nval; 34062306a36Sopenharmony_ci int i, j; 34162306a36Sopenharmony_ci u32 bit; 34262306a36Sopenharmony_ci unsigned long addr; 34362306a36Sopenharmony_ci struct sdw_dpn_prop *dpn; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci prop->scp_int1_mask = SDW_SCP_INT1_IMPL_DEF | SDW_SCP_INT1_BUS_CLASH | 34662306a36Sopenharmony_ci SDW_SCP_INT1_PARITY; 34762306a36Sopenharmony_ci prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci prop->paging_support = false; 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* first we need to allocate memory for set bits in port lists */ 35262306a36Sopenharmony_ci prop->source_ports = 0x14; /* BITMAP: 00010100 */ 35362306a36Sopenharmony_ci prop->sink_ports = 0x8; /* BITMAP: 00001000 */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci nval = hweight32(prop->source_ports); 35662306a36Sopenharmony_ci prop->src_dpn_prop = devm_kcalloc(&slave->dev, nval, 35762306a36Sopenharmony_ci sizeof(*prop->src_dpn_prop), 35862306a36Sopenharmony_ci GFP_KERNEL); 35962306a36Sopenharmony_ci if (!prop->src_dpn_prop) 36062306a36Sopenharmony_ci return -ENOMEM; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci i = 0; 36362306a36Sopenharmony_ci dpn = prop->src_dpn_prop; 36462306a36Sopenharmony_ci addr = prop->source_ports; 36562306a36Sopenharmony_ci for_each_set_bit(bit, &addr, 32) { 36662306a36Sopenharmony_ci dpn[i].num = bit; 36762306a36Sopenharmony_ci dpn[i].type = SDW_DPN_FULL; 36862306a36Sopenharmony_ci dpn[i].simple_ch_prep_sm = true; 36962306a36Sopenharmony_ci dpn[i].ch_prep_timeout = 10; 37062306a36Sopenharmony_ci i++; 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci /* do this again for sink now */ 37462306a36Sopenharmony_ci nval = hweight32(prop->sink_ports); 37562306a36Sopenharmony_ci prop->sink_dpn_prop = devm_kcalloc(&slave->dev, nval, 37662306a36Sopenharmony_ci sizeof(*prop->sink_dpn_prop), 37762306a36Sopenharmony_ci GFP_KERNEL); 37862306a36Sopenharmony_ci if (!prop->sink_dpn_prop) 37962306a36Sopenharmony_ci return -ENOMEM; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci j = 0; 38262306a36Sopenharmony_ci dpn = prop->sink_dpn_prop; 38362306a36Sopenharmony_ci addr = prop->sink_ports; 38462306a36Sopenharmony_ci for_each_set_bit(bit, &addr, 32) { 38562306a36Sopenharmony_ci dpn[j].num = bit; 38662306a36Sopenharmony_ci dpn[j].type = SDW_DPN_FULL; 38762306a36Sopenharmony_ci dpn[j].simple_ch_prep_sm = true; 38862306a36Sopenharmony_ci dpn[j].ch_prep_timeout = 10; 38962306a36Sopenharmony_ci j++; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* set the timeout values */ 39362306a36Sopenharmony_ci prop->clk_stop_timeout = 20; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* wake-up event */ 39662306a36Sopenharmony_ci prop->wake_capable = 1; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return 0; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic int rt711_bus_config(struct sdw_slave *slave, 40262306a36Sopenharmony_ci struct sdw_bus_params *params) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); 40562306a36Sopenharmony_ci int ret; 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci memcpy(&rt711->params, params, sizeof(*params)); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci ret = rt711_clock_config(&slave->dev); 41062306a36Sopenharmony_ci if (ret < 0) 41162306a36Sopenharmony_ci dev_err(&slave->dev, "Invalid clk config"); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return ret; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int rt711_interrupt_callback(struct sdw_slave *slave, 41762306a36Sopenharmony_ci struct sdw_slave_intr_status *status) 41862306a36Sopenharmony_ci{ 41962306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci dev_dbg(&slave->dev, 42262306a36Sopenharmony_ci "%s control_port_stat=%x", __func__, status->control_port); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci mutex_lock(&rt711->disable_irq_lock); 42562306a36Sopenharmony_ci if (status->control_port & 0x4 && !rt711->disable_irq) { 42662306a36Sopenharmony_ci mod_delayed_work(system_power_efficient_wq, 42762306a36Sopenharmony_ci &rt711->jack_detect_work, msecs_to_jiffies(250)); 42862306a36Sopenharmony_ci } 42962306a36Sopenharmony_ci mutex_unlock(&rt711->disable_irq_lock); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic const struct sdw_slave_ops rt711_slave_ops = { 43562306a36Sopenharmony_ci .read_prop = rt711_read_prop, 43662306a36Sopenharmony_ci .interrupt_callback = rt711_interrupt_callback, 43762306a36Sopenharmony_ci .update_status = rt711_update_status, 43862306a36Sopenharmony_ci .bus_config = rt711_bus_config, 43962306a36Sopenharmony_ci}; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic int rt711_sdw_probe(struct sdw_slave *slave, 44262306a36Sopenharmony_ci const struct sdw_device_id *id) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct regmap *sdw_regmap, *regmap; 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* Regmap Initialization */ 44762306a36Sopenharmony_ci sdw_regmap = devm_regmap_init_sdw(slave, &rt711_sdw_regmap); 44862306a36Sopenharmony_ci if (IS_ERR(sdw_regmap)) 44962306a36Sopenharmony_ci return PTR_ERR(sdw_regmap); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci regmap = devm_regmap_init(&slave->dev, NULL, 45262306a36Sopenharmony_ci &slave->dev, &rt711_regmap); 45362306a36Sopenharmony_ci if (IS_ERR(regmap)) 45462306a36Sopenharmony_ci return PTR_ERR(regmap); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return rt711_init(&slave->dev, sdw_regmap, regmap, slave); 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic int rt711_sdw_remove(struct sdw_slave *slave) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(&slave->dev); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (rt711->hw_init) { 46462306a36Sopenharmony_ci cancel_delayed_work_sync(&rt711->jack_detect_work); 46562306a36Sopenharmony_ci cancel_delayed_work_sync(&rt711->jack_btn_check_work); 46662306a36Sopenharmony_ci cancel_work_sync(&rt711->calibration_work); 46762306a36Sopenharmony_ci } 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci pm_runtime_disable(&slave->dev); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci mutex_destroy(&rt711->calibrate_mutex); 47262306a36Sopenharmony_ci mutex_destroy(&rt711->disable_irq_lock); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic const struct sdw_device_id rt711_id[] = { 47862306a36Sopenharmony_ci SDW_SLAVE_ENTRY_EXT(0x025d, 0x711, 0x2, 0, 0), 47962306a36Sopenharmony_ci {}, 48062306a36Sopenharmony_ci}; 48162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(sdw, rt711_id); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic int __maybe_unused rt711_dev_suspend(struct device *dev) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci if (!rt711->hw_init) 48862306a36Sopenharmony_ci return 0; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci cancel_delayed_work_sync(&rt711->jack_detect_work); 49162306a36Sopenharmony_ci cancel_delayed_work_sync(&rt711->jack_btn_check_work); 49262306a36Sopenharmony_ci cancel_work_sync(&rt711->calibration_work); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci regcache_cache_only(rt711->regmap, true); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci return 0; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic int __maybe_unused rt711_dev_system_suspend(struct device *dev) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 50262306a36Sopenharmony_ci struct sdw_slave *slave = dev_to_sdw_dev(dev); 50362306a36Sopenharmony_ci int ret; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci if (!rt711->hw_init) 50662306a36Sopenharmony_ci return 0; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci /* 50962306a36Sopenharmony_ci * prevent new interrupts from being handled after the 51062306a36Sopenharmony_ci * deferred work completes and before the parent disables 51162306a36Sopenharmony_ci * interrupts on the link 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci mutex_lock(&rt711->disable_irq_lock); 51462306a36Sopenharmony_ci rt711->disable_irq = true; 51562306a36Sopenharmony_ci ret = sdw_update_no_pm(slave, SDW_SCP_INTMASK1, 51662306a36Sopenharmony_ci SDW_SCP_INT1_IMPL_DEF, 0); 51762306a36Sopenharmony_ci mutex_unlock(&rt711->disable_irq_lock); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (ret < 0) { 52062306a36Sopenharmony_ci /* log but don't prevent suspend from happening */ 52162306a36Sopenharmony_ci dev_dbg(&slave->dev, "%s: could not disable imp-def interrupts\n:", __func__); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci return rt711_dev_suspend(dev); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci#define RT711_PROBE_TIMEOUT 5000 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_cistatic int __maybe_unused rt711_dev_resume(struct device *dev) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci struct sdw_slave *slave = dev_to_sdw_dev(dev); 53262306a36Sopenharmony_ci struct rt711_priv *rt711 = dev_get_drvdata(dev); 53362306a36Sopenharmony_ci unsigned long time; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci if (!rt711->first_hw_init) 53662306a36Sopenharmony_ci return 0; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci if (!slave->unattach_request) { 53962306a36Sopenharmony_ci if (rt711->disable_irq == true) { 54062306a36Sopenharmony_ci mutex_lock(&rt711->disable_irq_lock); 54162306a36Sopenharmony_ci sdw_write_no_pm(slave, SDW_SCP_INTMASK1, SDW_SCP_INT1_IMPL_DEF); 54262306a36Sopenharmony_ci rt711->disable_irq = false; 54362306a36Sopenharmony_ci mutex_unlock(&rt711->disable_irq_lock); 54462306a36Sopenharmony_ci } 54562306a36Sopenharmony_ci goto regmap_sync; 54662306a36Sopenharmony_ci } 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci time = wait_for_completion_timeout(&slave->initialization_complete, 54962306a36Sopenharmony_ci msecs_to_jiffies(RT711_PROBE_TIMEOUT)); 55062306a36Sopenharmony_ci if (!time) { 55162306a36Sopenharmony_ci dev_err(&slave->dev, "Initialization not complete, timed out\n"); 55262306a36Sopenharmony_ci return -ETIMEDOUT; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ciregmap_sync: 55662306a36Sopenharmony_ci slave->unattach_request = 0; 55762306a36Sopenharmony_ci regcache_cache_only(rt711->regmap, false); 55862306a36Sopenharmony_ci regcache_sync_region(rt711->regmap, 0x3000, 0x8fff); 55962306a36Sopenharmony_ci regcache_sync_region(rt711->regmap, 0x752009, 0x752091); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_cistatic const struct dev_pm_ops rt711_pm = { 56562306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(rt711_dev_system_suspend, rt711_dev_resume) 56662306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(rt711_dev_suspend, rt711_dev_resume, NULL) 56762306a36Sopenharmony_ci}; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic struct sdw_driver rt711_sdw_driver = { 57062306a36Sopenharmony_ci .driver = { 57162306a36Sopenharmony_ci .name = "rt711", 57262306a36Sopenharmony_ci .owner = THIS_MODULE, 57362306a36Sopenharmony_ci .pm = &rt711_pm, 57462306a36Sopenharmony_ci }, 57562306a36Sopenharmony_ci .probe = rt711_sdw_probe, 57662306a36Sopenharmony_ci .remove = rt711_sdw_remove, 57762306a36Sopenharmony_ci .ops = &rt711_slave_ops, 57862306a36Sopenharmony_ci .id_table = rt711_id, 57962306a36Sopenharmony_ci}; 58062306a36Sopenharmony_cimodule_sdw_driver(rt711_sdw_driver); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ciMODULE_DESCRIPTION("ASoC RT711 SDW driver"); 58362306a36Sopenharmony_ciMODULE_AUTHOR("Shuming Fan <shumingf@realtek.com>"); 58462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 585