Skip to content

Commit 68f201f

Browse files
Stefan Bindingjwrdegoede
authored andcommitted
platform/x86: serial-multi-instantiate: Add SPI support
Add support for spi bus in serial-multi-instantiate driver Some peripherals can have either a I2C or a SPI connection to the host (but not both) but use the same HID for both types. So it is not possible to use the HID to determine whether it is I2C or SPI. The driver must check the node to see if it contains I2cSerialBus or SpiSerialBus entries. For backwards-compatibility with the existing nodes I2C is checked first and if such entries are found ONLY I2C devices are created. Since some existing nodes that were already handled by this driver could also contain unrelated SpiSerialBus nodes that were previously ignored, and this preserves that behavior. If there is ever a need to handle a node where both I2C and SPI devices must be instantiated this can be added in future. Signed-off-by: Stefan Binding <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Hans de Goede <[email protected]> Signed-off-by: Hans de Goede <[email protected]>
1 parent 35a36cb commit 68f201f

File tree

2 files changed

+150
-25
lines changed

2 files changed

+150
-25
lines changed

drivers/platform/x86/Kconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -992,7 +992,7 @@ config TOPSTAR_LAPTOP
992992

993993
config SERIAL_MULTI_INSTANTIATE
994994
tristate "Serial bus multi instantiate pseudo device driver"
995-
depends on I2C && ACPI
995+
depends on I2C && SPI && ACPI
996996
help
997997
Some ACPI-based systems list multiple devices in a single ACPI
998998
firmware-node. This driver will instantiate separate clients

drivers/platform/x86/serial-multi-instantiate.c

Lines changed: 149 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,22 +14,36 @@
1414
#include <linux/module.h>
1515
#include <linux/platform_device.h>
1616
#include <linux/property.h>
17+
#include <linux/spi/spi.h>
1718
#include <linux/types.h>
1819

1920
#define IRQ_RESOURCE_TYPE GENMASK(1, 0)
2021
#define IRQ_RESOURCE_NONE 0
2122
#define IRQ_RESOURCE_GPIO 1
2223
#define IRQ_RESOURCE_APIC 2
2324

25+
enum smi_bus_type {
26+
SMI_I2C,
27+
SMI_SPI,
28+
SMI_AUTO_DETECT,
29+
};
30+
2431
struct smi_instance {
2532
const char *type;
2633
unsigned int flags;
2734
int irq_idx;
2835
};
2936

37+
struct smi_node {
38+
enum smi_bus_type bus_type;
39+
struct smi_instance instances[];
40+
};
41+
3042
struct smi {
3143
int i2c_num;
44+
int spi_num;
3245
struct i2c_client **i2c_devs;
46+
struct spi_device **spi_devs;
3347
};
3448

3549
static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev,
@@ -59,6 +73,94 @@ static void smi_devs_unregister(struct smi *smi)
5973
{
6074
while (smi->i2c_num > 0)
6175
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+
*/
90+
static 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;
160+
error:
161+
smi_devs_unregister(smi);
162+
163+
return ret;
62164
}
63165

64166
/**
@@ -126,17 +228,17 @@ static int smi_i2c_probe(struct platform_device *pdev, struct acpi_device *adev,
126228

127229
static int smi_probe(struct platform_device *pdev)
128230
{
129-
const struct smi_instance *inst_array;
130231
struct device *dev = &pdev->dev;
232+
const struct smi_node *node;
131233
struct acpi_device *adev;
132234
struct smi *smi;
133235

134236
adev = ACPI_COMPANION(dev);
135237
if (!adev)
136238
return -ENODEV;
137239

138-
inst_array = device_get_match_data(dev);
139-
if (!inst_array) {
240+
node = device_get_match_data(dev);
241+
if (!node) {
140242
dev_dbg(dev, "Error ACPI match data is missing\n");
141243
return -ENODEV;
142244
}
@@ -147,7 +249,21 @@ static int smi_probe(struct platform_device *pdev)
147249

148250
platform_set_drvdata(pdev, smi);
149251

150-
return smi_i2c_probe(pdev, adev, smi, inst_array);
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 */
151267
}
152268

153269
static int smi_remove(struct platform_device *pdev)
@@ -159,37 +275,46 @@ static int smi_remove(struct platform_device *pdev)
159275
return 0;
160276
}
161277

162-
static const struct smi_instance bsg1160_data[] = {
163-
{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
164-
{ "bmc150_magn" },
165-
{ "bmg160" },
166-
{}
278+
static 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,
167286
};
168287

169-
static const struct smi_instance bsg2150_data[] = {
170-
{ "bmc150_accel", IRQ_RESOURCE_GPIO, 0 },
171-
{ "bmc150_magn" },
172-
/* The resources describe a 3th client, but it is not really there. */
173-
{ "bsg2150_dummy_dev" },
174-
{}
288+
static 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,
175297
};
176298

177-
static const struct smi_instance int3515_data[] = {
178-
{ "tps6598x", IRQ_RESOURCE_APIC, 0 },
179-
{ "tps6598x", IRQ_RESOURCE_APIC, 1 },
180-
{ "tps6598x", IRQ_RESOURCE_APIC, 2 },
181-
{ "tps6598x", IRQ_RESOURCE_APIC, 3 },
182-
{}
299+
static 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,
183308
};
184309

185310
/*
186311
* Note new device-ids must also be added to ignore_serial_bus_ids in
187312
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
188313
*/
189314
static const struct acpi_device_id smi_acpi_ids[] = {
190-
{ "BSG1160", (unsigned long)bsg1160_data },
191-
{ "BSG2150", (unsigned long)bsg2150_data },
192-
{ "INT3515", (unsigned long)int3515_data },
315+
{ "BSG1160", (unsigned long)&bsg1160_data },
316+
{ "BSG2150", (unsigned long)&bsg2150_data },
317+
{ "INT3515", (unsigned long)&int3515_data },
193318
{ }
194319
};
195320
MODULE_DEVICE_TABLE(acpi, smi_acpi_ids);

0 commit comments

Comments
 (0)