Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soundwire: Add SoundWire bus type

This adds the base SoundWire bus type, bus and driver registration.
along with changes to module device table for new SoundWire
device type.

Signed-off-by: Sanyog Kale <sanyog.r.kale@intel.com>
Reviewed-by: Philippe Ombredanne <pombredanne@nexb.com>
Acked-By: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Takashi Iwai <tiwai@suse.de>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Vinod Koul and committed by
Greg Kroah-Hartman
9251345d 8ecf4264

+356
+2
drivers/Kconfig
··· 153 153 154 154 source "drivers/rpmsg/Kconfig" 155 155 156 + source "drivers/soundwire/Kconfig" 157 + 156 158 source "drivers/soc/Kconfig" 157 159 158 160 source "drivers/devfreq/Kconfig"
+1
drivers/Makefile
··· 158 158 obj-$(CONFIG_HWSPINLOCK) += hwspinlock/ 159 159 obj-$(CONFIG_REMOTEPROC) += remoteproc/ 160 160 obj-$(CONFIG_RPMSG) += rpmsg/ 161 + obj-$(CONFIG_SOUNDWIRE) += soundwire/ 161 162 162 163 # Virtualization drivers 163 164 obj-$(CONFIG_VIRT_DRIVERS) += virt/
+22
drivers/soundwire/Kconfig
··· 1 + # 2 + # SoundWire subsystem configuration 3 + # 4 + 5 + menuconfig SOUNDWIRE 6 + bool "SoundWire support" 7 + ---help--- 8 + SoundWire is a 2-Pin interface with data and clock line ratified 9 + by the MIPI Alliance. SoundWire is used for transporting data 10 + typically related to audio functions. SoundWire interface is 11 + optimized to integrate audio devices in mobile or mobile inspired 12 + systems. Say Y to enable this subsystem, N if you do not have such 13 + a device 14 + 15 + if SOUNDWIRE 16 + 17 + comment "SoundWire Devices" 18 + 19 + config SOUNDWIRE_BUS 20 + tristate 21 + 22 + endif
+7
drivers/soundwire/Makefile
··· 1 + # 2 + # Makefile for soundwire core 3 + # 4 + 5 + #Bus Objs 6 + soundwire-bus-objs := bus_type.o 7 + obj-$(CONFIG_SOUNDWIRE_BUS) += soundwire-bus.o
+172
drivers/soundwire/bus_type.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright(c) 2015-17 Intel Corporation. 3 + 4 + #include <linux/module.h> 5 + #include <linux/mod_devicetable.h> 6 + #include <linux/pm_domain.h> 7 + #include <linux/soundwire/sdw.h> 8 + #include <linux/soundwire/sdw_type.h> 9 + 10 + /** 11 + * sdw_get_device_id - find the matching SoundWire device id 12 + * @slave: SoundWire Slave Device 13 + * @drv: SoundWire Slave Driver 14 + * 15 + * The match is done by comparing the mfg_id and part_id from the 16 + * struct sdw_device_id. 17 + */ 18 + static const struct sdw_device_id * 19 + sdw_get_device_id(struct sdw_slave *slave, struct sdw_driver *drv) 20 + { 21 + const struct sdw_device_id *id = drv->id_table; 22 + 23 + while (id && id->mfg_id) { 24 + if (slave->id.mfg_id == id->mfg_id && 25 + slave->id.part_id == id->part_id) 26 + return id; 27 + id++; 28 + } 29 + 30 + return NULL; 31 + } 32 + 33 + static int sdw_bus_match(struct device *dev, struct device_driver *ddrv) 34 + { 35 + struct sdw_slave *slave = dev_to_sdw_dev(dev); 36 + struct sdw_driver *drv = drv_to_sdw_driver(ddrv); 37 + 38 + return !!sdw_get_device_id(slave, drv); 39 + } 40 + 41 + int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size) 42 + { 43 + /* modalias is sdw:m<mfg_id>p<part_id> */ 44 + 45 + return snprintf(buf, size, "sdw:m%04Xp%04X\n", 46 + slave->id.mfg_id, slave->id.part_id); 47 + } 48 + 49 + static int sdw_uevent(struct device *dev, struct kobj_uevent_env *env) 50 + { 51 + struct sdw_slave *slave = dev_to_sdw_dev(dev); 52 + char modalias[32]; 53 + 54 + sdw_slave_modalias(slave, modalias, sizeof(modalias)); 55 + 56 + if (add_uevent_var(env, "MODALIAS=%s", modalias)) 57 + return -ENOMEM; 58 + 59 + return 0; 60 + } 61 + 62 + struct bus_type sdw_bus_type = { 63 + .name = "soundwire", 64 + .match = sdw_bus_match, 65 + .uevent = sdw_uevent, 66 + }; 67 + EXPORT_SYMBOL_GPL(sdw_bus_type); 68 + 69 + static int sdw_drv_probe(struct device *dev) 70 + { 71 + struct sdw_slave *slave = dev_to_sdw_dev(dev); 72 + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 73 + const struct sdw_device_id *id; 74 + int ret; 75 + 76 + id = sdw_get_device_id(slave, drv); 77 + if (!id) 78 + return -ENODEV; 79 + 80 + /* 81 + * attach to power domain but don't turn on (last arg) 82 + */ 83 + ret = dev_pm_domain_attach(dev, false); 84 + if (ret != -EPROBE_DEFER) { 85 + ret = drv->probe(slave, id); 86 + if (ret) { 87 + dev_err(dev, "Probe of %s failed: %d\n", drv->name, ret); 88 + dev_pm_domain_detach(dev, false); 89 + } 90 + } 91 + 92 + return ret; 93 + } 94 + 95 + static int sdw_drv_remove(struct device *dev) 96 + { 97 + struct sdw_slave *slave = dev_to_sdw_dev(dev); 98 + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 99 + int ret = 0; 100 + 101 + if (drv->remove) 102 + ret = drv->remove(slave); 103 + 104 + dev_pm_domain_detach(dev, false); 105 + 106 + return ret; 107 + } 108 + 109 + static void sdw_drv_shutdown(struct device *dev) 110 + { 111 + struct sdw_slave *slave = dev_to_sdw_dev(dev); 112 + struct sdw_driver *drv = drv_to_sdw_driver(dev->driver); 113 + 114 + if (drv->shutdown) 115 + drv->shutdown(slave); 116 + } 117 + 118 + /** 119 + * __sdw_register_driver() - register a SoundWire Slave driver 120 + * @drv: driver to register 121 + * @owner: owning module/driver 122 + * 123 + * Return: zero on success, else a negative error code. 124 + */ 125 + int __sdw_register_driver(struct sdw_driver *drv, struct module *owner) 126 + { 127 + drv->driver.bus = &sdw_bus_type; 128 + 129 + if (!drv->probe) { 130 + pr_err("driver %s didn't provide SDW probe routine\n", 131 + drv->name); 132 + return -EINVAL; 133 + } 134 + 135 + drv->driver.owner = owner; 136 + drv->driver.probe = sdw_drv_probe; 137 + 138 + if (drv->remove) 139 + drv->driver.remove = sdw_drv_remove; 140 + 141 + if (drv->shutdown) 142 + drv->driver.shutdown = sdw_drv_shutdown; 143 + 144 + return driver_register(&drv->driver); 145 + } 146 + EXPORT_SYMBOL_GPL(__sdw_register_driver); 147 + 148 + /** 149 + * sdw_unregister_driver() - unregisters the SoundWire Slave driver 150 + * @drv: driver to unregister 151 + */ 152 + void sdw_unregister_driver(struct sdw_driver *drv) 153 + { 154 + driver_unregister(&drv->driver); 155 + } 156 + EXPORT_SYMBOL_GPL(sdw_unregister_driver); 157 + 158 + static int __init sdw_bus_init(void) 159 + { 160 + return bus_register(&sdw_bus_type); 161 + } 162 + 163 + static void __exit sdw_bus_exit(void) 164 + { 165 + bus_unregister(&sdw_bus_type); 166 + } 167 + 168 + postcore_initcall(sdw_bus_init); 169 + module_exit(sdw_bus_exit); 170 + 171 + MODULE_DESCRIPTION("SoundWire bus"); 172 + MODULE_LICENSE("GPL v2");
+6
include/linux/mod_devicetable.h
··· 229 229 unsigned long driver_data; 230 230 }; 231 231 232 + struct sdw_device_id { 233 + __u16 mfg_id; 234 + __u16 part_id; 235 + kernel_ulong_t driver_data; 236 + }; 237 + 232 238 /* 233 239 * Struct used for matching a device 234 240 */
+108
include/linux/soundwire/sdw.h
··· 1 + // SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) 2 + // Copyright(c) 2015-17 Intel Corporation. 3 + 4 + #ifndef __SOUNDWIRE_H 5 + #define __SOUNDWIRE_H 6 + 7 + struct sdw_bus; 8 + struct sdw_slave; 9 + 10 + #define SDW_MAX_DEVICES 11 11 + 12 + /** 13 + * enum sdw_slave_status - Slave status 14 + * @SDW_SLAVE_UNATTACHED: Slave is not attached with the bus. 15 + * @SDW_SLAVE_ATTACHED: Slave is attached with bus. 16 + * @SDW_SLAVE_ALERT: Some alert condition on the Slave 17 + * @SDW_SLAVE_RESERVED: Reserved for future use 18 + */ 19 + enum sdw_slave_status { 20 + SDW_SLAVE_UNATTACHED = 0, 21 + SDW_SLAVE_ATTACHED = 1, 22 + SDW_SLAVE_ALERT = 2, 23 + SDW_SLAVE_RESERVED = 3, 24 + }; 25 + 26 + /* 27 + * SDW Slave Structures and APIs 28 + */ 29 + 30 + /** 31 + * struct sdw_slave_id - Slave ID 32 + * @mfg_id: MIPI Manufacturer ID 33 + * @part_id: Device Part ID 34 + * @class_id: MIPI Class ID, unused now. 35 + * Currently a placeholder in MIPI SoundWire Spec 36 + * @unique_id: Device unique ID 37 + * @sdw_version: SDW version implemented 38 + * 39 + * The order of the IDs here does not follow the DisCo spec definitions 40 + */ 41 + struct sdw_slave_id { 42 + __u16 mfg_id; 43 + __u16 part_id; 44 + __u8 class_id; 45 + __u8 unique_id:4; 46 + __u8 sdw_version:4; 47 + }; 48 + 49 + /** 50 + * struct sdw_slave - SoundWire Slave 51 + * @id: MIPI device ID 52 + * @dev: Linux device 53 + * @status: Status reported by the Slave 54 + * @bus: Bus handle 55 + * @node: node for bus list 56 + * @dev_num: Device Number assigned by Bus 57 + */ 58 + struct sdw_slave { 59 + struct sdw_slave_id id; 60 + struct device dev; 61 + enum sdw_slave_status status; 62 + struct sdw_bus *bus; 63 + struct list_head node; 64 + u16 dev_num; 65 + }; 66 + 67 + #define dev_to_sdw_dev(_dev) container_of(_dev, struct sdw_slave, dev) 68 + 69 + struct sdw_driver { 70 + const char *name; 71 + 72 + int (*probe)(struct sdw_slave *sdw, 73 + const struct sdw_device_id *id); 74 + int (*remove)(struct sdw_slave *sdw); 75 + void (*shutdown)(struct sdw_slave *sdw); 76 + 77 + const struct sdw_device_id *id_table; 78 + const struct sdw_slave_ops *ops; 79 + 80 + struct device_driver driver; 81 + }; 82 + 83 + #define SDW_SLAVE_ENTRY(_mfg_id, _part_id, _drv_data) \ 84 + { .mfg_id = (_mfg_id), .part_id = (_part_id), \ 85 + .driver_data = (unsigned long)(_drv_data) } 86 + 87 + /* 88 + * SDW master structures and APIs 89 + */ 90 + 91 + /** 92 + * struct sdw_bus - SoundWire bus 93 + * @dev: Master linux device 94 + * @link_id: Link id number, can be 0 to N, unique for each Master 95 + * @slaves: list of Slaves on this bus 96 + * @assigned: Bitmap for Slave device numbers. 97 + * Bit set implies used number, bit clear implies unused number. 98 + * @bus_lock: bus lock 99 + */ 100 + struct sdw_bus { 101 + struct device *dev; 102 + unsigned int link_id; 103 + struct list_head slaves; 104 + DECLARE_BITMAP(assigned, SDW_MAX_DEVICES); 105 + struct mutex bus_lock; 106 + }; 107 + 108 + #endif /* __SOUNDWIRE_H */
+19
include/linux/soundwire/sdw_type.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright(c) 2015-17 Intel Corporation. 3 + 4 + #ifndef __SOUNDWIRE_TYPES_H 5 + #define __SOUNDWIRE_TYPES_H 6 + 7 + extern struct bus_type sdw_bus_type; 8 + 9 + #define drv_to_sdw_driver(_drv) container_of(_drv, struct sdw_driver, driver) 10 + 11 + #define sdw_register_driver(drv) \ 12 + __sdw_register_driver(drv, THIS_MODULE) 13 + 14 + int __sdw_register_driver(struct sdw_driver *drv, struct module *); 15 + void sdw_unregister_driver(struct sdw_driver *drv); 16 + 17 + int sdw_slave_modalias(const struct sdw_slave *slave, char *buf, size_t size); 18 + 19 + #endif /* __SOUNDWIRE_TYPES_H */
+4
scripts/mod/devicetable-offsets.c
··· 203 203 DEVID_FIELD(hda_device_id, rev_id); 204 204 DEVID_FIELD(hda_device_id, api_version); 205 205 206 + DEVID(sdw_device_id); 207 + DEVID_FIELD(sdw_device_id, mfg_id); 208 + DEVID_FIELD(sdw_device_id, part_id); 209 + 206 210 DEVID(fsl_mc_device_id); 207 211 DEVID_FIELD(fsl_mc_device_id, vendor); 208 212 DEVID_FIELD(fsl_mc_device_id, obj_type);
+15
scripts/mod/file2alias.c
··· 1289 1289 } 1290 1290 ADD_TO_DEVTABLE("hdaudio", hda_device_id, do_hda_entry); 1291 1291 1292 + /* Looks like: sdw:mNpN */ 1293 + static int do_sdw_entry(const char *filename, void *symval, char *alias) 1294 + { 1295 + DEF_FIELD(symval, sdw_device_id, mfg_id); 1296 + DEF_FIELD(symval, sdw_device_id, part_id); 1297 + 1298 + strcpy(alias, "sdw:"); 1299 + ADD(alias, "m", mfg_id != 0, mfg_id); 1300 + ADD(alias, "p", part_id != 0, part_id); 1301 + 1302 + add_wildcard(alias); 1303 + return 1; 1304 + } 1305 + ADD_TO_DEVTABLE("sdw", sdw_device_id, do_sdw_entry); 1306 + 1292 1307 /* Looks like: fsl-mc:vNdN */ 1293 1308 static int do_fsl_mc_entry(const char *filename, void *symval, 1294 1309 char *alias)