1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * CS42L43 SoundWire driver 4 * 5 * Copyright (C) 2022-2023 Cirrus Logic, Inc. and 6 * Cirrus Logic International Semiconductor Ltd. 7 */ 8 9 #include <linux/err.h> 10 #include <linux/errno.h> 11 #include <linux/mfd/cs42l43-regs.h> 12 #include <linux/module.h> 13 #include <linux/device.h> 14 #include <linux/soundwire/sdw.h> 15 #include <linux/soundwire/sdw_registers.h> 16 #include <linux/soundwire/sdw_type.h> 17 18 #include "cs42l43.h" 19 20 enum cs42l43_sdw_ports { 21 CS42L43_DMIC_DEC_ASP_PORT = 1, 22 CS42L43_SPK_TX_PORT, 23 CS42L43_SPDIF_HP_PORT, 24 CS42L43_SPK_RX_PORT, 25 CS42L43_ASP_PORT, 26 }; 27 28 static const struct regmap_config cs42l43_sdw_regmap = { 29 .reg_bits = 32, 30 .reg_stride = 4, 31 .val_bits = 32, 32 .reg_format_endian = REGMAP_ENDIAN_LITTLE, 33 .val_format_endian = REGMAP_ENDIAN_LITTLE, 34 35 .max_register = CS42L43_MCU_RAM_MAX, 36 .readable_reg = cs42l43_readable_register, 37 .volatile_reg = cs42l43_volatile_register, 38 .precious_reg = cs42l43_precious_register, 39 40 .cache_type = REGCACHE_MAPLE, 41 .reg_defaults = cs42l43_reg_default, 42 .num_reg_defaults = ARRAY_SIZE(cs42l43_reg_default), 43 }; 44 45 static int cs42l43_read_prop(struct sdw_slave *sdw) 46 { 47 struct sdw_slave_prop *prop = &sdw->prop; 48 struct device *dev = &sdw->dev; 49 struct sdw_dpn_prop *dpn; 50 unsigned long addr; 51 int nval; 52 int i; 53 u32 bit; 54 55 prop->use_domain_irq = true; 56 prop->paging_support = true; 57 prop->wake_capable = true; 58 prop->source_ports = BIT(CS42L43_DMIC_DEC_ASP_PORT) | BIT(CS42L43_SPK_TX_PORT); 59 prop->sink_ports = BIT(CS42L43_SPDIF_HP_PORT) | 60 BIT(CS42L43_SPK_RX_PORT) | BIT(CS42L43_ASP_PORT); 61 prop->quirks = SDW_SLAVE_QUIRKS_INVALID_INITIAL_PARITY; 62 prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | 63 SDW_SCP_INT1_IMPL_DEF; 64 65 nval = hweight32(prop->source_ports); 66 prop->src_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->src_dpn_prop), 67 GFP_KERNEL); 68 if (!prop->src_dpn_prop) 69 return -ENOMEM; 70 71 i = 0; 72 dpn = prop->src_dpn_prop; 73 addr = prop->source_ports; 74 for_each_set_bit(bit, &addr, 32) { 75 dpn[i].num = bit; 76 dpn[i].max_ch = 2; 77 dpn[i].type = SDW_DPN_FULL; 78 dpn[i].max_word = 24; 79 i++; 80 } 81 /* 82 * All ports are 2 channels max, except the first one, 83 * CS42L43_DMIC_DEC_ASP_PORT. 84 */ 85 dpn[CS42L43_DMIC_DEC_ASP_PORT].max_ch = 4; 86 87 nval = hweight32(prop->sink_ports); 88 prop->sink_dpn_prop = devm_kcalloc(dev, nval, sizeof(*prop->sink_dpn_prop), 89 GFP_KERNEL); 90 if (!prop->sink_dpn_prop) 91 return -ENOMEM; 92 93 i = 0; 94 dpn = prop->sink_dpn_prop; 95 addr = prop->sink_ports; 96 for_each_set_bit(bit, &addr, 32) { 97 dpn[i].num = bit; 98 dpn[i].max_ch = 2; 99 dpn[i].type = SDW_DPN_FULL; 100 dpn[i].max_word = 24; 101 i++; 102 } 103 104 return 0; 105 } 106 107 static int cs42l43_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status) 108 { 109 struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); 110 111 switch (status) { 112 case SDW_SLAVE_ATTACHED: 113 dev_dbg(cs42l43->dev, "Device attach\n"); 114 115 sdw_write_no_pm(sdw, CS42L43_GEN_INT_MASK_1, 116 CS42L43_INT_STAT_GEN1_MASK); 117 118 cs42l43->attached = true; 119 120 complete(&cs42l43->device_attach); 121 break; 122 case SDW_SLAVE_UNATTACHED: 123 dev_dbg(cs42l43->dev, "Device detach\n"); 124 125 cs42l43->attached = false; 126 127 reinit_completion(&cs42l43->device_attach); 128 complete(&cs42l43->device_detach); 129 break; 130 default: 131 break; 132 } 133 134 return 0; 135 } 136 137 static int cs42l43_sdw_interrupt(struct sdw_slave *sdw, 138 struct sdw_slave_intr_status *status) 139 { 140 /* 141 * The IRQ itself was handled through the regmap_irq handler, this is 142 * just clearing up the additional Cirrus SoundWire registers that are 143 * not covered by the SoundWire framework or the IRQ handler itself. 144 * There is only a single bit in GEN_INT_STAT_1 and it doesn't clear if 145 * IRQs are still pending so doing a read/write here after handling the 146 * IRQ is fine. 147 */ 148 sdw_read_no_pm(sdw, CS42L43_GEN_INT_STAT_1); 149 sdw_write_no_pm(sdw, CS42L43_GEN_INT_STAT_1, CS42L43_INT_STAT_GEN1_MASK); 150 151 return 0; 152 } 153 154 static int cs42l43_sdw_bus_config(struct sdw_slave *sdw, 155 struct sdw_bus_params *params) 156 { 157 struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); 158 int ret = 0; 159 160 mutex_lock(&cs42l43->pll_lock); 161 162 if (cs42l43->sdw_freq != params->curr_dr_freq / 2) { 163 if (cs42l43->sdw_pll_active) { 164 dev_err(cs42l43->dev, 165 "PLL active can't change SoundWire bus clock\n"); 166 ret = -EBUSY; 167 } else { 168 cs42l43->sdw_freq = params->curr_dr_freq / 2; 169 } 170 } 171 172 mutex_unlock(&cs42l43->pll_lock); 173 174 return ret; 175 } 176 177 static const struct sdw_slave_ops cs42l43_sdw_ops = { 178 .read_prop = cs42l43_read_prop, 179 .update_status = cs42l43_sdw_update_status, 180 .interrupt_callback = cs42l43_sdw_interrupt, 181 .bus_config = cs42l43_sdw_bus_config, 182 }; 183 184 static int cs42l43_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) 185 { 186 struct cs42l43 *cs42l43; 187 struct device *dev = &sdw->dev; 188 int ret; 189 190 cs42l43 = devm_kzalloc(dev, sizeof(*cs42l43), GFP_KERNEL); 191 if (!cs42l43) 192 return -ENOMEM; 193 194 cs42l43->dev = dev; 195 cs42l43->sdw = sdw; 196 197 cs42l43->regmap = devm_regmap_init_sdw(sdw, &cs42l43_sdw_regmap); 198 if (IS_ERR(cs42l43->regmap)) { 199 ret = PTR_ERR(cs42l43->regmap); 200 dev_err(cs42l43->dev, "Failed to allocate regmap: %d\n", ret); 201 return ret; 202 } 203 204 return cs42l43_dev_probe(cs42l43); 205 } 206 207 static int cs42l43_sdw_remove(struct sdw_slave *sdw) 208 { 209 struct cs42l43 *cs42l43 = dev_get_drvdata(&sdw->dev); 210 211 cs42l43_dev_remove(cs42l43); 212 213 return 0; 214 } 215 216 static const struct sdw_device_id cs42l43_sdw_id[] = { 217 SDW_SLAVE_ENTRY(0x01FA, 0x4243, 0), 218 {} 219 }; 220 MODULE_DEVICE_TABLE(sdw, cs42l43_sdw_id); 221 222 static struct sdw_driver cs42l43_sdw_driver = { 223 .driver = { 224 .name = "cs42l43", 225 .pm = pm_ptr(&cs42l43_pm_ops), 226 }, 227 228 .probe = cs42l43_sdw_probe, 229 .remove = cs42l43_sdw_remove, 230 .id_table = cs42l43_sdw_id, 231 .ops = &cs42l43_sdw_ops, 232 }; 233 module_sdw_driver(cs42l43_sdw_driver); 234 235 MODULE_IMPORT_NS(MFD_CS42L43); 236 237 MODULE_DESCRIPTION("CS42L43 SoundWire Driver"); 238 MODULE_AUTHOR("Lucas Tanure <tanureal@opensource.cirrus.com>"); 239 MODULE_LICENSE("GPL"); 240