1*2d877d06SCharles Keepax // SPDX-License-Identifier: GPL-2.0 2*2d877d06SCharles Keepax // Copyright (C) 2025 Cirrus Logic, Inc. and 3*2d877d06SCharles Keepax // Cirrus Logic International Semiconductor Ltd. 4*2d877d06SCharles Keepax 5*2d877d06SCharles Keepax /* 6*2d877d06SCharles Keepax * The MIPI SDCA specification is available for public downloads at 7*2d877d06SCharles Keepax * https://www.mipi.org/mipi-sdca-v1-0-download 8*2d877d06SCharles Keepax */ 9*2d877d06SCharles Keepax 10*2d877d06SCharles Keepax #include <linux/device.h> 11*2d877d06SCharles Keepax #include <linux/err.h> 12*2d877d06SCharles Keepax #include <linux/mod_devicetable.h> 13*2d877d06SCharles Keepax #include <linux/module.h> 14*2d877d06SCharles Keepax #include <linux/pm.h> 15*2d877d06SCharles Keepax #include <linux/pm_runtime.h> 16*2d877d06SCharles Keepax #include <linux/regmap.h> 17*2d877d06SCharles Keepax #include <linux/soundwire/sdw.h> 18*2d877d06SCharles Keepax #include <linux/soundwire/sdw_registers.h> 19*2d877d06SCharles Keepax #include <linux/soundwire/sdw_type.h> 20*2d877d06SCharles Keepax #include <sound/sdca.h> 21*2d877d06SCharles Keepax #include <sound/sdca_function.h> 22*2d877d06SCharles Keepax #include <sound/sdca_interrupts.h> 23*2d877d06SCharles Keepax #include <sound/sdca_regmap.h> 24*2d877d06SCharles Keepax #include "sdca_class.h" 25*2d877d06SCharles Keepax 26*2d877d06SCharles Keepax #define CLASS_SDW_ATTACH_TIMEOUT_MS 5000 27*2d877d06SCharles Keepax 28*2d877d06SCharles Keepax static int class_read_prop(struct sdw_slave *sdw) 29*2d877d06SCharles Keepax { 30*2d877d06SCharles Keepax struct sdw_slave_prop *prop = &sdw->prop; 31*2d877d06SCharles Keepax 32*2d877d06SCharles Keepax sdw_slave_read_prop(sdw); 33*2d877d06SCharles Keepax 34*2d877d06SCharles Keepax prop->use_domain_irq = true; 35*2d877d06SCharles Keepax prop->scp_int1_mask = SDW_SCP_INT1_BUS_CLASH | SDW_SCP_INT1_PARITY | 36*2d877d06SCharles Keepax SDW_SCP_INT1_IMPL_DEF; 37*2d877d06SCharles Keepax 38*2d877d06SCharles Keepax return 0; 39*2d877d06SCharles Keepax } 40*2d877d06SCharles Keepax 41*2d877d06SCharles Keepax static int class_sdw_update_status(struct sdw_slave *sdw, enum sdw_slave_status status) 42*2d877d06SCharles Keepax { 43*2d877d06SCharles Keepax struct sdca_class_drv *drv = dev_get_drvdata(&sdw->dev); 44*2d877d06SCharles Keepax 45*2d877d06SCharles Keepax switch (status) { 46*2d877d06SCharles Keepax case SDW_SLAVE_ATTACHED: 47*2d877d06SCharles Keepax dev_dbg(drv->dev, "device attach\n"); 48*2d877d06SCharles Keepax 49*2d877d06SCharles Keepax drv->attached = true; 50*2d877d06SCharles Keepax 51*2d877d06SCharles Keepax complete(&drv->device_attach); 52*2d877d06SCharles Keepax break; 53*2d877d06SCharles Keepax case SDW_SLAVE_UNATTACHED: 54*2d877d06SCharles Keepax dev_dbg(drv->dev, "device detach\n"); 55*2d877d06SCharles Keepax 56*2d877d06SCharles Keepax drv->attached = false; 57*2d877d06SCharles Keepax 58*2d877d06SCharles Keepax reinit_completion(&drv->device_attach); 59*2d877d06SCharles Keepax break; 60*2d877d06SCharles Keepax default: 61*2d877d06SCharles Keepax break; 62*2d877d06SCharles Keepax } 63*2d877d06SCharles Keepax 64*2d877d06SCharles Keepax return 0; 65*2d877d06SCharles Keepax } 66*2d877d06SCharles Keepax 67*2d877d06SCharles Keepax static const struct sdw_slave_ops class_sdw_ops = { 68*2d877d06SCharles Keepax .read_prop = class_read_prop, 69*2d877d06SCharles Keepax .update_status = class_sdw_update_status, 70*2d877d06SCharles Keepax }; 71*2d877d06SCharles Keepax 72*2d877d06SCharles Keepax static void class_regmap_lock(void *data) 73*2d877d06SCharles Keepax { 74*2d877d06SCharles Keepax struct mutex *lock = data; 75*2d877d06SCharles Keepax 76*2d877d06SCharles Keepax mutex_lock(lock); 77*2d877d06SCharles Keepax } 78*2d877d06SCharles Keepax 79*2d877d06SCharles Keepax static void class_regmap_unlock(void *data) 80*2d877d06SCharles Keepax { 81*2d877d06SCharles Keepax struct mutex *lock = data; 82*2d877d06SCharles Keepax 83*2d877d06SCharles Keepax mutex_unlock(lock); 84*2d877d06SCharles Keepax } 85*2d877d06SCharles Keepax 86*2d877d06SCharles Keepax static int class_wait_for_attach(struct sdca_class_drv *drv) 87*2d877d06SCharles Keepax { 88*2d877d06SCharles Keepax if (!drv->attached) { 89*2d877d06SCharles Keepax unsigned long timeout = msecs_to_jiffies(CLASS_SDW_ATTACH_TIMEOUT_MS); 90*2d877d06SCharles Keepax unsigned long time; 91*2d877d06SCharles Keepax 92*2d877d06SCharles Keepax time = wait_for_completion_timeout(&drv->device_attach, timeout); 93*2d877d06SCharles Keepax if (!time) { 94*2d877d06SCharles Keepax dev_err(drv->dev, "timed out waiting for device re-attach\n"); 95*2d877d06SCharles Keepax return -ETIMEDOUT; 96*2d877d06SCharles Keepax } 97*2d877d06SCharles Keepax } 98*2d877d06SCharles Keepax 99*2d877d06SCharles Keepax regcache_cache_only(drv->dev_regmap, false); 100*2d877d06SCharles Keepax 101*2d877d06SCharles Keepax return 0; 102*2d877d06SCharles Keepax } 103*2d877d06SCharles Keepax 104*2d877d06SCharles Keepax static bool class_dev_regmap_volatile(struct device *dev, unsigned int reg) 105*2d877d06SCharles Keepax { 106*2d877d06SCharles Keepax switch (reg) { 107*2d877d06SCharles Keepax case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4: 108*2d877d06SCharles Keepax return false; 109*2d877d06SCharles Keepax default: 110*2d877d06SCharles Keepax return true; 111*2d877d06SCharles Keepax } 112*2d877d06SCharles Keepax } 113*2d877d06SCharles Keepax 114*2d877d06SCharles Keepax static bool class_dev_regmap_precious(struct device *dev, unsigned int reg) 115*2d877d06SCharles Keepax { 116*2d877d06SCharles Keepax switch (reg) { 117*2d877d06SCharles Keepax case SDW_SCP_SDCA_INT1 ... SDW_SCP_SDCA_INT4: 118*2d877d06SCharles Keepax case SDW_SCP_SDCA_INTMASK1 ... SDW_SCP_SDCA_INTMASK4: 119*2d877d06SCharles Keepax return false; 120*2d877d06SCharles Keepax default: 121*2d877d06SCharles Keepax return true; 122*2d877d06SCharles Keepax } 123*2d877d06SCharles Keepax } 124*2d877d06SCharles Keepax 125*2d877d06SCharles Keepax static const struct regmap_config class_dev_regmap_config = { 126*2d877d06SCharles Keepax .name = "sdca-device", 127*2d877d06SCharles Keepax .reg_bits = 32, 128*2d877d06SCharles Keepax .val_bits = 8, 129*2d877d06SCharles Keepax 130*2d877d06SCharles Keepax .max_register = SDW_SDCA_MAX_REGISTER, 131*2d877d06SCharles Keepax .volatile_reg = class_dev_regmap_volatile, 132*2d877d06SCharles Keepax .precious_reg = class_dev_regmap_precious, 133*2d877d06SCharles Keepax 134*2d877d06SCharles Keepax .cache_type = REGCACHE_MAPLE, 135*2d877d06SCharles Keepax 136*2d877d06SCharles Keepax .lock = class_regmap_lock, 137*2d877d06SCharles Keepax .unlock = class_regmap_unlock, 138*2d877d06SCharles Keepax }; 139*2d877d06SCharles Keepax 140*2d877d06SCharles Keepax static void class_boot_work(struct work_struct *work) 141*2d877d06SCharles Keepax { 142*2d877d06SCharles Keepax struct sdca_class_drv *drv = container_of(work, 143*2d877d06SCharles Keepax struct sdca_class_drv, 144*2d877d06SCharles Keepax boot_work); 145*2d877d06SCharles Keepax int ret; 146*2d877d06SCharles Keepax 147*2d877d06SCharles Keepax ret = class_wait_for_attach(drv); 148*2d877d06SCharles Keepax if (ret) 149*2d877d06SCharles Keepax goto err; 150*2d877d06SCharles Keepax 151*2d877d06SCharles Keepax drv->irq_info = sdca_irq_allocate(drv->dev, drv->dev_regmap, 152*2d877d06SCharles Keepax drv->sdw->irq); 153*2d877d06SCharles Keepax if (IS_ERR(drv->irq_info)) 154*2d877d06SCharles Keepax goto err; 155*2d877d06SCharles Keepax 156*2d877d06SCharles Keepax ret = sdca_dev_register_functions(drv->sdw); 157*2d877d06SCharles Keepax if (ret) 158*2d877d06SCharles Keepax goto err; 159*2d877d06SCharles Keepax 160*2d877d06SCharles Keepax dev_dbg(drv->dev, "boot work complete\n"); 161*2d877d06SCharles Keepax 162*2d877d06SCharles Keepax pm_runtime_mark_last_busy(drv->dev); 163*2d877d06SCharles Keepax pm_runtime_put_autosuspend(drv->dev); 164*2d877d06SCharles Keepax 165*2d877d06SCharles Keepax return; 166*2d877d06SCharles Keepax 167*2d877d06SCharles Keepax err: 168*2d877d06SCharles Keepax pm_runtime_put_sync(drv->dev); 169*2d877d06SCharles Keepax } 170*2d877d06SCharles Keepax 171*2d877d06SCharles Keepax static void class_dev_remove(void *data) 172*2d877d06SCharles Keepax { 173*2d877d06SCharles Keepax struct sdca_class_drv *drv = data; 174*2d877d06SCharles Keepax 175*2d877d06SCharles Keepax cancel_work_sync(&drv->boot_work); 176*2d877d06SCharles Keepax 177*2d877d06SCharles Keepax sdca_dev_unregister_functions(drv->sdw); 178*2d877d06SCharles Keepax } 179*2d877d06SCharles Keepax 180*2d877d06SCharles Keepax static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id) 181*2d877d06SCharles Keepax { 182*2d877d06SCharles Keepax struct device *dev = &sdw->dev; 183*2d877d06SCharles Keepax struct sdca_device_data *data = &sdw->sdca_data; 184*2d877d06SCharles Keepax struct regmap_config *dev_config; 185*2d877d06SCharles Keepax struct sdca_class_drv *drv; 186*2d877d06SCharles Keepax int ret; 187*2d877d06SCharles Keepax 188*2d877d06SCharles Keepax sdca_lookup_swft(sdw); 189*2d877d06SCharles Keepax 190*2d877d06SCharles Keepax drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); 191*2d877d06SCharles Keepax if (!drv) 192*2d877d06SCharles Keepax return -ENOMEM; 193*2d877d06SCharles Keepax 194*2d877d06SCharles Keepax dev_config = devm_kmemdup(dev, &class_dev_regmap_config, 195*2d877d06SCharles Keepax sizeof(*dev_config), GFP_KERNEL); 196*2d877d06SCharles Keepax if (!dev_config) 197*2d877d06SCharles Keepax return -ENOMEM; 198*2d877d06SCharles Keepax 199*2d877d06SCharles Keepax drv->functions = devm_kcalloc(dev, data->num_functions, 200*2d877d06SCharles Keepax sizeof(*drv->functions), 201*2d877d06SCharles Keepax GFP_KERNEL); 202*2d877d06SCharles Keepax if (!drv->functions) 203*2d877d06SCharles Keepax return -ENOMEM; 204*2d877d06SCharles Keepax 205*2d877d06SCharles Keepax drv->dev = dev; 206*2d877d06SCharles Keepax drv->sdw = sdw; 207*2d877d06SCharles Keepax mutex_init(&drv->regmap_lock); 208*2d877d06SCharles Keepax 209*2d877d06SCharles Keepax dev_set_drvdata(drv->dev, drv); 210*2d877d06SCharles Keepax 211*2d877d06SCharles Keepax INIT_WORK(&drv->boot_work, class_boot_work); 212*2d877d06SCharles Keepax init_completion(&drv->device_attach); 213*2d877d06SCharles Keepax 214*2d877d06SCharles Keepax dev_config->lock_arg = &drv->regmap_lock; 215*2d877d06SCharles Keepax 216*2d877d06SCharles Keepax drv->dev_regmap = devm_regmap_init_sdw(sdw, dev_config); 217*2d877d06SCharles Keepax if (IS_ERR(drv->dev_regmap)) 218*2d877d06SCharles Keepax return dev_err_probe(drv->dev, PTR_ERR(drv->dev_regmap), 219*2d877d06SCharles Keepax "failed to create device regmap\n"); 220*2d877d06SCharles Keepax 221*2d877d06SCharles Keepax regcache_cache_only(drv->dev_regmap, true); 222*2d877d06SCharles Keepax 223*2d877d06SCharles Keepax pm_runtime_set_autosuspend_delay(dev, 250); 224*2d877d06SCharles Keepax pm_runtime_use_autosuspend(dev); 225*2d877d06SCharles Keepax pm_runtime_set_active(dev); 226*2d877d06SCharles Keepax pm_runtime_get_noresume(dev); 227*2d877d06SCharles Keepax 228*2d877d06SCharles Keepax ret = devm_pm_runtime_enable(dev); 229*2d877d06SCharles Keepax if (ret) 230*2d877d06SCharles Keepax return ret; 231*2d877d06SCharles Keepax 232*2d877d06SCharles Keepax ret = devm_add_action_or_reset(dev, class_dev_remove, drv); 233*2d877d06SCharles Keepax if (ret) 234*2d877d06SCharles Keepax return ret; 235*2d877d06SCharles Keepax 236*2d877d06SCharles Keepax queue_work(system_long_wq, &drv->boot_work); 237*2d877d06SCharles Keepax 238*2d877d06SCharles Keepax return 0; 239*2d877d06SCharles Keepax } 240*2d877d06SCharles Keepax 241*2d877d06SCharles Keepax static int class_runtime_suspend(struct device *dev) 242*2d877d06SCharles Keepax { 243*2d877d06SCharles Keepax struct sdca_class_drv *drv = dev_get_drvdata(dev); 244*2d877d06SCharles Keepax 245*2d877d06SCharles Keepax /* 246*2d877d06SCharles Keepax * Whilst the driver doesn't power the chip down here, going into runtime 247*2d877d06SCharles Keepax * suspend lets the SoundWire bus power down, which means the driver 248*2d877d06SCharles Keepax * can't communicate with the device any more. 249*2d877d06SCharles Keepax */ 250*2d877d06SCharles Keepax regcache_cache_only(drv->dev_regmap, true); 251*2d877d06SCharles Keepax 252*2d877d06SCharles Keepax return 0; 253*2d877d06SCharles Keepax } 254*2d877d06SCharles Keepax 255*2d877d06SCharles Keepax static int class_runtime_resume(struct device *dev) 256*2d877d06SCharles Keepax { 257*2d877d06SCharles Keepax struct sdca_class_drv *drv = dev_get_drvdata(dev); 258*2d877d06SCharles Keepax int ret; 259*2d877d06SCharles Keepax 260*2d877d06SCharles Keepax ret = class_wait_for_attach(drv); 261*2d877d06SCharles Keepax if (ret) 262*2d877d06SCharles Keepax goto err; 263*2d877d06SCharles Keepax 264*2d877d06SCharles Keepax regcache_mark_dirty(drv->dev_regmap); 265*2d877d06SCharles Keepax 266*2d877d06SCharles Keepax ret = regcache_sync(drv->dev_regmap); 267*2d877d06SCharles Keepax if (ret) { 268*2d877d06SCharles Keepax dev_err(drv->dev, "failed to restore cache: %d\n", ret); 269*2d877d06SCharles Keepax goto err; 270*2d877d06SCharles Keepax } 271*2d877d06SCharles Keepax 272*2d877d06SCharles Keepax return 0; 273*2d877d06SCharles Keepax 274*2d877d06SCharles Keepax err: 275*2d877d06SCharles Keepax regcache_cache_only(drv->dev_regmap, true); 276*2d877d06SCharles Keepax 277*2d877d06SCharles Keepax return ret; 278*2d877d06SCharles Keepax } 279*2d877d06SCharles Keepax 280*2d877d06SCharles Keepax static const struct dev_pm_ops class_pm_ops = { 281*2d877d06SCharles Keepax RUNTIME_PM_OPS(class_runtime_suspend, class_runtime_resume, NULL) 282*2d877d06SCharles Keepax }; 283*2d877d06SCharles Keepax 284*2d877d06SCharles Keepax static const struct sdw_device_id class_sdw_id[] = { 285*2d877d06SCharles Keepax SDW_SLAVE_ENTRY(0x01FA, 0x4245, 0), 286*2d877d06SCharles Keepax {} 287*2d877d06SCharles Keepax }; 288*2d877d06SCharles Keepax MODULE_DEVICE_TABLE(sdw, class_sdw_id); 289*2d877d06SCharles Keepax 290*2d877d06SCharles Keepax static struct sdw_driver class_sdw_driver = { 291*2d877d06SCharles Keepax .driver = { 292*2d877d06SCharles Keepax .name = "sdca_class", 293*2d877d06SCharles Keepax .pm = pm_ptr(&class_pm_ops), 294*2d877d06SCharles Keepax }, 295*2d877d06SCharles Keepax 296*2d877d06SCharles Keepax .probe = class_sdw_probe, 297*2d877d06SCharles Keepax .id_table = class_sdw_id, 298*2d877d06SCharles Keepax .ops = &class_sdw_ops, 299*2d877d06SCharles Keepax }; 300*2d877d06SCharles Keepax module_sdw_driver(class_sdw_driver); 301*2d877d06SCharles Keepax 302*2d877d06SCharles Keepax MODULE_LICENSE("GPL"); 303*2d877d06SCharles Keepax MODULE_DESCRIPTION("SDCA Class Driver"); 304*2d877d06SCharles Keepax MODULE_IMPORT_NS("SND_SOC_SDCA"); 305