diff --git a/include/sound/sdca_class.h b/include/sound/sdca_class.h index 890c2dbd88a2..794a756472cd 100644 --- a/include/sound/sdca_class.h +++ b/include/sound/sdca_class.h @@ -19,6 +19,19 @@ struct regmap; struct sdw_slave; struct sdca_function_data; +/** + * struct sdca_class_ops - optional codec-provided class callbacks + * @populate_function: fill @function (entities, clusters, init_table, ...) + * from static tables in place of sdca_parse_function() on + * DT/non-DisCo platforms. Called once per SDCA function with + * @dev pointing at that function's device. Pure data source; + * performs no bus I/O. Return 0 on success or a negative errno. + */ +struct sdca_class_ops { + int (*populate_function)(struct device *dev, + struct sdca_function_data *function); +}; + struct sdca_class_drv { struct device *dev; struct regmap *dev_regmap; @@ -26,6 +39,8 @@ struct sdca_class_drv { struct sdca_interrupt_info *irq_info; + const struct sdca_class_ops *ops; + struct mutex regmap_lock; /* Serialise function initialisations */ struct mutex init_lock; @@ -33,7 +48,9 @@ struct sdca_class_drv { }; /* Library helpers used by codec-specific SDCA SoundWire drivers. */ -int sdca_class_probe(struct sdw_slave *sdw, struct sdca_class_drv *drv); +int sdca_class_probe(struct sdw_slave *sdw, + struct sdca_class_drv *drv, + const struct sdca_class_ops *ops); void sdca_class_remove(struct sdca_class_drv *drv); /* diff --git a/sound/soc/sdca/sdca_class.c b/sound/soc/sdca/sdca_class.c index 0e6dead41495..79fdb672be1d 100644 --- a/sound/soc/sdca/sdca_class.c +++ b/sound/soc/sdca/sdca_class.c @@ -144,6 +144,8 @@ static void class_boot_work(struct work_struct *work) * allocation and sets its own dev_set_drvdata() -- the framework * does not touch drvdata. Typically embedded in the codec's own * priv struct so codec drivers can keep per-slave state. + * @ops: optional codec-provided class callbacks (may be NULL for + * pure-generic SDCA parts that need no quirks) * * Codec-specific SoundWire drivers call this from their .probe after * allocating a struct sdca_class_drv (usually embedded in their own @@ -151,7 +153,9 @@ static void class_boot_work(struct work_struct *work) * sdca_class_drv fields, sets up the class regmap, and queues the * deferred boot work. */ -int sdca_class_probe(struct sdw_slave *sdw, struct sdca_class_drv *drv) +int sdca_class_probe(struct sdw_slave *sdw, + struct sdca_class_drv *drv, + const struct sdca_class_ops *ops) { struct device *dev = &sdw->dev; struct regmap_config *dev_config; @@ -169,6 +173,7 @@ int sdca_class_probe(struct sdw_slave *sdw, struct sdca_class_drv *drv) drv->dev = dev; drv->sdw = sdw; + drv->ops = ops; mutex_init(&drv->regmap_lock); mutex_init(&drv->init_lock); @@ -213,7 +218,7 @@ static int class_sdw_probe(struct sdw_slave *sdw, const struct sdw_device_id *id dev_set_drvdata(&sdw->dev, drv); - return sdca_class_probe(sdw, drv); + return sdca_class_probe(sdw, drv, NULL); } /** diff --git a/sound/soc/sdca/sdca_class_function.c b/sound/soc/sdca/sdca_class_function.c index 411e3d717bb6..c49afa2e626d 100644 --- a/sound/soc/sdca/sdca_class_function.c +++ b/sound/soc/sdca/sdca_class_function.c @@ -329,7 +329,14 @@ static int class_function_probe(struct auxiliary_device *auxdev, drv->core = core; drv->function = &sdev->function; - ret = sdca_parse_function(dev, drv->function); + if (core->ops && core->ops->populate_function) { + ret = core->ops->populate_function(dev, drv->function); + } else if (drv->function->desc->node) { + ret = sdca_parse_function(dev, drv->function); + } else { + dev_err(dev, "no firmware node and no populate_function hook\n"); + return -ENOENT; + } if (ret) return ret;