serial-multi-instantiate.c (8403B)
1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Serial multi-instantiate driver, pseudo driver to instantiate multiple 4 * client devices from a single fwnode. 5 * 6 * Copyright 2018 Hans de Goede <hdegoede@redhat.com> 7 */ 8 9#include <linux/acpi.h> 10#include <linux/bits.h> 11#include <linux/i2c.h> 12#include <linux/interrupt.h> 13#include <linux/kernel.h> 14#include <linux/module.h> 15#include <linux/platform_device.h> 16#include <linux/property.h> 17#include <linux/spi/spi.h> 18#include <linux/types.h> 19 20#define IRQ_RESOURCE_TYPE GENMASK(1, 0) 21#define IRQ_RESOURCE_NONE 0 22#define IRQ_RESOURCE_GPIO 1 23#define IRQ_RESOURCE_APIC 2 24 25enum smi_bus_type { 26 SMI_I2C, 27 SMI_SPI, 28 SMI_AUTO_DETECT, 29}; 30 31struct smi_instance { 32 const char *type; 33 unsigned int flags; 34 int irq_idx; 35}; 36 37struct smi_node { 38 enum smi_bus_type bus_type; 39 struct smi_instance instances[]; 40}; 41 42struct smi { 43 int i2c_num; 44 int spi_num; 45 struct i2c_client **i2c_devs; 46 struct spi_device **spi_devs; 47}; 48 49static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev, 50 const struct smi_instance *inst) 51{ 52 int ret; 53 54 switch (inst->flags & IRQ_RESOURCE_TYPE) { 55 case IRQ_RESOURCE_GPIO: 56 ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx); 57 break; 58 case IRQ_RESOURCE_APIC: 59 ret = platform_get_irq(pdev, inst->irq_idx); 60 break; 61 default: 62 return 0; 63 } 64 65 if (ret < 0) 66 dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d: %d\n", 67 inst->irq_idx, ret); 68 69 return ret; 70} 71 72static void smi_devs_unregister(struct smi *smi) 73{ 74 while (smi->i2c_num > 0) 75 i2c_unregister_device(smi->i2c_devs[--smi->i2c_num]); 76 77 while (smi->spi_num > 0) 78 spi_unregister_device(smi->spi_devs[--smi->spi_num]); 79} 80 81/** 82 * smi_spi_probe - Instantiate multiple SPI devices from inst array 83 * @pdev: Platform device 84 * @adev: ACPI device 85 * @smi: Internal struct for Serial multi instantiate driver 86 * @inst_array: Array of instances to probe 87 * 88 * Returns the number of SPI devices instantiate, Zero if none is found or a negative error code. 89 */ 90static int smi_spi_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, 91 const struct smi_instance *inst_array) 92{ 93 struct device *dev = &pdev->dev; 94 struct spi_controller *ctlr; 95 struct spi_device *spi_dev; 96 char name[50]; 97 int i, ret, count; 98 99 ret = acpi_spi_count_resources(adev); 100 if (ret < 0) 101 return ret; 102 else if (!ret) 103 return -ENODEV; 104 105 count = ret; 106 107 smi->spi_devs = devm_kcalloc(dev, count, sizeof(*smi->spi_devs), GFP_KERNEL); 108 if (!smi->spi_devs) 109 return -ENOMEM; 110 111 for (i = 0; i < count && inst_array[i].type; i++) { 112 113 spi_dev = acpi_spi_device_alloc(NULL, adev, i); 114 if (IS_ERR(spi_dev)) { 115 ret = PTR_ERR(spi_dev); 116 dev_err_probe(dev, ret, "failed to allocate SPI device %s from ACPI: %d\n", 117 dev_name(&adev->dev), ret); 118 goto error; 119 } 120 121 ctlr = spi_dev->controller; 122 123 strscpy(spi_dev->modalias, inst_array[i].type, sizeof(spi_dev->modalias)); 124 125 ret = smi_get_irq(pdev, adev, &inst_array[i]); 126 if (ret < 0) { 127 spi_dev_put(spi_dev); 128 goto error; 129 } 130 spi_dev->irq = ret; 131 132 snprintf(name, sizeof(name), "%s-%s-%s.%d", dev_name(&ctlr->dev), dev_name(dev), 133 inst_array[i].type, i); 134 spi_dev->dev.init_name = name; 135 136 ret = spi_add_device(spi_dev); 137 if (ret) { 138 dev_err_probe(&ctlr->dev, ret, 139 "failed to add SPI device %s from ACPI: %d\n", 140 dev_name(&adev->dev), ret); 141 spi_dev_put(spi_dev); 142 goto error; 143 } 144 145 dev_dbg(dev, "SPI device %s using chip select %u", name, spi_dev->chip_select); 146 147 smi->spi_devs[i] = spi_dev; 148 smi->spi_num++; 149 } 150 151 if (smi->spi_num < count) { 152 dev_dbg(dev, "Error finding driver, idx %d\n", i); 153 ret = -ENODEV; 154 goto error; 155 } 156 157 dev_info(dev, "Instantiated %d SPI devices.\n", smi->spi_num); 158 159 return 0; 160error: 161 smi_devs_unregister(smi); 162 163 return ret; 164} 165 166/** 167 * smi_i2c_probe - Instantiate multiple I2C devices from inst array 168 * @pdev: Platform device 169 * @adev: ACPI device 170 * @smi: Internal struct for Serial multi instantiate driver 171 * @inst_array: Array of instances to probe 172 * 173 * Returns the number of I2C devices instantiate, Zero if none is found or a negative error code. 174 */ 175static int smi_i2c_probe(struct platform_device *pdev, struct acpi_device *adev, struct smi *smi, 176 const struct smi_instance *inst_array) 177{ 178 struct i2c_board_info board_info = {}; 179 struct device *dev = &pdev->dev; 180 char name[32]; 181 int i, ret, count; 182 183 ret = i2c_acpi_client_count(adev); 184 if (ret < 0) 185 return ret; 186 else if (!ret) 187 return -ENODEV; 188 189 count = ret; 190 191 smi->i2c_devs = devm_kcalloc(dev, count, sizeof(*smi->i2c_devs), GFP_KERNEL); 192 if (!smi->i2c_devs) 193 return -ENOMEM; 194 195 for (i = 0; i < count && inst_array[i].type; i++) { 196 memset(&board_info, 0, sizeof(board_info)); 197 strscpy(board_info.type, inst_array[i].type, I2C_NAME_SIZE); 198 snprintf(name, sizeof(name), "%s-%s.%d", dev_name(dev), inst_array[i].type, i); 199 board_info.dev_name = name; 200 201 ret = smi_get_irq(pdev, adev, &inst_array[i]); 202 if (ret < 0) 203 goto error; 204 board_info.irq = ret; 205 206 smi->i2c_devs[i] = i2c_acpi_new_device(dev, i, &board_info); 207 if (IS_ERR(smi->i2c_devs[i])) { 208 ret = dev_err_probe(dev, PTR_ERR(smi->i2c_devs[i]), 209 "Error creating i2c-client, idx %d\n", i); 210 goto error; 211 } 212 smi->i2c_num++; 213 } 214 if (smi->i2c_num < count) { 215 dev_dbg(dev, "Error finding driver, idx %d\n", i); 216 ret = -ENODEV; 217 goto error; 218 } 219 220 dev_info(dev, "Instantiated %d I2C devices.\n", smi->i2c_num); 221 222 return 0; 223error: 224 smi_devs_unregister(smi); 225 226 return ret; 227} 228 229static int smi_probe(struct platform_device *pdev) 230{ 231 struct device *dev = &pdev->dev; 232 const struct smi_node *node; 233 struct acpi_device *adev; 234 struct smi *smi; 235 236 adev = ACPI_COMPANION(dev); 237 if (!adev) 238 return -ENODEV; 239 240 node = device_get_match_data(dev); 241 if (!node) { 242 dev_dbg(dev, "Error ACPI match data is missing\n"); 243 return -ENODEV; 244 } 245 246 smi = devm_kzalloc(dev, sizeof(*smi), GFP_KERNEL); 247 if (!smi) 248 return -ENOMEM; 249 250 platform_set_drvdata(pdev, smi); 251 252 switch (node->bus_type) { 253 case SMI_I2C: 254 return smi_i2c_probe(pdev, adev, smi, node->instances); 255 case SMI_SPI: 256 return smi_spi_probe(pdev, adev, smi, node->instances); 257 case SMI_AUTO_DETECT: 258 if (i2c_acpi_client_count(adev) > 0) 259 return smi_i2c_probe(pdev, adev, smi, node->instances); 260 else 261 return smi_spi_probe(pdev, adev, smi, node->instances); 262 default: 263 return -EINVAL; 264 } 265 266 return 0; /* never reached */ 267} 268 269static int smi_remove(struct platform_device *pdev) 270{ 271 struct smi *smi = platform_get_drvdata(pdev); 272 273 smi_devs_unregister(smi); 274 275 return 0; 276} 277 278static const struct smi_node bsg1160_data = { 279 .instances = { 280 { "bmc150_accel", IRQ_RESOURCE_GPIO, 0 }, 281 { "bmc150_magn" }, 282 { "bmg160" }, 283 {} 284 }, 285 .bus_type = SMI_I2C, 286}; 287 288static const struct smi_node bsg2150_data = { 289 .instances = { 290 { "bmc150_accel", IRQ_RESOURCE_GPIO, 0 }, 291 { "bmc150_magn" }, 292 /* The resources describe a 3th client, but it is not really there. */ 293 { "bsg2150_dummy_dev" }, 294 {} 295 }, 296 .bus_type = SMI_I2C, 297}; 298 299static const struct smi_node int3515_data = { 300 .instances = { 301 { "tps6598x", IRQ_RESOURCE_APIC, 0 }, 302 { "tps6598x", IRQ_RESOURCE_APIC, 1 }, 303 { "tps6598x", IRQ_RESOURCE_APIC, 2 }, 304 { "tps6598x", IRQ_RESOURCE_APIC, 3 }, 305 {} 306 }, 307 .bus_type = SMI_I2C, 308}; 309 310static const struct smi_node cs35l41_hda = { 311 .instances = { 312 { "cs35l41-hda", IRQ_RESOURCE_GPIO, 0 }, 313 { "cs35l41-hda", IRQ_RESOURCE_GPIO, 0 }, 314 { "cs35l41-hda", IRQ_RESOURCE_GPIO, 0 }, 315 { "cs35l41-hda", IRQ_RESOURCE_GPIO, 0 }, 316 {} 317 }, 318 .bus_type = SMI_AUTO_DETECT, 319}; 320 321/* 322 * Note new device-ids must also be added to ignore_serial_bus_ids in 323 * drivers/acpi/scan.c: acpi_device_enumeration_by_parent(). 324 */ 325static const struct acpi_device_id smi_acpi_ids[] = { 326 { "BSG1160", (unsigned long)&bsg1160_data }, 327 { "BSG2150", (unsigned long)&bsg2150_data }, 328 { "INT3515", (unsigned long)&int3515_data }, 329 { "CSC3551", (unsigned long)&cs35l41_hda }, 330 /* Non-conforming _HID for Cirrus Logic already released */ 331 { "CLSA0100", (unsigned long)&cs35l41_hda }, 332 { } 333}; 334MODULE_DEVICE_TABLE(acpi, smi_acpi_ids); 335 336static struct platform_driver smi_driver = { 337 .driver = { 338 .name = "Serial bus multi instantiate pseudo device driver", 339 .acpi_match_table = smi_acpi_ids, 340 }, 341 .probe = smi_probe, 342 .remove = smi_remove, 343}; 344module_platform_driver(smi_driver); 345 346MODULE_DESCRIPTION("Serial multi instantiate pseudo device driver"); 347MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 348MODULE_LICENSE("GPL");