1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2025 Cirrus Logic, Inc. and 3 // Cirrus Logic International Semiconductor Ltd. 4 5 /* 6 * The MIPI SDCA specification is available for public downloads at 7 * https://www.mipi.org/mipi-sdca-v1-0-download 8 */ 9 10 #include <linux/device.h> 11 #include <linux/err.h> 12 #include <linux/module.h> 13 #include <linux/pm.h> 14 #include <linux/pm_runtime.h> 15 #include <linux/regmap.h> 16 #include <linux/soundwire/sdw.h> 17 #include <linux/soundwire/sdw_registers.h> 18 #include <linux/soundwire/sdw_type.h> 19 #include <sound/sdca.h> 20 #include <sound/sdca_function.h> 21 #include <sound/sdca_interrupts.h> 22 #include <sound/sdca_regmap.h> 23 #include <sound/sdca_class.h> 24 25 #define CLASS_SDW_ATTACH_TIMEOUT_MS 5000 26 27 static int class_read_prop(struct sdw_slave *sdw) 28 { 29 struct sdw_slave_prop *prop = &sdw->prop; 30 int ret; 31 32 ret = sdw_slave_read_prop(sdw); 33 if (ret) 34 return ret; 35 36 prop->use_domain_irq = true; 37 prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | 38 SDW_SCP_INT1_IMPL_DEF; 39 40 return 0; 41 } 42 43 static const struct sdw_slave_ops class_sdw_ops = { 44 .read_prop = class_read_prop, 45 }; 46 47 static void class_regmap_lock(void *data) 48 { 49 struct mutex *lock = data; 50 51 mutex_lock(lock); 52 } 53 54 static void class_regmap_unlock(void *data) 55 { 56 struct mutex *lock = data; 57 58 mutex_unlock(lock); 59 } 60 61 static bool class_dev_regmap_volatile(struct device *dev, unsigned int reg) 62 { 63 switch (reg) { 64 case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4: 65 return false; 66 default: 67 return true; 68 } 69 } 70 71 static bool class_dev_regmap_precious(struct device *dev, unsigned int reg) 72 { 73 switch (reg) { 74 case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INT4: 75 case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4: 76 return false; 77 default: 78 return true; 79 } 80 } 81 82 static const struct regmap_config class_dev_regmap_config = { 83 .name = "sdca-device", 84 .reg_bits = 32, 85 .val_bits = 8, 86 87 .max_register = SDW_SDCA_MAX_REGISTER, 88 .volatile_reg = class_dev_regmap_volatile, 89 .precious_reg = class_dev_regmap_precious, 90 91 .cache_type = REGCACHE_MAPLE, 92 93 .lock = class_regmap_lock, 94 .unlock = class_regmap_unlock, 95 }; 96 97 static void class_remove_functions(void *data) 98 { 99 struct sdca_class_drv *drv = data; 100 101 sdca_dev_unregister_functions(drv->sdw); 102 } 103 104 static void class_boot_work(struct work_struct *work) 105 { 106 struct sdca_class_drv *drv = container_of(work, 107 struct sdca_class_drv, 108 boot_work); 109 int ret; 110 111 ret = sdw_slave_wait_for_init(drv->sdw, CLASS_SDW_ATTACH_TIMEOUT_MS); 112 if (ret) 113 goto err; 114 115 regcache_cache_only(drv->dev_regmap, false); 116 117 drv->irq_info = devm_sdca_irq_allocate(drv->dev, drv->dev_regmap, 118 drv->sdw->irq); 119 if (IS_ERR(drv->irq_info)) 120 goto err; 121 122 ret = sdca_dev_register_functions(drv->sdw); 123 if (ret) 124 goto err; 125 126 /* Ensure function drivers are removed before the IRQ is destroyed */ 127 ret = devm_add_action_or_reset(drv->dev, class_remove_functions, drv); 128 if (ret) 129 goto err; 130 131 dev_dbg(drv->dev, "boot work complete\n"); 132 133 pm_runtime_mark_last_busy(drv->dev); 134 pm_runtime_put_autosuspend(drv->dev); 135 136 return; 137 138 err: 139 pm_runtime_put_sync(drv->dev); 140 } 141 142 /** 143 * sdca_class_probe - SDCA class SoundWire slave probe helper 144 * @sdw: SoundWire slave 145 * @drv: caller-allocated sdca_class_drv storage. The caller (a codec 146 * driver, or the built-in class_sdw_driver in this file) owns the 147 * allocation and sets its own dev_set_drvdata() -- the framework 148 * does not touch drvdata. Typically embedded in the codec's own 149 * priv struct so codec drivers can keep per-slave state. 150 * @ops: optional codec-provided class callbacks (may be NULL for 151 * pure-generic SDCA parts that need no quirks) 152 * 153 * Codec-specific SoundWire drivers call this from their .probe after 154 * allocating a struct sdca_class_drv (usually embedded in their own 155 * priv) and setting drvdata to their priv. The framework fills in the 156 * sdca_class_drv fields, sets up the class regmap, and queues the 157 * deferred boot work. 158 */ 159 int sdca_class_probe(struct sdw_slave *sdw, 160 struct sdca_class_drv *drv, 161 const struct sdca_class_ops *ops) 162 { 163 struct device *dev = &sdw->dev; 164 struct regmap_config *dev_config; 165 int ret; 166 167 sdca_lookup_swft(sdw); 168 169 if (!drv) 170 return -EINVAL; 171 172 dev_config = devm_kmemdup(dev, &class_dev_regmap_config, 173 sizeof(*dev_config), GFP_KERNEL); 174 if (!dev_config) 175 return -ENOMEM; 176 177 drv->dev = dev; 178 drv->sdw = sdw; 179 drv->ops = ops; 180 mutex_init(&drv->regmap_lock); 181 mutex_init(&drv->init_lock); 182 183 INIT_WORK(&drv->boot_work, class_boot_work); 184 185 dev_config->lock_arg = &drv->regmap_lock; 186 187 drv->dev_regmap = devm_regmap_init_sdw(sdw, dev_config); 188 if (IS_ERR(drv->dev_regmap)) 189 return dev_err_probe(drv->dev, PTR_ERR(drv->dev_regmap), 190 "failed to create device regmap\n"); 191 192 regcache_cache_only(drv->dev_regmap, true); 193 194 pm_runtime_set_autosuspend_delay(dev, 250); 195 pm_runtime_use_autosuspend(dev); 196 pm_runtime_set_active(dev); 197 pm_runtime_get_noresume(dev); 198 199 ret = devm_pm_runtime_enable(dev); 200 if (ret) { 201 pm_runtime_put_sync(dev); 202 return ret; 203 } 204 205 queue_work(system_long_wq, &drv->boot_work); 206 207 return 0; 208 } 209 EXPORT_SYMBOL_NS_GPL(sdca_class_probe, "SND_SOC_SDCA_CLASS"); 210 211 static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) 212 { 213 struct sdca_class_drv *drv; 214 215 /* 216 * Pure-generic SDCA parts: no codec priv to embed, so allocate a 217 * bare sdca_class_drv here and stash it in drvdata for the 218 * built-in PM ops to fetch. 219 */ 220 drv = devm_kzalloc(&sdw->dev, sizeof(*drv), GFP_KERNEL); 221 if (!drv) 222 return -ENOMEM; 223 224 dev_set_drvdata(&sdw->dev, drv); 225 226 return sdca_class_probe(sdw, drv, NULL); 227 } 228 229 /** 230 * sdca_class_remove - SDCA class SoundWire slave remove helper 231 * @drv: caller-owned sdca_class_drv (the one handed to sdca_class_probe()). 232 * 233 * Cancels the deferred boot work so devres can safely free @drv and the 234 * embedding codec priv without racing class_boot_work. Codec-specific 235 * SoundWire drivers that call sdca_class_probe() must call this from 236 * their .remove with the same drv pointer they passed to probe. 237 */ 238 void sdca_class_remove(struct sdca_class_drv *drv) 239 { 240 cancel_work_sync(&drv->boot_work); 241 } 242 EXPORT_SYMBOL_NS_GPL(sdca_class_remove, "SND_SOC_SDCA_CLASS"); 243 244 static void class_sdw_remove(struct sdw_slave *sdw) 245 { 246 struct sdca_class_drv *drv = dev_get_drvdata(&sdw->dev); 247 248 sdca_class_remove(drv); 249 } 250 251 /** 252 * sdca_class_system_suspend - SDCA class system suspend helper 253 * @drv: caller-owned sdca_class_drv. 254 * 255 * Codec drivers compose this into their own dev_pm_ops. Disables the 256 * SoundWire interrupt and forces runtime suspend of the underlying 257 * class regmap. 258 */ 259 int sdca_class_system_suspend(struct sdca_class_drv *drv) 260 { 261 int ret; 262 263 disable_irq(drv->sdw->irq); 264 265 ret = pm_runtime_force_suspend(drv->dev); 266 if (ret) { 267 dev_err(drv->dev, "failed to force suspend: %d\n", ret); 268 enable_irq(drv->sdw->irq); 269 return ret; 270 } 271 272 return 0; 273 } 274 EXPORT_SYMBOL_NS_GPL(sdca_class_system_suspend, "SND_SOC_SDCA_CLASS"); 275 276 /** 277 * sdca_class_system_resume - SDCA class system resume helper 278 * @drv: caller-owned sdca_class_drv. 279 */ 280 int sdca_class_system_resume(struct sdca_class_drv *drv) 281 { 282 int ret; 283 284 ret = pm_runtime_force_resume(drv->dev); 285 if (ret) { 286 dev_err(drv->dev, "failed to force resume: %d\n", ret); 287 return ret; 288 } 289 290 enable_irq(drv->sdw->irq); 291 292 return 0; 293 } 294 EXPORT_SYMBOL_NS_GPL(sdca_class_system_resume, "SND_SOC_SDCA_CLASS"); 295 296 /** 297 * sdca_class_runtime_suspend - SDCA class runtime suspend helper 298 * @drv: caller-owned sdca_class_drv. 299 */ 300 int sdca_class_runtime_suspend(struct sdca_class_drv *drv) 301 { 302 /* 303 * Whilst the driver doesn't power the chip down here, going into runtime 304 * suspend lets the SoundWire bus power down, which means the driver 305 * can't communicate with the device any more. 306 */ 307 regcache_cache_only(drv->dev_regmap, true); 308 309 return 0; 310 } 311 EXPORT_SYMBOL_NS_GPL(sdca_class_runtime_suspend, "SND_SOC_SDCA_CLASS"); 312 313 /** 314 * sdca_class_runtime_resume - SDCA class runtime resume helper 315 * @drv: caller-owned sdca_class_drv. 316 */ 317 int sdca_class_runtime_resume(struct sdca_class_drv *drv) 318 { 319 int ret; 320 321 ret = sdw_slave_wait_for_init(drv->sdw, CLASS_SDW_ATTACH_TIMEOUT_MS); 322 if (ret) 323 goto err; 324 325 regcache_cache_only(drv->dev_regmap, false); 326 regcache_mark_dirty(drv->dev_regmap); 327 328 ret = regcache_sync(drv->dev_regmap); 329 if (ret) { 330 dev_err(drv->dev, "failed to restore cache: %d\n", ret); 331 goto err; 332 } 333 334 return 0; 335 336 err: 337 regcache_cache_only(drv->dev_regmap, true); 338 339 return ret; 340 } 341 EXPORT_SYMBOL_NS_GPL(sdca_class_runtime_resume, "SND_SOC_SDCA_CLASS"); 342 343 /* 344 * Convenience dev_pm_ops used by the built-in class_sdw_driver, which 345 * stashes its sdca_class_drv in drvdata directly. Codec drivers that 346 * embed sdca_class_drv in their own priv compose their own dev_pm_ops 347 * using the sdca_class_*_suspend/resume helpers above. 348 */ 349 static int class_pm_system_suspend(struct device *dev) 350 { 351 return sdca_class_system_suspend(dev_get_drvdata(dev)); 352 } 353 354 static int class_pm_system_resume(struct device *dev) 355 { 356 return sdca_class_system_resume(dev_get_drvdata(dev)); 357 } 358 359 static int class_pm_runtime_suspend(struct device *dev) 360 { 361 return sdca_class_runtime_suspend(dev_get_drvdata(dev)); 362 } 363 364 static int class_pm_runtime_resume(struct device *dev) 365 { 366 return sdca_class_runtime_resume(dev_get_drvdata(dev)); 367 } 368 369 static const struct dev_pm_ops sdca_class_pm_ops = { 370 SYSTEM_SLEEP_PM_OPS(class_pm_system_suspend, class_pm_system_resume) 371 RUNTIME_PM_OPS(class_pm_runtime_suspend, class_pm_runtime_resume, NULL) 372 }; 373 374 static const struct sdw_device_id class_sdw_id[] = { 375 SDW_SLAVE_ENTRY(0x01FA, 0x4245, 0), 376 SDW_SLAVE_ENTRY(0x01FA, 0x4249, 0), 377 SDW_SLAVE_ENTRY(0x01FA, 0x4747, 0), 378 {} 379 }; 380 MODULE_DEVICE_TABLE(sdw, class_sdw_id); 381 382 static struct sdw_driver class_sdw_driver = { 383 .driver = { 384 .name = "sdca_class", 385 .pm = pm_ptr(&sdca_class_pm_ops), 386 }, 387 388 .probe = class_sdw_probe, 389 .remove = class_sdw_remove, 390 .id_table = class_sdw_id, 391 .ops = &class_sdw_ops, 392 }; 393 module_sdw_driver(class_sdw_driver); 394 395 MODULE_LICENSE("GPL"); 396 MODULE_DESCRIPTION("SDCA Class Driver"); 397 MODULE_IMPORT_NS("SND_SOC_SDCA"); 398