diff options
Diffstat (limited to 'drivers/spi/spi.c')
-rw-r--r-- | drivers/spi/spi.c | 183 |
1 files changed, 157 insertions, 26 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 7bb733d91519..c3f6b524b3ce 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -80,7 +80,7 @@ static ssize_t spi_master_##field##_show(struct device *dev, \ return spi_statistics_##field##_show(&master->statistics, buf); \ } \ static struct device_attribute dev_attr_spi_master_##field = { \ - .attr = { .name = file, .mode = S_IRUGO }, \ + .attr = { .name = file, .mode = 0444 }, \ .show = spi_master_##field##_show, \ }; \ static ssize_t spi_device_##field##_show(struct device *dev, \ @@ -91,7 +91,7 @@ static ssize_t spi_device_##field##_show(struct device *dev, \ return spi_statistics_##field##_show(&spi->statistics, buf); \ } \ static struct device_attribute dev_attr_spi_device_##field = { \ - .attr = { .name = file, .mode = S_IRUGO }, \ + .attr = { .name = file, .mode = 0444 }, \ .show = spi_device_##field##_show, \ } @@ -1535,15 +1535,6 @@ static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi, u32 value; int rc; - /* Device address */ - rc = of_property_read_u32(nc, "reg", &value); - if (rc) { - dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", - nc->full_name, rc); - return rc; - } - spi->chip_select = value; - /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; @@ -1593,6 +1584,24 @@ static int of_spi_parse_dt(struct spi_master *master, struct spi_device *spi, } } + if (spi_controller_is_slave(master)) { + if (strcmp(nc->name, "slave")) { + dev_err(&master->dev, "%s is not called 'slave'\n", + nc->full_name); + return -EINVAL; + } + return 0; + } + + /* Device address */ + rc = of_property_read_u32(nc, "reg", &value); + if (rc) { + dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n", + nc->full_name, rc); + return rc; + } + spi->chip_select = value; + /* Device speed */ rc = of_property_read_u32(nc, "spi-max-frequency", &value); if (rc) { @@ -1658,8 +1667,8 @@ err_out: * of_register_spi_devices() - Register child devices onto the SPI bus * @master: Pointer to spi_master device * - * Registers an spi_device for each child node of master node which has a 'reg' - * property. + * Registers an spi_device for each child node of controller node which + * represents a valid SPI slave. */ static void of_register_spi_devices(struct spi_master *master) { @@ -1828,28 +1837,129 @@ static struct class spi_master_class = { .dev_groups = spi_master_groups, }; +#ifdef CONFIG_SPI_SLAVE +/** + * spi_slave_abort - abort the ongoing transfer request on an SPI slave + * controller + * @spi: device used for the current transfer + */ +int spi_slave_abort(struct spi_device *spi) +{ + struct spi_master *master = spi->master; + + if (spi_controller_is_slave(master) && master->slave_abort) + return master->slave_abort(master); + + return -ENOTSUPP; +} +EXPORT_SYMBOL_GPL(spi_slave_abort); + +static int match_true(struct device *dev, void *data) +{ + return 1; +} + +static ssize_t spi_slave_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct spi_master *ctlr = container_of(dev, struct spi_master, dev); + struct device *child; + + child = device_find_child(&ctlr->dev, NULL, match_true); + return sprintf(buf, "%s\n", + child ? to_spi_device(child)->modalias : NULL); +} + +static ssize_t spi_slave_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct spi_master *ctlr = container_of(dev, struct spi_master, dev); + struct spi_device *spi; + struct device *child; + char name[32]; + int rc; + + rc = sscanf(buf, "%31s", name); + if (rc != 1 || !name[0]) + return -EINVAL; + + child = device_find_child(&ctlr->dev, NULL, match_true); + if (child) { + /* Remove registered slave */ + device_unregister(child); + put_device(child); + } + + if (strcmp(name, "(null)")) { + /* Register new slave */ + spi = spi_alloc_device(ctlr); + if (!spi) + return -ENOMEM; + + strlcpy(spi->modalias, name, sizeof(spi->modalias)); + + rc = spi_add_device(spi); + if (rc) { + spi_dev_put(spi); + return rc; + } + } + + return count; +} + +static DEVICE_ATTR(slave, 0644, spi_slave_show, spi_slave_store); + +static struct attribute *spi_slave_attrs[] = { + &dev_attr_slave.attr, + NULL, +}; + +static const struct attribute_group spi_slave_group = { + .attrs = spi_slave_attrs, +}; + +static const struct attribute_group *spi_slave_groups[] = { + &spi_master_statistics_group, + &spi_slave_group, + NULL, +}; + +static struct class spi_slave_class = { + .name = "spi_slave", + .owner = THIS_MODULE, + .dev_release = spi_master_release, + .dev_groups = spi_slave_groups, +}; +#else +extern struct class spi_slave_class; /* dummy */ +#endif /** - * spi_alloc_master - allocate SPI master controller + * __spi_alloc_controller - allocate an SPI master or slave controller * @dev: the controller, possibly using the platform_bus * @size: how much zeroed driver-private data to allocate; the pointer to this * memory is in the driver_data field of the returned device, * accessible with spi_master_get_devdata(). + * @slave: flag indicating whether to allocate an SPI master (false) or SPI + * slave (true) controller * Context: can sleep * - * This call is used only by SPI master controller drivers, which are the + * This call is used only by SPI controller drivers, which are the * only ones directly touching chip registers. It's how they allocate * an spi_master structure, prior to calling spi_register_master(). * * This must be called from context that can sleep. * - * The caller is responsible for assigning the bus number and initializing - * the master's methods before calling spi_register_master(); and (after errors + * The caller is responsible for assigning the bus number and initializing the + * controller's methods before calling spi_register_master(); and (after errors * adding the device) calling spi_master_put() to prevent a memory leak. * - * Return: the SPI master structure on success, else NULL. + * Return: the SPI controller structure on success, else NULL. */ -struct spi_master *spi_alloc_master(struct device *dev, unsigned size) +struct spi_master *__spi_alloc_controller(struct device *dev, + unsigned int size, bool slave) { struct spi_master *master; @@ -1863,14 +1973,18 @@ struct spi_master *spi_alloc_master(struct device *dev, unsigned size) device_initialize(&master->dev); master->bus_num = -1; master->num_chipselect = 1; - master->dev.class = &spi_master_class; + master->slave = slave; + if (IS_ENABLED(CONFIG_SPI_SLAVE) && slave) + master->dev.class = &spi_slave_class; + else + master->dev.class = &spi_master_class; master->dev.parent = dev; pm_suspend_ignore_children(&master->dev, true); spi_master_set_devdata(master, &master[1]); return master; } -EXPORT_SYMBOL_GPL(spi_alloc_master); +EXPORT_SYMBOL_GPL(__spi_alloc_controller); #ifdef CONFIG_OF static int of_spi_register_master(struct spi_master *master) @@ -1946,9 +2060,11 @@ int spi_register_master(struct spi_master *master) if (!dev) return -ENODEV; - status = of_spi_register_master(master); - if (status) - return status; + if (!spi_controller_is_slave(master)) { + status = of_spi_register_master(master); + if (status) + return status; + } /* even if it's just one always-selected device, there must * be at least one chipselect @@ -1985,8 +2101,9 @@ int spi_register_master(struct spi_master *master) status = device_add(&master->dev); if (status < 0) goto done; - dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev), - dynamic ? " (dynamic)" : ""); + dev_dbg(dev, "registered %s %s%s\n", + spi_controller_is_slave(master) ? "slave" : "master", + dev_name(&master->dev), dynamic ? " (dynamic)" : ""); /* If we're using a queued driver, start the queue */ if (master->transfer) @@ -3159,6 +3276,9 @@ static struct spi_master *of_find_spi_master_by_node(struct device_node *node) dev = class_find_device(&spi_master_class, NULL, node, __spi_of_master_match); + if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE)) + dev = class_find_device(&spi_slave_class, NULL, node, + __spi_of_master_match); if (!dev) return NULL; @@ -3240,6 +3360,9 @@ static struct spi_master *acpi_spi_find_master_by_adev(struct acpi_device *adev) dev = class_find_device(&spi_master_class, NULL, adev, spi_acpi_master_match); + if (!dev && IS_ENABLED(CONFIG_SPI_SLAVE)) + dev = class_find_device(&spi_slave_class, NULL, adev, + spi_acpi_master_match); if (!dev) return NULL; @@ -3312,6 +3435,12 @@ static int __init spi_init(void) if (status < 0) goto err2; + if (IS_ENABLED(CONFIG_SPI_SLAVE)) { + status = class_register(&spi_slave_class); + if (status < 0) + goto err3; + } + if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_register(&spi_of_notifier)); if (IS_ENABLED(CONFIG_ACPI)) @@ -3319,6 +3448,8 @@ static int __init spi_init(void) return 0; +err3: + class_unregister(&spi_master_class); err2: bus_unregister(&spi_bus_type); err1: |