xref: /linux/drivers/platform/x86/serial-multi-instantiate.c (revision 3a39d672e7f48b8d6b91a09afa4b55352773b4b5)
15e63b2eaSLucas Tanure // SPDX-License-Identifier: GPL-2.0+
25e63b2eaSLucas Tanure /*
35e63b2eaSLucas Tanure  * Serial multi-instantiate driver, pseudo driver to instantiate multiple
45e63b2eaSLucas Tanure  * client devices from a single fwnode.
55e63b2eaSLucas Tanure  *
65e63b2eaSLucas Tanure  * Copyright 2018 Hans de Goede <hdegoede@redhat.com>
75e63b2eaSLucas Tanure  */
85e63b2eaSLucas Tanure 
95e63b2eaSLucas Tanure #include <linux/acpi.h>
105e63b2eaSLucas Tanure #include <linux/bits.h>
115e63b2eaSLucas Tanure #include <linux/i2c.h>
125e63b2eaSLucas Tanure #include <linux/interrupt.h>
135e63b2eaSLucas Tanure #include <linux/kernel.h>
145e63b2eaSLucas Tanure #include <linux/module.h>
155e63b2eaSLucas Tanure #include <linux/platform_device.h>
165e63b2eaSLucas Tanure #include <linux/property.h>
1768f201f9SStefan Binding #include <linux/spi/spi.h>
185e63b2eaSLucas Tanure #include <linux/types.h>
195e63b2eaSLucas Tanure 
205e63b2eaSLucas Tanure #define IRQ_RESOURCE_TYPE	GENMASK(1, 0)
215e63b2eaSLucas Tanure #define IRQ_RESOURCE_NONE	0
225e63b2eaSLucas Tanure #define IRQ_RESOURCE_GPIO	1
235e63b2eaSLucas Tanure #define IRQ_RESOURCE_APIC	2
24676b7c5eSDavid Xu #define IRQ_RESOURCE_AUTO   3
255e63b2eaSLucas Tanure 
2668f201f9SStefan Binding enum smi_bus_type {
2768f201f9SStefan Binding 	SMI_I2C,
2868f201f9SStefan Binding 	SMI_SPI,
2968f201f9SStefan Binding 	SMI_AUTO_DETECT,
3068f201f9SStefan Binding };
3168f201f9SStefan Binding 
325e63b2eaSLucas Tanure struct smi_instance {
335e63b2eaSLucas Tanure 	const char *type;
345e63b2eaSLucas Tanure 	unsigned int flags;
355e63b2eaSLucas Tanure 	int irq_idx;
365e63b2eaSLucas Tanure };
375e63b2eaSLucas Tanure 
3868f201f9SStefan Binding struct smi_node {
3968f201f9SStefan Binding 	enum smi_bus_type bus_type;
4068f201f9SStefan Binding 	struct smi_instance instances[];
4168f201f9SStefan Binding };
4268f201f9SStefan Binding 
435e63b2eaSLucas Tanure struct smi {
445e63b2eaSLucas Tanure 	int i2c_num;
4568f201f9SStefan Binding 	int spi_num;
4635a36cbbSLucas Tanure 	struct i2c_client **i2c_devs;
4768f201f9SStefan Binding 	struct spi_device **spi_devs;
485e63b2eaSLucas Tanure };
495e63b2eaSLucas Tanure 
smi_get_irq(struct platform_device * pdev,struct acpi_device * adev,const struct smi_instance * inst)5035a36cbbSLucas Tanure static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev,
5135a36cbbSLucas Tanure 		       const struct smi_instance *inst)
525e63b2eaSLucas Tanure {
5335a36cbbSLucas Tanure 	int ret;
545e63b2eaSLucas Tanure 
5535a36cbbSLucas Tanure 	switch (inst->flags & IRQ_RESOURCE_TYPE) {
56676b7c5eSDavid Xu 	case IRQ_RESOURCE_AUTO:
57676b7c5eSDavid Xu 		ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx);
58676b7c5eSDavid Xu 		if (ret > 0) {
59676b7c5eSDavid Xu 			dev_dbg(&pdev->dev, "Using gpio irq\n");
60676b7c5eSDavid Xu 			break;
61676b7c5eSDavid Xu 		}
62676b7c5eSDavid Xu 		ret = platform_get_irq(pdev, inst->irq_idx);
63676b7c5eSDavid Xu 		if (ret > 0) {
64676b7c5eSDavid Xu 			dev_dbg(&pdev->dev, "Using platform irq\n");
65676b7c5eSDavid Xu 			break;
66676b7c5eSDavid Xu 		}
67676b7c5eSDavid Xu 		break;
6835a36cbbSLucas Tanure 	case IRQ_RESOURCE_GPIO:
6935a36cbbSLucas Tanure 		ret = acpi_dev_gpio_irq_get(adev, inst->irq_idx);
7035a36cbbSLucas Tanure 		break;
7135a36cbbSLucas Tanure 	case IRQ_RESOURCE_APIC:
7235a36cbbSLucas Tanure 		ret = platform_get_irq(pdev, inst->irq_idx);
7335a36cbbSLucas Tanure 		break;
7435a36cbbSLucas Tanure 	default:
7535a36cbbSLucas Tanure 		return 0;
765e63b2eaSLucas Tanure 	}
7735a36cbbSLucas Tanure 	if (ret < 0)
7814a9aa99SAndy Shevchenko 		return dev_err_probe(&pdev->dev, ret, "Error requesting irq at index %d\n",
7914a9aa99SAndy Shevchenko 				     inst->irq_idx);
805e63b2eaSLucas Tanure 
8135a36cbbSLucas Tanure 	return ret;
8235a36cbbSLucas Tanure }
8335a36cbbSLucas Tanure 
smi_devs_unregister(struct smi * smi)8435a36cbbSLucas Tanure static void smi_devs_unregister(struct smi *smi)
8535a36cbbSLucas Tanure {
86*3900c6abSRichard Fitzgerald #if IS_REACHABLE(CONFIG_I2C)
87ed7adc2bSAndy Shevchenko 	while (smi->i2c_num--)
88ed7adc2bSAndy Shevchenko 		i2c_unregister_device(smi->i2c_devs[smi->i2c_num]);
89*3900c6abSRichard Fitzgerald #endif
9068f201f9SStefan Binding 
91*3900c6abSRichard Fitzgerald 	if (IS_REACHABLE(CONFIG_SPI)) {
92ed7adc2bSAndy Shevchenko 		while (smi->spi_num--)
93ed7adc2bSAndy Shevchenko 			spi_unregister_device(smi->spi_devs[smi->spi_num]);
9468f201f9SStefan Binding 	}
95*3900c6abSRichard Fitzgerald }
9668f201f9SStefan Binding 
9768f201f9SStefan Binding /**
9868f201f9SStefan Binding  * smi_spi_probe - Instantiate multiple SPI devices from inst array
9968f201f9SStefan Binding  * @pdev:	Platform device
10068f201f9SStefan Binding  * @smi:	Internal struct for Serial multi instantiate driver
10168f201f9SStefan Binding  * @inst_array:	Array of instances to probe
10268f201f9SStefan Binding  *
10368f201f9SStefan Binding  * Returns the number of SPI devices instantiate, Zero if none is found or a negative error code.
10468f201f9SStefan Binding  */
smi_spi_probe(struct platform_device * pdev,struct smi * smi,const struct smi_instance * inst_array)1058b50c48dSAndy Shevchenko static int smi_spi_probe(struct platform_device *pdev, struct smi *smi,
10668f201f9SStefan Binding 			 const struct smi_instance *inst_array)
10768f201f9SStefan Binding {
10868f201f9SStefan Binding 	struct device *dev = &pdev->dev;
1098b50c48dSAndy Shevchenko 	struct acpi_device *adev = ACPI_COMPANION(dev);
11068f201f9SStefan Binding 	struct spi_controller *ctlr;
11168f201f9SStefan Binding 	struct spi_device *spi_dev;
11268f201f9SStefan Binding 	char name[50];
11368f201f9SStefan Binding 	int i, ret, count;
11468f201f9SStefan Binding 
11568f201f9SStefan Binding 	ret = acpi_spi_count_resources(adev);
11668f201f9SStefan Binding 	if (ret < 0)
11768f201f9SStefan Binding 		return ret;
118f3e13bbcSAndy Shevchenko 	if (!ret)
1192b5b2782SAndy Shevchenko 		return -ENOENT;
12068f201f9SStefan Binding 
12168f201f9SStefan Binding 	count = ret;
12268f201f9SStefan Binding 
12368f201f9SStefan Binding 	smi->spi_devs = devm_kcalloc(dev, count, sizeof(*smi->spi_devs), GFP_KERNEL);
12468f201f9SStefan Binding 	if (!smi->spi_devs)
12568f201f9SStefan Binding 		return -ENOMEM;
12668f201f9SStefan Binding 
12768f201f9SStefan Binding 	for (i = 0; i < count && inst_array[i].type; i++) {
12868f201f9SStefan Binding 
12968f201f9SStefan Binding 		spi_dev = acpi_spi_device_alloc(NULL, adev, i);
13068f201f9SStefan Binding 		if (IS_ERR(spi_dev)) {
13114a9aa99SAndy Shevchenko 			ret = dev_err_probe(dev, PTR_ERR(spi_dev), "failed to allocate SPI device %s from ACPI\n",
13214a9aa99SAndy Shevchenko 					    dev_name(&adev->dev));
13368f201f9SStefan Binding 			goto error;
13468f201f9SStefan Binding 		}
13568f201f9SStefan Binding 
13668f201f9SStefan Binding 		ctlr = spi_dev->controller;
13768f201f9SStefan Binding 
1389a3291e9SAndy Shevchenko 		strscpy(spi_dev->modalias, inst_array[i].type);
13968f201f9SStefan Binding 
14068f201f9SStefan Binding 		ret = smi_get_irq(pdev, adev, &inst_array[i]);
14168f201f9SStefan Binding 		if (ret < 0) {
14268f201f9SStefan Binding 			spi_dev_put(spi_dev);
14368f201f9SStefan Binding 			goto error;
14468f201f9SStefan Binding 		}
14568f201f9SStefan Binding 		spi_dev->irq = ret;
14668f201f9SStefan Binding 
14768f201f9SStefan Binding 		snprintf(name, sizeof(name), "%s-%s-%s.%d", dev_name(&ctlr->dev), dev_name(dev),
14868f201f9SStefan Binding 			 inst_array[i].type, i);
14968f201f9SStefan Binding 		spi_dev->dev.init_name = name;
15068f201f9SStefan Binding 
15168f201f9SStefan Binding 		ret = spi_add_device(spi_dev);
15268f201f9SStefan Binding 		if (ret) {
15314a9aa99SAndy Shevchenko 			dev_err_probe(&ctlr->dev, ret, "failed to add SPI device %s from ACPI\n",
15414a9aa99SAndy Shevchenko 				      dev_name(&adev->dev));
15568f201f9SStefan Binding 			spi_dev_put(spi_dev);
15668f201f9SStefan Binding 			goto error;
15768f201f9SStefan Binding 		}
15868f201f9SStefan Binding 
159e20451f4SAmit Kumar Mahapatra via Alsa-devel 		dev_dbg(dev, "SPI device %s using chip select %u", name,
160e20451f4SAmit Kumar Mahapatra via Alsa-devel 			spi_get_chipselect(spi_dev, 0));
16168f201f9SStefan Binding 
16268f201f9SStefan Binding 		smi->spi_devs[i] = spi_dev;
16368f201f9SStefan Binding 		smi->spi_num++;
16468f201f9SStefan Binding 	}
16568f201f9SStefan Binding 
16668f201f9SStefan Binding 	if (smi->spi_num < count) {
16768f201f9SStefan Binding 		dev_dbg(dev, "Error finding driver, idx %d\n", i);
16868f201f9SStefan Binding 		ret = -ENODEV;
16968f201f9SStefan Binding 		goto error;
17068f201f9SStefan Binding 	}
17168f201f9SStefan Binding 
17268f201f9SStefan Binding 	dev_info(dev, "Instantiated %d SPI devices.\n", smi->spi_num);
17368f201f9SStefan Binding 
17468f201f9SStefan Binding 	return 0;
17568f201f9SStefan Binding error:
17668f201f9SStefan Binding 	smi_devs_unregister(smi);
17768f201f9SStefan Binding 
17868f201f9SStefan Binding 	return ret;
17935a36cbbSLucas Tanure }
18035a36cbbSLucas Tanure 
18135a36cbbSLucas Tanure /**
18235a36cbbSLucas Tanure  * smi_i2c_probe - Instantiate multiple I2C devices from inst array
18335a36cbbSLucas Tanure  * @pdev:	Platform device
18435a36cbbSLucas Tanure  * @smi:	Internal struct for Serial multi instantiate driver
18535a36cbbSLucas Tanure  * @inst_array:	Array of instances to probe
18635a36cbbSLucas Tanure  *
18735a36cbbSLucas Tanure  * Returns the number of I2C devices instantiate, Zero if none is found or a negative error code.
18835a36cbbSLucas Tanure  */
smi_i2c_probe(struct platform_device * pdev,struct smi * smi,const struct smi_instance * inst_array)1898b50c48dSAndy Shevchenko static int smi_i2c_probe(struct platform_device *pdev, struct smi *smi,
19035a36cbbSLucas Tanure 			 const struct smi_instance *inst_array)
19135a36cbbSLucas Tanure {
19235a36cbbSLucas Tanure 	struct i2c_board_info board_info = {};
19335a36cbbSLucas Tanure 	struct device *dev = &pdev->dev;
1948b50c48dSAndy Shevchenko 	struct acpi_device *adev = ACPI_COMPANION(dev);
19535a36cbbSLucas Tanure 	char name[32];
19635a36cbbSLucas Tanure 	int i, ret, count;
19735a36cbbSLucas Tanure 
1985e63b2eaSLucas Tanure 	ret = i2c_acpi_client_count(adev);
1995e63b2eaSLucas Tanure 	if (ret < 0)
2005e63b2eaSLucas Tanure 		return ret;
201f3e13bbcSAndy Shevchenko 	if (!ret)
2022b5b2782SAndy Shevchenko 		return -ENOENT;
2035e63b2eaSLucas Tanure 
20435a36cbbSLucas Tanure 	count = ret;
20535a36cbbSLucas Tanure 
20635a36cbbSLucas Tanure 	smi->i2c_devs = devm_kcalloc(dev, count, sizeof(*smi->i2c_devs), GFP_KERNEL);
20735a36cbbSLucas Tanure 	if (!smi->i2c_devs)
2085e63b2eaSLucas Tanure 		return -ENOMEM;
2095e63b2eaSLucas Tanure 
21035a36cbbSLucas Tanure 	for (i = 0; i < count && inst_array[i].type; i++) {
2115e63b2eaSLucas Tanure 		memset(&board_info, 0, sizeof(board_info));
2129a3291e9SAndy Shevchenko 		strscpy(board_info.type, inst_array[i].type);
21335a36cbbSLucas Tanure 		snprintf(name, sizeof(name), "%s-%s.%d", dev_name(dev), inst_array[i].type, i);
2145e63b2eaSLucas Tanure 		board_info.dev_name = name;
21535a36cbbSLucas Tanure 
21635a36cbbSLucas Tanure 		ret = smi_get_irq(pdev, adev, &inst_array[i]);
21735a36cbbSLucas Tanure 		if (ret < 0)
2185e63b2eaSLucas Tanure 			goto error;
2195e63b2eaSLucas Tanure 		board_info.irq = ret;
22035a36cbbSLucas Tanure 
2215e63b2eaSLucas Tanure 		smi->i2c_devs[i] = i2c_acpi_new_device(dev, i, &board_info);
2225e63b2eaSLucas Tanure 		if (IS_ERR(smi->i2c_devs[i])) {
2235e63b2eaSLucas Tanure 			ret = dev_err_probe(dev, PTR_ERR(smi->i2c_devs[i]),
2245e63b2eaSLucas Tanure 					    "Error creating i2c-client, idx %d\n", i);
2255e63b2eaSLucas Tanure 			goto error;
2265e63b2eaSLucas Tanure 		}
22735a36cbbSLucas Tanure 		smi->i2c_num++;
2285e63b2eaSLucas Tanure 	}
22935a36cbbSLucas Tanure 	if (smi->i2c_num < count) {
23035a36cbbSLucas Tanure 		dev_dbg(dev, "Error finding driver, idx %d\n", i);
2315e63b2eaSLucas Tanure 		ret = -ENODEV;
2325e63b2eaSLucas Tanure 		goto error;
2335e63b2eaSLucas Tanure 	}
2345e63b2eaSLucas Tanure 
23535a36cbbSLucas Tanure 	dev_info(dev, "Instantiated %d I2C devices.\n", smi->i2c_num);
2365e63b2eaSLucas Tanure 
23735a36cbbSLucas Tanure 	return 0;
2385e63b2eaSLucas Tanure error:
23935a36cbbSLucas Tanure 	smi_devs_unregister(smi);
2405e63b2eaSLucas Tanure 
2415e63b2eaSLucas Tanure 	return ret;
2425e63b2eaSLucas Tanure }
2435e63b2eaSLucas Tanure 
smi_probe(struct platform_device * pdev)24435a36cbbSLucas Tanure static int smi_probe(struct platform_device *pdev)
24535a36cbbSLucas Tanure {
24635a36cbbSLucas Tanure 	struct device *dev = &pdev->dev;
24768f201f9SStefan Binding 	const struct smi_node *node;
24835a36cbbSLucas Tanure 	struct smi *smi;
2492b5b2782SAndy Shevchenko 	int ret;
25035a36cbbSLucas Tanure 
25168f201f9SStefan Binding 	node = device_get_match_data(dev);
25268f201f9SStefan Binding 	if (!node) {
25335a36cbbSLucas Tanure 		dev_dbg(dev, "Error ACPI match data is missing\n");
25435a36cbbSLucas Tanure 		return -ENODEV;
25535a36cbbSLucas Tanure 	}
25635a36cbbSLucas Tanure 
25735a36cbbSLucas Tanure 	smi = devm_kzalloc(dev, sizeof(*smi), GFP_KERNEL);
25835a36cbbSLucas Tanure 	if (!smi)
25935a36cbbSLucas Tanure 		return -ENOMEM;
26035a36cbbSLucas Tanure 
26135a36cbbSLucas Tanure 	platform_set_drvdata(pdev, smi);
26235a36cbbSLucas Tanure 
26368f201f9SStefan Binding 	switch (node->bus_type) {
26468f201f9SStefan Binding 	case SMI_I2C:
265*3900c6abSRichard Fitzgerald 		if (IS_REACHABLE(CONFIG_I2C))
2668b50c48dSAndy Shevchenko 			return smi_i2c_probe(pdev, smi, node->instances);
267*3900c6abSRichard Fitzgerald 
268*3900c6abSRichard Fitzgerald 		return -ENODEV;
26968f201f9SStefan Binding 	case SMI_SPI:
270*3900c6abSRichard Fitzgerald 		if (IS_REACHABLE(CONFIG_SPI))
2718b50c48dSAndy Shevchenko 			return smi_spi_probe(pdev, smi, node->instances);
272*3900c6abSRichard Fitzgerald 
273*3900c6abSRichard Fitzgerald 		return -ENODEV;
27468f201f9SStefan Binding 	case SMI_AUTO_DETECT:
2752b5b2782SAndy Shevchenko 		/*
2762b5b2782SAndy Shevchenko 		 * For backwards-compatibility with the existing nodes I2C
2772b5b2782SAndy Shevchenko 		 * is checked first and if such entries are found ONLY I2C
2782b5b2782SAndy Shevchenko 		 * devices are created. Since some existing nodes that were
2792b5b2782SAndy Shevchenko 		 * already handled by this driver could also contain unrelated
2802b5b2782SAndy Shevchenko 		 * SpiSerialBus nodes that were previously ignored, and this
2812b5b2782SAndy Shevchenko 		 * preserves that behavior.
2822b5b2782SAndy Shevchenko 		 */
283*3900c6abSRichard Fitzgerald 		if (IS_REACHABLE(CONFIG_I2C)) {
2848b50c48dSAndy Shevchenko 			ret = smi_i2c_probe(pdev, smi, node->instances);
2852b5b2782SAndy Shevchenko 			if (ret != -ENOENT)
2862b5b2782SAndy Shevchenko 				return ret;
287*3900c6abSRichard Fitzgerald 		}
288*3900c6abSRichard Fitzgerald 
289*3900c6abSRichard Fitzgerald 		if (IS_REACHABLE(CONFIG_SPI))
2908b50c48dSAndy Shevchenko 			return smi_spi_probe(pdev, smi, node->instances);
291*3900c6abSRichard Fitzgerald 
292*3900c6abSRichard Fitzgerald 		return -ENODEV;
29368f201f9SStefan Binding 	default:
29468f201f9SStefan Binding 		return -EINVAL;
29568f201f9SStefan Binding 	}
29635a36cbbSLucas Tanure }
29735a36cbbSLucas Tanure 
smi_remove(struct platform_device * pdev)298143b3c1aSUwe Kleine-König static void smi_remove(struct platform_device *pdev)
2995e63b2eaSLucas Tanure {
3005e63b2eaSLucas Tanure 	struct smi *smi = platform_get_drvdata(pdev);
3015e63b2eaSLucas Tanure 
30235a36cbbSLucas Tanure 	smi_devs_unregister(smi);
3035e63b2eaSLucas Tanure }
3045e63b2eaSLucas Tanure 
30568f201f9SStefan Binding static const struct smi_node bsg1160_data = {
30668f201f9SStefan Binding 	.instances = {
3075e63b2eaSLucas Tanure 		{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
3085e63b2eaSLucas Tanure 		{ "bmc150_magn" },
3095e63b2eaSLucas Tanure 		{ "bmg160" },
3105e63b2eaSLucas Tanure 		{}
31168f201f9SStefan Binding 	},
31268f201f9SStefan Binding 	.bus_type = SMI_I2C,
3135e63b2eaSLucas Tanure };
3145e63b2eaSLucas Tanure 
31568f201f9SStefan Binding static const struct smi_node bsg2150_data = {
31668f201f9SStefan Binding 	.instances = {
3175e63b2eaSLucas Tanure 		{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
3185e63b2eaSLucas Tanure 		{ "bmc150_magn" },
3195e63b2eaSLucas Tanure 		/* The resources describe a 3th client, but it is not really there. */
3205e63b2eaSLucas Tanure 		{ "bsg2150_dummy_dev" },
3215e63b2eaSLucas Tanure 		{}
32268f201f9SStefan Binding 	},
32368f201f9SStefan Binding 	.bus_type = SMI_I2C,
3245e63b2eaSLucas Tanure };
3255e63b2eaSLucas Tanure 
32668f201f9SStefan Binding static const struct smi_node int3515_data = {
32768f201f9SStefan Binding 	.instances = {
3285e63b2eaSLucas Tanure 		{ "tps6598x", IRQ_RESOURCE_APIC, 0 },
3295e63b2eaSLucas Tanure 		{ "tps6598x", IRQ_RESOURCE_APIC, 1 },
3305e63b2eaSLucas Tanure 		{ "tps6598x", IRQ_RESOURCE_APIC, 2 },
3315e63b2eaSLucas Tanure 		{ "tps6598x", IRQ_RESOURCE_APIC, 3 },
3325e63b2eaSLucas Tanure 		{}
33368f201f9SStefan Binding 	},
33468f201f9SStefan Binding 	.bus_type = SMI_I2C,
3355e63b2eaSLucas Tanure };
3365e63b2eaSLucas Tanure 
337d9c01c53SLucas Tanure static const struct smi_node cs35l41_hda = {
338d9c01c53SLucas Tanure 	.instances = {
339676b7c5eSDavid Xu 		{ "cs35l41-hda", IRQ_RESOURCE_AUTO, 0 },
340676b7c5eSDavid Xu 		{ "cs35l41-hda", IRQ_RESOURCE_AUTO, 0 },
341676b7c5eSDavid Xu 		{ "cs35l41-hda", IRQ_RESOURCE_AUTO, 0 },
342676b7c5eSDavid Xu 		{ "cs35l41-hda", IRQ_RESOURCE_AUTO, 0 },
343d9c01c53SLucas Tanure 		{}
344d9c01c53SLucas Tanure 	},
345d9c01c53SLucas Tanure 	.bus_type = SMI_AUTO_DETECT,
346d9c01c53SLucas Tanure };
347d9c01c53SLucas Tanure 
3486fa9ba2dSSimon Trimmer static const struct smi_node cs35l54_hda = {
3496fa9ba2dSSimon Trimmer 	.instances = {
3506fa9ba2dSSimon Trimmer 		{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
3516fa9ba2dSSimon Trimmer 		{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
3526fa9ba2dSSimon Trimmer 		{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
3536fa9ba2dSSimon Trimmer 		{ "cs35l54-hda", IRQ_RESOURCE_AUTO, 0 },
3546fa9ba2dSSimon Trimmer 		/* a 5th entry is an alias address, not a real device */
3556fa9ba2dSSimon Trimmer 		{ "cs35l54-hda_dummy_dev" },
3566fa9ba2dSSimon Trimmer 		{}
3576fa9ba2dSSimon Trimmer 	},
3586fa9ba2dSSimon Trimmer 	.bus_type = SMI_AUTO_DETECT,
3596fa9ba2dSSimon Trimmer };
3606fa9ba2dSSimon Trimmer 
3611cd0302bSSimon Trimmer static const struct smi_node cs35l56_hda = {
3621cd0302bSSimon Trimmer 	.instances = {
3631cd0302bSSimon Trimmer 		{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
3641cd0302bSSimon Trimmer 		{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
3651cd0302bSSimon Trimmer 		{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
3661cd0302bSSimon Trimmer 		{ "cs35l56-hda", IRQ_RESOURCE_AUTO, 0 },
3671cd0302bSSimon Trimmer 		/* a 5th entry is an alias address, not a real device */
3681cd0302bSSimon Trimmer 		{ "cs35l56-hda_dummy_dev" },
3691cd0302bSSimon Trimmer 		{}
3701cd0302bSSimon Trimmer 	},
3711cd0302bSSimon Trimmer 	.bus_type = SMI_AUTO_DETECT,
3721cd0302bSSimon Trimmer };
3731cd0302bSSimon Trimmer 
3746fa9ba2dSSimon Trimmer static const struct smi_node cs35l57_hda = {
3756fa9ba2dSSimon Trimmer 	.instances = {
3766fa9ba2dSSimon Trimmer 		{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
3776fa9ba2dSSimon Trimmer 		{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
3786fa9ba2dSSimon Trimmer 		{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
3796fa9ba2dSSimon Trimmer 		{ "cs35l57-hda", IRQ_RESOURCE_AUTO, 0 },
3806fa9ba2dSSimon Trimmer 		/* a 5th entry is an alias address, not a real device */
3816fa9ba2dSSimon Trimmer 		{ "cs35l57-hda_dummy_dev" },
3826fa9ba2dSSimon Trimmer 		{}
3836fa9ba2dSSimon Trimmer 	},
3846fa9ba2dSSimon Trimmer 	.bus_type = SMI_AUTO_DETECT,
3856fa9ba2dSSimon Trimmer };
3866fa9ba2dSSimon Trimmer 
3875e63b2eaSLucas Tanure /*
3885e63b2eaSLucas Tanure  * Note new device-ids must also be added to ignore_serial_bus_ids in
3895e63b2eaSLucas Tanure  * drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
3905e63b2eaSLucas Tanure  */
3915e63b2eaSLucas Tanure static const struct acpi_device_id smi_acpi_ids[] = {
39268f201f9SStefan Binding 	{ "BSG1160", (unsigned long)&bsg1160_data },
39368f201f9SStefan Binding 	{ "BSG2150", (unsigned long)&bsg2150_data },
394d9c01c53SLucas Tanure 	{ "CSC3551", (unsigned long)&cs35l41_hda },
3956fa9ba2dSSimon Trimmer 	{ "CSC3554", (unsigned long)&cs35l54_hda },
3961cd0302bSSimon Trimmer 	{ "CSC3556", (unsigned long)&cs35l56_hda },
3976fa9ba2dSSimon Trimmer 	{ "CSC3557", (unsigned long)&cs35l57_hda },
398e286044bSAndy Shevchenko 	{ "INT3515", (unsigned long)&int3515_data },
399d9c01c53SLucas Tanure 	/* Non-conforming _HID for Cirrus Logic already released */
400d9c01c53SLucas Tanure 	{ "CLSA0100", (unsigned long)&cs35l41_hda },
40188392a0dSLucas Tanure 	{ "CLSA0101", (unsigned long)&cs35l41_hda },
4025e63b2eaSLucas Tanure 	{ }
4035e63b2eaSLucas Tanure };
4045e63b2eaSLucas Tanure MODULE_DEVICE_TABLE(acpi, smi_acpi_ids);
4055e63b2eaSLucas Tanure 
4065e63b2eaSLucas Tanure static struct platform_driver smi_driver = {
4075e63b2eaSLucas Tanure 	.driver	= {
4085e63b2eaSLucas Tanure 		.name = "Serial bus multi instantiate pseudo device driver",
4095e63b2eaSLucas Tanure 		.acpi_match_table = smi_acpi_ids,
4105e63b2eaSLucas Tanure 	},
4115e63b2eaSLucas Tanure 	.probe = smi_probe,
412143b3c1aSUwe Kleine-König 	.remove_new = smi_remove,
4135e63b2eaSLucas Tanure };
4145e63b2eaSLucas Tanure module_platform_driver(smi_driver);
4155e63b2eaSLucas Tanure 
4165e63b2eaSLucas Tanure MODULE_DESCRIPTION("Serial multi instantiate pseudo device driver");
4175e63b2eaSLucas Tanure MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
4185e63b2eaSLucas Tanure MODULE_LICENSE("GPL");
419