14496d1c6SPierre-Louis Bossart // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 24496d1c6SPierre-Louis Bossart // Copyright(c) 2024 Intel Corporation. 34496d1c6SPierre-Louis Bossart 44496d1c6SPierre-Louis Bossart /* 54496d1c6SPierre-Louis Bossart * SDCA Function Device management 64496d1c6SPierre-Louis Bossart */ 74496d1c6SPierre-Louis Bossart 84496d1c6SPierre-Louis Bossart #include <linux/acpi.h> 94496d1c6SPierre-Louis Bossart #include <linux/module.h> 104496d1c6SPierre-Louis Bossart #include <linux/auxiliary_bus.h> 114496d1c6SPierre-Louis Bossart #include <linux/soundwire/sdw.h> 124496d1c6SPierre-Louis Bossart #include <sound/sdca.h> 134496d1c6SPierre-Louis Bossart #include <sound/sdca_function.h> 144496d1c6SPierre-Louis Bossart #include "sdca_function_device.h" 154496d1c6SPierre-Louis Bossart 164496d1c6SPierre-Louis Bossart /* 174496d1c6SPierre-Louis Bossart * A SoundWire device can have multiple SDCA functions identified by 184496d1c6SPierre-Louis Bossart * their type and ADR. there can be multiple SoundWire devices per 194496d1c6SPierre-Louis Bossart * link, or multiple devices spread across multiple links. An IDA is 204496d1c6SPierre-Louis Bossart * required to identify each instance. 214496d1c6SPierre-Louis Bossart */ 224496d1c6SPierre-Louis Bossart static DEFINE_IDA(sdca_function_ida); 234496d1c6SPierre-Louis Bossart 244496d1c6SPierre-Louis Bossart static void sdca_dev_release(struct device *dev) 254496d1c6SPierre-Louis Bossart { 264496d1c6SPierre-Louis Bossart struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 274496d1c6SPierre-Louis Bossart struct sdca_dev *sdev = auxiliary_dev_to_sdca_dev(auxdev); 284496d1c6SPierre-Louis Bossart 294496d1c6SPierre-Louis Bossart ida_free(&sdca_function_ida, auxdev->id); 304496d1c6SPierre-Louis Bossart kfree(sdev); 314496d1c6SPierre-Louis Bossart } 324496d1c6SPierre-Louis Bossart 334496d1c6SPierre-Louis Bossart /* alloc, init and add link devices */ 344496d1c6SPierre-Louis Bossart static struct sdca_dev *sdca_dev_register(struct device *parent, 354496d1c6SPierre-Louis Bossart struct sdca_function_desc *function_desc) 364496d1c6SPierre-Louis Bossart { 374496d1c6SPierre-Louis Bossart struct sdca_dev *sdev; 384496d1c6SPierre-Louis Bossart struct auxiliary_device *auxdev; 394496d1c6SPierre-Louis Bossart int ret; 404496d1c6SPierre-Louis Bossart int rc; 414496d1c6SPierre-Louis Bossart 424496d1c6SPierre-Louis Bossart sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); 434496d1c6SPierre-Louis Bossart if (!sdev) 444496d1c6SPierre-Louis Bossart return ERR_PTR(-ENOMEM); 454496d1c6SPierre-Louis Bossart 464496d1c6SPierre-Louis Bossart auxdev = &sdev->auxdev; 474496d1c6SPierre-Louis Bossart auxdev->name = function_desc->name; 484496d1c6SPierre-Louis Bossart auxdev->dev.parent = parent; 494496d1c6SPierre-Louis Bossart auxdev->dev.fwnode = function_desc->node; 504496d1c6SPierre-Louis Bossart auxdev->dev.release = sdca_dev_release; 514496d1c6SPierre-Louis Bossart 524496d1c6SPierre-Louis Bossart sdev->function.desc = function_desc; 534496d1c6SPierre-Louis Bossart 544496d1c6SPierre-Louis Bossart rc = ida_alloc(&sdca_function_ida, GFP_KERNEL); 554496d1c6SPierre-Louis Bossart if (rc < 0) { 564496d1c6SPierre-Louis Bossart kfree(sdev); 574496d1c6SPierre-Louis Bossart return ERR_PTR(rc); 584496d1c6SPierre-Louis Bossart } 594496d1c6SPierre-Louis Bossart auxdev->id = rc; 604496d1c6SPierre-Louis Bossart 614496d1c6SPierre-Louis Bossart /* now follow the two-step init/add sequence */ 624496d1c6SPierre-Louis Bossart ret = auxiliary_device_init(auxdev); 634496d1c6SPierre-Louis Bossart if (ret < 0) { 644496d1c6SPierre-Louis Bossart dev_err(parent, "failed to initialize SDCA function dev %s\n", 654496d1c6SPierre-Louis Bossart function_desc->name); 664496d1c6SPierre-Louis Bossart ida_free(&sdca_function_ida, auxdev->id); 674496d1c6SPierre-Louis Bossart kfree(sdev); 684496d1c6SPierre-Louis Bossart return ERR_PTR(ret); 694496d1c6SPierre-Louis Bossart } 704496d1c6SPierre-Louis Bossart 714496d1c6SPierre-Louis Bossart ret = auxiliary_device_add(auxdev); 724496d1c6SPierre-Louis Bossart if (ret < 0) { 734496d1c6SPierre-Louis Bossart dev_err(parent, "failed to add SDCA function dev %s\n", 744496d1c6SPierre-Louis Bossart sdev->auxdev.name); 754496d1c6SPierre-Louis Bossart /* sdev will be freed with the put_device() and .release sequence */ 764496d1c6SPierre-Louis Bossart auxiliary_device_uninit(&sdev->auxdev); 774496d1c6SPierre-Louis Bossart return ERR_PTR(ret); 784496d1c6SPierre-Louis Bossart } 794496d1c6SPierre-Louis Bossart 804496d1c6SPierre-Louis Bossart return sdev; 814496d1c6SPierre-Louis Bossart } 824496d1c6SPierre-Louis Bossart 834496d1c6SPierre-Louis Bossart static void sdca_dev_unregister(struct sdca_dev *sdev) 844496d1c6SPierre-Louis Bossart { 854496d1c6SPierre-Louis Bossart auxiliary_device_delete(&sdev->auxdev); 864496d1c6SPierre-Louis Bossart auxiliary_device_uninit(&sdev->auxdev); 874496d1c6SPierre-Louis Bossart } 884496d1c6SPierre-Louis Bossart 894496d1c6SPierre-Louis Bossart int sdca_dev_register_functions(struct sdw_slave *slave) 904496d1c6SPierre-Louis Bossart { 914496d1c6SPierre-Louis Bossart struct sdca_device_data *sdca_data = &slave->sdca_data; 924496d1c6SPierre-Louis Bossart int i; 934496d1c6SPierre-Louis Bossart 944496d1c6SPierre-Louis Bossart for (i = 0; i < sdca_data->num_functions; i++) { 954496d1c6SPierre-Louis Bossart struct sdca_dev *func_dev; 964496d1c6SPierre-Louis Bossart 974496d1c6SPierre-Louis Bossart func_dev = sdca_dev_register(&slave->dev, 984496d1c6SPierre-Louis Bossart &sdca_data->function[i]); 99*80339b38SDan Carpenter if (IS_ERR(func_dev)) 100*80339b38SDan Carpenter return PTR_ERR(func_dev); 1014496d1c6SPierre-Louis Bossart 1024496d1c6SPierre-Louis Bossart sdca_data->function[i].func_dev = func_dev; 1034496d1c6SPierre-Louis Bossart } 1044496d1c6SPierre-Louis Bossart 1054496d1c6SPierre-Louis Bossart return 0; 1064496d1c6SPierre-Louis Bossart } 1074496d1c6SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdca_dev_register_functions, "SND_SOC_SDCA"); 1084496d1c6SPierre-Louis Bossart 1094496d1c6SPierre-Louis Bossart void sdca_dev_unregister_functions(struct sdw_slave *slave) 1104496d1c6SPierre-Louis Bossart { 1114496d1c6SPierre-Louis Bossart struct sdca_device_data *sdca_data = &slave->sdca_data; 1124496d1c6SPierre-Louis Bossart int i; 1134496d1c6SPierre-Louis Bossart 1144496d1c6SPierre-Louis Bossart for (i = 0; i < sdca_data->num_functions; i++) 1154496d1c6SPierre-Louis Bossart sdca_dev_unregister(sdca_data->function[i].func_dev); 1164496d1c6SPierre-Louis Bossart } 1174496d1c6SPierre-Louis Bossart EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA"); 118