I have been a bit hesitant to reiterate the series, but this is anyways a v1 of the 96Boards Mezzanine Low Speed connector driver framework.
I know the boards have a high speed connector as well, just trying to work stepwise and do the simple things first.
What convinced me to continue was very real usecases that exist today, as this makes the secure96 Mezzanine work:
- Get something upstream that makes it possible to without any trouble or extensive ugly hacking probe and use the secure96 mezzanine. This is motivated by the IoT design space which needs a way to plug in proper security and the secure96 offers a TPM chip for root of trust and key handling.
- A clear indication that the same approach will work just as fine with ACPI without reinventing the universe. I do not have a definitive proof of this, but it is more plausible that this will be reusable for ACPI than any of the DT-centric ideas I've seen for populating daughterboards. There are 96boards using ACPI today. A secure96 TPM is desireable for things like the ARM developer box which has this LS connector: https://www.96boards.org/product/developerbox/
- Some indication that binding the connector like this will not implicate or screw things up for the DT-overlays idea, i.e. a both/and and not either/or approach.
The idea is for this to go upstream through ARM SoC the day noone actively NACK it and someone actively ACK it. Expect some more iterations.
Linus Walleij (4): eeprom: at24: Allow passing gpiodesc from pdata spi: Make of_find_spi_device_by_node() available bus: Add DT bindings for 96Boards low speed connector bus: 96boards Low-Speed Connector
.../bus/96boards,low-speed-connector.txt | 50 +++ drivers/bus/Kconfig | 2 + drivers/bus/Makefile | 4 +- drivers/bus/daughterboards/96boards-ls-bus.c | 39 ++ .../daughterboards/96boards-ls-connector.c | 367 ++++++++++++++++++ .../bus/daughterboards/96boards-mezzanines.h | 77 ++++ .../bus/daughterboards/96boards-secure96.c | 265 +++++++++++++ drivers/bus/daughterboards/Kconfig | 50 +++ drivers/bus/daughterboards/Makefile | 6 + drivers/misc/eeprom/at24.c | 6 +- drivers/spi/spi.c | 33 +- include/linux/platform_data/at24.h | 2 + include/linux/spi/spi.h | 4 + 13 files changed, 888 insertions(+), 17 deletions(-) create mode 100644 Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt create mode 100644 drivers/bus/daughterboards/96boards-ls-bus.c create mode 100644 drivers/bus/daughterboards/96boards-ls-connector.c create mode 100644 drivers/bus/daughterboards/96boards-mezzanines.h create mode 100644 drivers/bus/daughterboards/96boards-secure96.c create mode 100644 drivers/bus/daughterboards/Kconfig create mode 100644 drivers/bus/daughterboards/Makefile
This makes it possible to pass an initialized GPIO descriptor to the driver through platform data.
This is useful when we are dealing with EEPROMs on expansion boards where the GPIO has to be looked up indirectly using a connector abstraction (several systems using the same connector) so the machine descriptor tables cannot be used to associate the descriptor with the device and we then want to pass this descriptor on to the EEPROM driver this way instead.
Cc: Bartosz Golaszewski brgl@bgdev.pl Cc: linux-i2c@vger.kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog v1->v2: - No changes - Requesting an ACK from the EEPROM maintainer (Bartosz) so we can apply this to the ARM SoC tree with the series depending on it. --- drivers/misc/eeprom/at24.c | 6 +++++- include/linux/platform_data/at24.h | 2 ++ 2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index f5cc517d1131..d577cdbe221e 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -662,7 +662,11 @@ static int at24_probe(struct i2c_client *client) at24->client[0].client = client; at24->client[0].regmap = regmap;
- at24->wp_gpio = devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH); + if (pdata.wp_gpiod) + at24->wp_gpio = pdata.wp_gpiod; + else + at24->wp_gpio = + devm_gpiod_get_optional(dev, "wp", GPIOD_OUT_HIGH); if (IS_ERR(at24->wp_gpio)) return PTR_ERR(at24->wp_gpio);
diff --git a/include/linux/platform_data/at24.h b/include/linux/platform_data/at24.h index 63507ff464ee..5606fb2ef76c 100644 --- a/include/linux/platform_data/at24.h +++ b/include/linux/platform_data/at24.h @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/nvmem-consumer.h> #include <linux/bitops.h> +#include <linux/gpio/consumer.h>
/** * struct at24_platform_data - data to set up at24 (generic eeprom) driver @@ -55,6 +56,7 @@ struct at24_platform_data {
void (*setup)(struct nvmem_device *nvmem, void *context); void *context; + struct gpio_desc *wp_gpiod; };
#endif /* _LINUX_AT24_H */
2018-08-23 12:33 GMT+02:00 Linus Walleij linus.walleij@linaro.org:
This makes it possible to pass an initialized GPIO descriptor to the driver through platform data.
This is useful when we are dealing with EEPROMs on expansion boards where the GPIO has to be looked up indirectly using a connector abstraction (several systems using the same connector) so the machine descriptor tables cannot be used to associate the descriptor with the device and we then want to pass this descriptor on to the EEPROM driver this way instead.
Ugh I don't like this at all. In fact I'm right now trying to *get rid* of platform_data from at24 in favor of device properties[1].
Part of the changes from my series actually removes the setup function from at24 and replaces it with a notifier fired by the nvmem framework.
I would really prefer that we introduce some generic way of handling write-protect mechanisms in nvmem. Maybe starting by moving the wp_gpio to nvmem and then passing it in nvmem_config?
Best regards, Bartosz Golaszewski
This externalizes and exports the symbol of_find_spi_device_by_node() from the SPI core akin to how of_find_i2c_adapter_by_node() is already available. As we will need this also for non-dynamic OF setups, we move it under a CONFIG_OF check.
Cc: Mark Brown broonie@kernel.org Cc: linux-spi@vger.kernel.org Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog RFC->v1: - No changes - Requesting an ACK from the SPI mainatiner so that this patch can be applied with the rest of the series. --- drivers/spi/spi.c | 33 ++++++++++++++++++--------------- include/linux/spi/spi.h | 4 ++++ 2 files changed, 22 insertions(+), 15 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ec395a6baf9c..6a1085077317 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -3314,27 +3314,14 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
-#if IS_ENABLED(CONFIG_OF_DYNAMIC) -static int __spi_of_device_match(struct device *dev, void *data) -{ - return dev->of_node == data; -} - -/* must call put_device() when done with returned spi_device device */ -static struct spi_device *of_find_spi_device_by_node(struct device_node *node) -{ - struct device *dev = bus_find_device(&spi_bus_type, NULL, node, - __spi_of_device_match); - return dev ? to_spi_device(dev) : NULL; -} - +#if IS_ENABLED(CONFIG_OF) static int __spi_of_controller_match(struct device *dev, const void *data) { return dev->of_node == data; }
/* the spi controllers are not using spi_bus, so we find it with another way */ -static struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) +struct spi_controller *of_find_spi_controller_by_node(struct device_node *node) { struct device *dev;
@@ -3349,6 +3336,22 @@ static struct spi_controller *of_find_spi_controller_by_node(struct device_node /* reference got in class_find_device */ return container_of(dev, struct spi_controller, dev); } +EXPORT_SYMBOL_GPL(of_find_spi_controller_by_node); +#endif + +#if IS_ENABLED(CONFIG_OF_DYNAMIC) +static int __spi_of_device_match(struct device *dev, void *data) +{ + return dev->of_node == data; +} + +/* must call put_device() when done with returned spi_device device */ +static struct spi_device *of_find_spi_device_by_node(struct device_node *node) +{ + struct device *dev = bus_find_device(&spi_bus_type, NULL, node, + __spi_of_device_match); + return dev ? to_spi_device(dev) : NULL; +}
static int of_spi_notify(struct notifier_block *nb, unsigned long action, void *arg) diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index a64235e05321..c2be93224bd1 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -639,6 +639,10 @@ extern int devm_spi_register_controller(struct device *dev, struct spi_controller *ctlr); extern void spi_unregister_controller(struct spi_controller *ctlr);
+#if IS_ENABLED(CONFIG_OF) +struct spi_controller *of_find_spi_controller_by_node(struct device_node *node); +#endif + extern struct spi_controller *spi_busnum_to_master(u16 busnum);
/*
We need to be able to grab resources on a 96Boards low speed connector to populate and use a daughterboard, so define some very rudimentary properties simply passing phandles for the resources used on the low speed connector.
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- .../bus/96boards,low-speed-connector.txt | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt
diff --git a/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt b/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt new file mode 100644 index 000000000000..6631b3edd01f --- /dev/null +++ b/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt @@ -0,0 +1,50 @@ +96Boards Low Speed Connectors + +The 96Boards connectors represent a non-dicoverable Low Speed (LS) +and High Speed (HS) external bus on the 96Board development +boards. Each 96Board presents both of these connectors. + +The Low Speed (LS) connector is a 40 pin 2x20 female pin header: +- Power +- Two buttons: power and reset +- 2 x UART one optional with just RX/TX, one required with modem + CTS/RTS +- 2 x I2C +- 1 x SPI +- 1 x I2S (audio) +- 12 x GPIO lines named GPIO-A thru GPIO-L + +Further details on the electronics and signals are available in +"96Boards Consumer Edition, Low Cost Hardware Platform Specification" +As of writing version 1.0, January 2015. + +Required properties: + +- compatible: shall be "96boards,low-speed-connector" +- i2c0: phandle to the I2C0 bus +- i2c1: phandle to the I2C1 bus +- spi: phandle to the SPI bus +- gpios: a list of phandles to the GPIOs connected to the + connector. The handles need to be uniformly specified with the + 0 flag as the connector is not the end consumer. + +Example: + +lscon: connector { + compatible = "96boards,low-speed-connector"; + i2c0 = <&i2csw_0>; + i2c1 = <&i2csw_1>; + spi = <&spi0>; + gpios = <&gpio 36 0>, /* GPIO-A */ + <&gpio 37 0>, /* GPIO-B */ + <&gpio 39 0>, /* GPIO-C */ + <&gpio 40 0>, /* GPIO-D */ + <&gpio 44 0>, /* GPIO-E */ + <&gpio 45 0>, /* GPIO-F */ + <&gpio 78 0>, /* GPIO-G */ + <&gpio 79 0>, /* GPIO-H */ + <&gpio 80 0>, /* GPIO-I */ + <&gpio 81 0>, /* GPIO-J */ + <&gpio 82 0>, /* GPIO-K */ + <&gpio 83 0>; /* GPIO-L */ +};
On Thu, Aug 23, 2018 at 5:33 AM Linus Walleij linus.walleij@linaro.org wrote:
We need to be able to grab resources on a 96Boards low speed connector to populate and use a daughterboard, so define some very rudimentary properties simply passing phandles for the resources used on the low speed connector.
This only works for describing what's on the connector, but does nothing for describing downstream devices on the connector. We already have a way to do the former with label properties at least for uart, i2c and spi. And gpio has it's own method of labeling lines.
Signed-off-by: Linus Walleij linus.walleij@linaro.org
.../bus/96boards,low-speed-connector.txt | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt
diff --git a/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt b/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt new file mode 100644 index 000000000000..6631b3edd01f --- /dev/null +++ b/Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt @@ -0,0 +1,50 @@ +96Boards Low Speed Connectors
+The 96Boards connectors represent a non-dicoverable Low Speed (LS) +and High Speed (HS) external bus on the 96Board development +boards. Each 96Board presents both of these connectors.
+The Low Speed (LS) connector is a 40 pin 2x20 female pin header: +- Power +- Two buttons: power and reset +- 2 x UART one optional with just RX/TX, one required with modem
- CTS/RTS
+- 2 x I2C +- 1 x SPI +- 1 x I2S (audio) +- 12 x GPIO lines named GPIO-A thru GPIO-L
+Further details on the electronics and signals are available in +"96Boards Consumer Edition, Low Cost Hardware Platform Specification" +As of writing version 1.0, January 2015.
+Required properties:
+- compatible: shall be "96boards,low-speed-connector" +- i2c0: phandle to the I2C0 bus +- i2c1: phandle to the I2C1 bus +- spi: phandle to the SPI bus +- gpios: a list of phandles to the GPIOs connected to the
- connector. The handles need to be uniformly specified with the
- 0 flag as the connector is not the end consumer.
+Example:
+lscon: connector {
compatible = "96boards,low-speed-connector";
i2c0 = <&i2csw_0>;
i2c1 = <&i2csw_1>;
spi = <&spi0>;
David G has suggested using aliases (in this node, not top-level) for this purpose of mapping things like spi and i2c, and I think that's a good use of aliases (versus spi and i2c aliases at the top level which I don't). The hard part is still how to structure the child devices.
gpios = <&gpio 36 0>, /* GPIO-A */
We defined 'gpio-map' specifically for handling GPIOs thru connectors. It's in the DT spec (though not a released version yet). Use it here.
Sorry, but the only halfway solution I'm going to accept is one which can evolve into a full solution. Define the basic structure and add each interface one by one. Maybe that starts with just:
lscon: connector { compatible = "96boards,low-speed-connector"; };
That's not really my recommendation as that's really just kicking the can down the road.
Rob
On Thu, Aug 23, 2018 at 3:46 PM Rob Herring robh+dt@kernel.org wrote:
On Thu, Aug 23, 2018 at 5:33 AM Linus Walleij linus.walleij@linaro.org wrote:
We need to be able to grab resources on a 96Boards low speed connector to populate and use a daughterboard, so define some very rudimentary properties simply passing phandles for the resources used on the low speed connector.
This only works for describing what's on the connector, but does nothing for describing downstream devices on the connector. We already have a way to do the former with label properties at least for uart, i2c and spi. And gpio has it's own method of labeling lines.
This is on purpose as the downstream daughterboards are described by C code rather than DT. The idea is to use the same for ACPI rather than DSDT.
+lscon: connector {
compatible = "96boards,low-speed-connector";
i2c0 = <&i2csw_0>;
i2c1 = <&i2csw_1>;
spi = <&spi0>;
David G has suggested using aliases (in this node, not top-level) for this purpose of mapping things like spi and i2c, and I think that's a good use of aliases (versus spi and i2c aliases at the top level which I don't). The hard part is still how to structure the child devices.
Sorry, I am just too ignorant about the semantic difference between a phandle and an alias. As long as I can follow it to get a handle on the device node I'm happy, aliases are fine I guess.
The specification says:
"The phandle property specifies a numerical identifier for a node that is unique within the devicetree. The phandle property value is used by other nodes that need to refer to the node associated with the property."
Numerical? Hm.
The aliases are very vague and seem to not be really specified. Not in the DT spec at least. And that is not in line with how the Linux kernel DTs uses aliases anyway, it seems.
Syntactically they look like so:
aliases { serial0 = &uart1; };
phandles { serial0 = <&uart1>; };
Not a big difference.
In your opinion, what constitues the semantic meaning of an alias vs a phandle?
gpios = <&gpio 36 0>, /* GPIO-A */
We defined 'gpio-map' specifically for handling GPIOs thru connectors. It's in the DT spec (though not a released version yet). Use it here.
We have code for it (by Stephen Boyd) which works and I tested it even, it works fine!
But it is not intended for what I do here. It shares the ambition to define all devices in the daughterboard using DT, so there must be a consuming node, on the daughterboard, using my-gpios = <&connector 0>; and we are back at overlays. There is no way for a connector driver to grab a GPIO from the GPIO map, the map is just a cross-reference, not resource provider.
Maybe I could let the connector say that it's using GPIOs from itself? I can take a stab at that. It will look weird but it's allright I guess.
Sorry, but the only halfway solution I'm going to accept is one which can evolve into a full solution. Define the basic structure and add each interface one by one.
Maybe that starts with just:
lscon: connector { compatible = "96boards,low-speed-connector"; };
I suspect "full solution" in the above paragraph means full DT overlays, and ACPI systems are none of your concern in this context?
A halfway solution is what I am trying to do, because the walking all the way down the road means we run into the imperialistic ambitions of both DT and ACPI DSDT to describe the whole system using just DT or just ACPI DSDT.
As mentioned, we have today the developer box that is using ACPI, and the other 96Boards using mostly DT.
Which currently means similar support code twice for these (simple) mezzanines, then author and support overlays in both HW description languages.
Like with the fwnode rework that is going on in parallel, in my view it is really necessary for both DT and ACPI to take a step back and stop being so imperialistic. It seems they are both living under the assumption that they do not really need to care about the other HW description language, and it is stifling development. Maybe this view is too harsh, I am sometimes also just thinking inside my little box :(
My current plan is to develop the code in the patch set using fwnode where possible so that I have a proof of concept of the same mezzanine population code being used for DT and ACPI alike. It works for GPIOs, but phandles or aliases are going to be a challenge.
Yours, Linus Walleij
This creates a bus for using a small connector driver to plug in "mezzanine boards" on the 96boards low-speed connector either by a very simple compatible string for the entire board, or by simply inserting the board device from userspace.
These "mezzanine boards" are no different than "capes", "logic modules", etc. This thing, a non-discoverable connector where a user can plug in a few peripherals has been reinvented a few times.
As a proof-of-concept we add the Secure96, a quite minimal mezzanine board.
Users can register their boards in a simple way. Either just add their compatible-string in the device tree:
board { compatible = "96boards,secure96"; };
And if they can't even change three lines in their device tree, or if they at runtime decide to plug in some board and test it, they can use sysfs, as exemplified by plugging in the secure96 security board at runtime:
cd /sys/bus/96boards-ls-connector-bus cat supported
secure96
echo secure96 > inject
[ 61.014629] lscon connector: called mezzanine_store on secure96 [ 61.020530] lscon connector: populate secure96 [ 61.027081] at24 1-0050: 2048 byte 24c128 EEPROM, writable, 128 bytes/write [ 61.053569] atmel-ecc 1-0060: configuration zone is unlocked [ 61.502535] tpm_tis_spi spi0.0: 2.0 TPM (device-id 0x1B, rev-id 16) (...)
The plug-in board can be removed from sysfs and added back again multiple times like this with the devices being runtime added and removed by two writes to sysfs.
echo secure96 > eject echo secure96 > inject echo secure96 > eject
(...)
Signed-off-by: Linus Walleij linus.walleij@linaro.org --- ChangeLog RFC->v1: - Create a new bus type as recommended by Arnd, fixing a bunch of scalability issues and making the whole thing look like most other kernel device driver cores. - Create LS connector devices that have .probe() and .remove() functions like any other device. - Move dynamic device creation to bus attribute files. --- drivers/bus/Kconfig | 2 + drivers/bus/Makefile | 4 +- drivers/bus/daughterboards/96boards-ls-bus.c | 39 ++ .../daughterboards/96boards-ls-connector.c | 367 ++++++++++++++++++ .../bus/daughterboards/96boards-mezzanines.h | 77 ++++ .../bus/daughterboards/96boards-secure96.c | 265 +++++++++++++ drivers/bus/daughterboards/Kconfig | 50 +++ drivers/bus/daughterboards/Makefile | 6 + 8 files changed, 809 insertions(+), 1 deletion(-) create mode 100644 drivers/bus/daughterboards/96boards-ls-bus.c create mode 100644 drivers/bus/daughterboards/96boards-ls-connector.c create mode 100644 drivers/bus/daughterboards/96boards-mezzanines.h create mode 100644 drivers/bus/daughterboards/96boards-secure96.c create mode 100644 drivers/bus/daughterboards/Kconfig create mode 100644 drivers/bus/daughterboards/Makefile
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig index d1c0b60e9326..98393c6e2190 100644 --- a/drivers/bus/Kconfig +++ b/drivers/bus/Kconfig @@ -173,4 +173,6 @@ config DA8XX_MSTPRI
source "drivers/bus/fsl-mc/Kconfig"
+source "drivers/bus/daughterboards/Kconfig" + endmenu diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile index b8f036cca7ff..7a792e3e2cc2 100644 --- a/drivers/bus/Makefile +++ b/drivers/bus/Makefile @@ -29,5 +29,7 @@ obj-$(CONFIG_TI_SYSC) += ti-sysc.o obj-$(CONFIG_TS_NBUS) += ts-nbus.o obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o - obj-$(CONFIG_DA8XX_MSTPRI) += da8xx-mstpri.o + +# Non-discoverable daughterboards +obj-$(CONFIG_DAUGHTERBOARDS) += daughterboards/ diff --git a/drivers/bus/daughterboards/96boards-ls-bus.c b/drivers/bus/daughterboards/96boards-ls-bus.c new file mode 100644 index 000000000000..23de06b3fce3 --- /dev/null +++ b/drivers/bus/daughterboards/96boards-ls-bus.c @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 96boards Low-speed Connector bus initialization + * (C) 2018 Linus Walleij linus.walleij@linaro.org + */ +#include <linux/device.h> +#include <linux/init.h> +#include <linux/of_platform.h> +#include "96boards-mezzanines.h" + +static int ls_match(struct device *dev, struct device_driver *drv) +{ + /* First match on OF node */ + if (of_driver_match_device(dev, drv)) + return 1; + + /* Second match on name */ + return !strcmp(dev_name(dev), drv->name); +} + +struct bus_type ls_bus_type = { + .name = "96boards-ls-connector-bus", + .match = ls_match, +}; +EXPORT_SYMBOL_GPL(ls_bus_type); + +static int __init ls_bus_init(void) +{ + int ret; + + /* Register the LS connector bus so devices can start to probe */ + ret = bus_register(&ls_bus_type); + if (ret) { + pr_err("could not register LS connector bus\n"); + return ret; + } + return 0; +} +postcore_initcall(ls_bus_init); diff --git a/drivers/bus/daughterboards/96boards-ls-connector.c b/drivers/bus/daughterboards/96boards-ls-connector.c new file mode 100644 index 000000000000..5c958f47b23e --- /dev/null +++ b/drivers/bus/daughterboards/96boards-ls-connector.c @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 96boards Low-speed Connector driver + * (C) 2018 Linus Walleij linus.walleij@linaro.org + */ +#include <linux/device.h> +#include <linux/init.h> +#include <linux/sysfs.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/idr.h> +#include "96boards-mezzanines.h" + +static DEFINE_IDA(ls_device_ida); + +static int ls_driver_probe(struct device *dev) +{ + struct ls_device *lsdev = to_ls_device(dev); + struct ls_driver *lsdrv = to_ls_driver(dev->driver); + + if (lsdrv->probe) + return lsdrv->probe(lsdev); + return 0; +} + +static int ls_driver_remove(struct device *dev) +{ + struct ls_device *lsdev = to_ls_device(dev); + struct ls_driver *lsdrv = to_ls_driver(dev->driver); + + if (lsdrv->remove) + lsdrv->remove(lsdev); + return 0; +} + +int ls_driver_register(struct ls_driver *lsdrv) +{ + lsdrv->drv.bus = &ls_bus_type; + lsdrv->drv.probe = ls_driver_probe; + lsdrv->drv.remove = ls_driver_remove; + + return driver_register(&lsdrv->drv); +} +EXPORT_SYMBOL_GPL(ls_driver_register); + +void ls_driver_unregister(struct ls_driver *lsdrv) +{ + driver_unregister(&lsdrv->drv); +} +EXPORT_SYMBOL_GPL(ls_driver_unregister); + +struct gpio_desc *ls_get_gpiod(struct ls_device *ls, + enum ls_gpio pin, + const char *consumer_name, + enum gpiod_flags flags) +{ + struct gpio_desc *retdesc; + + /* + * TODO: get all the LS GPIOs as an array on probe() then + * the consumers can skip error handling of IS_ERR() descriptors + * and this need only set the consumer name. + */ + retdesc = devm_gpiod_get_index(ls->dev.parent, NULL, pin, flags); + if (!IS_ERR(retdesc) && consumer_name) + gpiod_set_consumer_name(retdesc, consumer_name); + + return retdesc; +} +EXPORT_SYMBOL_GPL(ls_get_gpiod); + +/* + * Mezzanine boards will call this to orderly remove their claimed + * gpio descriptors, since we acquired them all with devm_gpiod_get() + * they will eventually be released once this connector device + * disappears if the board do not release them in order. + */ +void ls_put_gpiod(struct ls_device *ls, struct gpio_desc *gpiod) +{ + devm_gpiod_put(ls->dev.parent, gpiod); +} +EXPORT_SYMBOL_GPL(ls_put_gpiod); + +static int lscon_add_device(struct ls_connector *ls, + const char *name, + struct device_node *np) +{ + struct ls_device *lsdev; + int ret; + + lsdev = kzalloc(sizeof(*lsdev), GFP_KERNEL); + if (!lsdev) + return -ENOMEM; + + lsdev->id = ida_simple_get(&ls_device_ida, 0, 0, GFP_KERNEL); + if (lsdev->id < 0) + return lsdev->id; + lsdev->dev.bus = &ls_bus_type; + lsdev->dev.of_node = np; + lsdev->dev.parent = ls->dev; + /* Propagate resources to the device */ + lsdev->i2c0 = ls->i2c0; + lsdev->i2c1 = ls->i2c1; + lsdev->spi = ls->spi; + /* + * In /sys/bus/96boards-ls-connector-bus/devices/ we find + * mezzanine0, mezzanine1 etc OR the device name if inserted + * from userspace. + */ + if (name) + dev_set_name(&lsdev->dev, "%s", name); + else + dev_set_name(&lsdev->dev, "mezzanine%d", lsdev->id); + device_initialize(&lsdev->dev); + ret = device_add(&lsdev->dev); + if (ret) { + dev_err(ls->dev, "failed to add device %s\n", + dev_name(&lsdev->dev)); + return ret; + } + + return 0; +} + +static void lscon_del_device(struct ls_device *lsdev) +{ + device_del(&lsdev->dev); + ida_simple_remove(&ls_device_ida, lsdev->id); + kfree(lsdev); +} + +struct ls_supported_buf { + char *buf; + size_t count; +}; + +static int ls_supported_print(struct device_driver *drv, void *data) +{ + struct ls_supported_buf *buf = data; + size_t count; + + count = snprintf(buf->buf + buf->count, + PAGE_SIZE, "%s\n", drv->name); + buf->count += count; + return 0; +} + +static ssize_t ls_supported_show(struct bus_type *bus, char *buf) +{ + struct ls_supported_buf sbuf; + + /* Loop over the driver list and show supported devices */ + sbuf.buf = buf; + sbuf.count = 0; + bus_for_each_drv(&ls_bus_type, NULL, &sbuf, ls_supported_print); + + return sbuf.count; +} + +static BUS_ATTR(supported, 0444, ls_supported_show, NULL); + +/* + * Match the supplied string to a driver name, if we find + * a match we return 1, saying this device is elegible for + * insertion. + */ +static int ls_inject_match(struct device_driver *drv, void *data) +{ + const char *devname = data; + + if (!strcmp(devname, drv->name)) + return 1; + return 0; +} + +static ssize_t ls_inject_store(struct bus_type *bus, + const char *buf, size_t count) +{ + struct device *dev = ls_bus_type.dev_root; + struct ls_connector *ls = dev_get_drvdata(dev); + char *devname; + int ret; + + devname = kstrdup(buf, GFP_KERNEL); + devname = strstrip(devname); + /* Look if we have a driver for this device */ + ret = bus_for_each_drv(&ls_bus_type, NULL, devname, ls_inject_match); + if (!ret) { + kfree(devname); + return count; + } + + dev_info(ls->dev, "create %s device\n", devname); + /* + * No corresponding DT node + * + * TODO: when we have device tree overlays, this is a good + * place to start when inserting dynamic devices. + */ + lscon_add_device(ls, devname, NULL); + + kfree(devname); + return count; +} + +static BUS_ATTR(inject, 0644, NULL, ls_inject_store); + +static ssize_t ls_eject_store(struct bus_type *bus, + const char *buf, size_t count) +{ + struct device *busdev = ls_bus_type.dev_root; + struct ls_connector *ls = dev_get_drvdata(busdev); + struct ls_device *lsdev; + struct device *dev; + char *devname; + + devname = kstrdup(buf, GFP_KERNEL); + devname = strstrip(devname); + /* Look if we have this device */ + dev = bus_find_device_by_name(&ls_bus_type, NULL, devname); + if (!dev) { + kfree(devname); + return count; + } + + dev_info(ls->dev, "destroy %s device\n", devname); + + lsdev = to_ls_device(dev); + lscon_del_device(lsdev); + kfree(devname); + + return count; +} + +static BUS_ATTR(eject, 0644, NULL, ls_eject_store); + +static int lscon_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct device_node *child; + struct spi_controller *spi; + struct ls_connector *ls; + int ret; + + ls = devm_kzalloc(dev, sizeof(*ls), GFP_KERNEL); + if (!ls) + return -ENOMEM; + ls->dev = dev; + + /* Bridge I2C busses */ + child = of_parse_phandle(np, "i2c0", 0); + if (!child) { + dev_err(dev, "no i2c0 phandle\n"); + return -ENODEV; + } + ls->i2c0 = of_get_i2c_adapter_by_node(child); + if (!ls->i2c0) { + dev_err(dev, "no i2c0 adapter, deferring\n"); + return -EPROBE_DEFER; + } + + child = of_parse_phandle(np, "i2c1", 0); + if (!child) { + dev_err(dev, "no i2c1 phandle\n"); + ret = -ENODEV; + goto out_put_i2c0; + } + ls->i2c1 = of_get_i2c_adapter_by_node(child); + if (!ls->i2c1) { + dev_err(dev, "no i2c0 adapter, deferring\n"); + ret = -EPROBE_DEFER; + goto out_put_i2c0; + } + + /* Bridge SPI bus */ + child = of_parse_phandle(np, "spi", 0); + if (!child) { + dev_err(dev, "no spi phandle\n"); + ret = -ENODEV; + goto out_put_i2c1; + } + spi = of_find_spi_controller_by_node(child); + if (!spi) { + dev_err(dev, "no spi controller, deferring\n"); + ret = -EPROBE_DEFER; + goto out_put_i2c1; + } + ls->spi = spi_controller_get(spi); + if (!ls->spi) { + dev_err(dev, "no spi reference\n"); + ret = -ENODEV; + goto out_put_i2c1; + } + + platform_set_drvdata(pdev, ls); + + ls_bus_type.dev_root = dev; + ret = bus_create_file(&ls_bus_type, &bus_attr_supported); + if (ret) + goto out_put_i2c1; + ret = bus_create_file(&ls_bus_type, &bus_attr_inject); + if (ret) + goto out_put_i2c1; + ret = bus_create_file(&ls_bus_type, &bus_attr_eject); + if (ret) + goto out_put_i2c1; + + /* + * Add mezzanine boards as children, stacking possible. + * All direct children of the LS connector will be considered + * mezzanines. + */ + for_each_available_child_of_node(np, child) + lscon_add_device(ls, NULL, child); + + return 0; + +out_put_i2c1: + i2c_put_adapter(ls->i2c1); +out_put_i2c0: + i2c_put_adapter(ls->i2c0); + return ret; +} + +static int lscon_del_dev(struct device *dev, void *data) +{ + struct ls_device *lsdev = to_ls_device(dev); + + lscon_del_device(lsdev); + return 0; +} + +static int lscon_remove(struct platform_device *pdev) +{ + struct ls_connector *ls = platform_get_drvdata(pdev); + + /* Make sure we remove any registered devices */ + bus_for_each_dev(&ls_bus_type, NULL, NULL, lscon_del_dev); + + ls_bus_type.dev_root = NULL; + spi_controller_put(ls->spi); + i2c_put_adapter(ls->i2c1); + i2c_put_adapter(ls->i2c0); + + return 0; +} + +static const struct of_device_id lscon_of_match[] = { + { + .compatible = "96boards,low-speed-connector", + }, + { }, +}; + +static struct platform_driver lscon_driver = { + .driver = { + .name = "lscon", + .of_match_table = of_match_ptr(lscon_of_match), + }, + .probe = lscon_probe, + .remove = lscon_remove, +}; +builtin_platform_driver(lscon_driver); diff --git a/drivers/bus/daughterboards/96boards-mezzanines.h b/drivers/bus/daughterboards/96boards-mezzanines.h new file mode 100644 index 000000000000..93d2c6c910ed --- /dev/null +++ b/drivers/bus/daughterboards/96boards-mezzanines.h @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/device.h> +#include <linux/of.h> +#include <linux/i2c.h> +#include <linux/gpio/consumer.h> + +/** + * enum ls_gpio - the GPIO lines on the low-speed connector + */ +enum ls_gpio { + LS_GPIO_A = 0, + LS_GPIO_B, + LS_GPIO_C, + LS_GPIO_D, + LS_GPIO_E, + LS_GPIO_F, + LS_GPIO_G, + LS_GPIO_H, + LS_GPIO_I, + LS_GPIO_J, + LS_GPIO_K, + LS_GPIO_L, +}; + +/* + * We try to use the most simplistic device model: here is the LS + * connector, it is a custom bus with its own type of devices and drivers + * on it. + */ + +extern struct bus_type ls_bus_type; + +/** + * struct ls_connector - the connector per se + * @dev: parent device (platform device in the device tree case) + * @i2c0: upward i2c0 I2C bus + * @i2c1: upward i2c1 I2C bus + * @spi: upward SPI bus + */ +struct ls_connector { + struct device *dev; + struct i2c_adapter *i2c0; + struct i2c_adapter *i2c1; + struct spi_controller *spi; +}; + +struct ls_device { + struct device dev; + const char *compatible; + int id; + struct i2c_adapter *i2c0; + struct i2c_adapter *i2c1; + struct spi_controller *spi; +}; + +struct ls_driver { + struct device_driver drv; + struct dev_ext_attribute ext_attr; + int (*probe)(struct ls_device *); + void (*remove)(struct ls_device *); +}; + +#define to_ls_device(d) \ + container_of(d, struct ls_device, dev) +#define to_ls_driver(d) \ + container_of(d, struct ls_driver, drv) + +extern int ls_driver_register(struct ls_driver *); +extern void ls_driver_unregister(struct ls_driver *); + +struct gpio_desc *ls_get_gpiod(struct ls_device *ls, + enum ls_gpio pin, + const char *consumer_name, + enum gpiod_flags flags); +void ls_put_gpiod(struct ls_device *ls, + struct gpio_desc *gpiod); diff --git a/drivers/bus/daughterboards/96boards-secure96.c b/drivers/bus/daughterboards/96boards-secure96.c new file mode 100644 index 000000000000..28053c646ba9 --- /dev/null +++ b/drivers/bus/daughterboards/96boards-secure96.c @@ -0,0 +1,265 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 96boards Secure96 mezzanine board driver + * (C) 2018 Linus Walleij linus.walleij@linaro.org + */ +#include <linux/gpio/consumer.h> +#include <linux/leds.h> +#include <linux/i2c.h> +#include <linux/spi/spi.h> +#include <linux/sizes.h> +#include <linux/platform_data/at24.h> +#include <linux/delay.h> +#include <linux/platform_device.h> +#include <linux/module.h> + +#include "96boards-mezzanines.h" + +struct secure96 { + struct device *dev; + struct ls_device *ls; + struct platform_device *leds_device; + struct gpio_led *secure96_leds; + struct i2c_client *eeprom; + struct i2c_client *crypto; + struct i2c_client *hash; + struct gpio_desc *tpm_reset; + struct gpio_desc *tpm_irq; + struct spi_device *tpm; +}; + +struct secure96_ledinfo { + enum ls_gpio pin; + const char *ledname; +}; + +/* + * GPIO-F, G, H and I are connected to LEDs, two red and two green + */ +static const struct secure96_ledinfo ledinfos[] = { + { + .pin = LS_GPIO_F, + .ledname = "secure96:red:0", + }, + { + .pin = LS_GPIO_G, + .ledname = "secure96:red:1", + }, + { + .pin = LS_GPIO_H, + .ledname = "secure96:green:0", + }, + { + .pin = LS_GPIO_I, + .ledname = "secure96:green:1", + }, +}; + +/* + * The On Semiconductor CAT21M01 is 131072bits i.e. 16KB. This should be + * mostly compatible to 24c128 so we register that with special pdata so + * that we can fill in the GPIO descriptor for write protect. + */ +static struct at24_platform_data secure96_eeprom_pdata = { + .byte_len = SZ_16K / 8, + .page_size = 256, + .flags = AT24_FLAG_ADDR16, +}; + +static const struct i2c_board_info secure96_eeprom = { + I2C_BOARD_INFO("24c128", 0x50), + .platform_data = &secure96_eeprom_pdata, +}; + +/* Crypto chip */ +static const struct i2c_board_info secure96_crypto = { + I2C_BOARD_INFO("atecc508a", 0x60), +}; + +/* SHA hash chip */ +static const struct i2c_board_info secure96_hash = { + I2C_BOARD_INFO("atsha204a", 0x64), +}; + +/* Infineon SLB9670 TPM 2.0 chip */ +static struct spi_board_info secure96_tpm = { + .modalias = "tpm_tis_spi", + /* The manual says 22.5MHz for 1.8V supply */ + .max_speed_hz = 22500000, + .chip_select = 0, +}; + +int secure96_probe(struct ls_device *ls) +{ + struct device *dev = &ls->dev; + struct secure96 *sec; + struct gpio_desc *gpiod; + struct gpio_led_platform_data secure96_leds_pdata; + int ret; + int i; + + sec = devm_kzalloc(dev, sizeof(*sec), GFP_KERNEL); + if (!sec) + return -ENOMEM; + sec->dev = dev; + sec->ls = ls; + + sec->secure96_leds = devm_kzalloc(dev, + ARRAY_SIZE(ledinfos) * sizeof(*sec->secure96_leds), + GFP_KERNEL); + if (!sec->secure96_leds) + return -ENOMEM; + + dev_info(dev, "populate secure96\n"); + + /* Populate the four LEDs */ + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) { + const struct secure96_ledinfo *linfo; + + linfo = &ledinfos[i]; + + gpiod = ls_get_gpiod(ls, linfo->pin, linfo->ledname, + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get GPIO line %d\n", + linfo->pin); + return -ENODEV; + } + sec->secure96_leds[i].gpiod = gpiod; + sec->secure96_leds[i].name = linfo->ledname; + /* Heartbeat on first LED */ + if (i == 0) + sec->secure96_leds[i].default_trigger = "heartbeat"; + } + + secure96_leds_pdata.num_leds = ARRAY_SIZE(ledinfos); + secure96_leds_pdata.leds = sec->secure96_leds; + + sec->leds_device = platform_device_register_data(dev, + "leds-gpio", + PLATFORM_DEVID_AUTO, + &secure96_leds_pdata, + sizeof(secure96_leds_pdata)); + if (IS_ERR(sec->leds_device)) { + dev_err(dev, "failed to populate LEDs device\n"); + return -ENODEV; + } + + /* Populate the three I2C0 devices */ + gpiod = ls_get_gpiod(ls, LS_GPIO_B, "cat21m01-wp", + GPIOD_OUT_HIGH); + if (IS_ERR(gpiod)) + dev_err(dev, "no CAT21M01 write-protect GPIO\n"); + else + secure96_eeprom_pdata.wp_gpiod = gpiod; + sec->eeprom = i2c_new_device(ls->i2c0, &secure96_eeprom); + if (!sec->eeprom) { + dev_err(dev, "failed to populate EEPROM\n"); + ret = -ENODEV; + goto out_unreg_leds; + } + + sec->crypto = i2c_new_device(ls->i2c0, &secure96_crypto); + if (!sec->eeprom) { + dev_err(dev, "failed to populate crypto device\n"); + ret = -ENODEV; + goto out_remove_eeprom; + } + + sec->hash = i2c_new_device(ls->i2c0, &secure96_hash); + if (!sec->eeprom) { + dev_err(dev, "failed to populate hash device\n"); + ret = -ENODEV; + goto out_remove_crypto; + } + + /* Populate the SPI TPM device */ + gpiod = ls_get_gpiod(ls, LS_GPIO_D, + "tpm-slb9670-rst", + GPIOD_OUT_LOW); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get TPM RESET\n"); + ret = -ENODEV; + goto out_remove_hash; + } + udelay(80); + /* Deassert RST */ + gpiod_set_value(gpiod, 1); + sec->tpm_reset = gpiod; + + gpiod = ls_get_gpiod(ls, LS_GPIO_C, + "tpm-slb9670-irq", + GPIOD_IN); + if (IS_ERR(gpiod)) { + dev_err(dev, "failed to get TPM IRQ GPIO\n"); + ret = -ENODEV; + goto out_remove_tpm_reset; + } + sec->tpm_irq = gpiod; + secure96_tpm.irq = gpiod_to_irq(gpiod); + sec->tpm = spi_new_device(ls->spi, &secure96_tpm); + if (!sec->tpm) { + dev_err(dev, "failed to populate TPM device\n"); + ret = -ENODEV; + goto out_remove_tpm_irq; + } + + dev_set_drvdata(&ls->dev, sec); + + return 0; + +out_remove_tpm_irq: + ls_put_gpiod(ls, sec->tpm_irq); +out_remove_tpm_reset: + ls_put_gpiod(ls, sec->tpm_reset); +out_remove_hash: + i2c_unregister_device(sec->hash); +out_remove_crypto: + i2c_unregister_device(sec->crypto); +out_remove_eeprom: + i2c_unregister_device(sec->eeprom); + if (secure96_eeprom_pdata.wp_gpiod) + ls_put_gpiod(ls, secure96_eeprom_pdata.wp_gpiod); +out_unreg_leds: + platform_device_unregister(sec->leds_device); + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) + ls_put_gpiod(ls, sec->secure96_leds[i].gpiod); + return ret; +} + +static void secure96_remove(struct ls_device *ls) +{ + struct secure96 *sec = dev_get_drvdata(&ls->dev); + int i; + + spi_unregister_device(sec->tpm); + ls_put_gpiod(sec->ls, sec->tpm_irq); + ls_put_gpiod(sec->ls, sec->tpm_reset); + i2c_unregister_device(sec->hash); + i2c_unregister_device(sec->crypto); + i2c_unregister_device(sec->eeprom); + if (secure96_eeprom_pdata.wp_gpiod) + ls_put_gpiod(sec->ls, secure96_eeprom_pdata.wp_gpiod); + platform_device_unregister(sec->leds_device); + for (i = 0; i < ARRAY_SIZE(ledinfos); i++) + ls_put_gpiod(sec->ls, sec->secure96_leds[i].gpiod); + dev_set_drvdata(&ls->dev, NULL); +} + +static const struct of_device_id secure96_of_match[] = { + { + .compatible = "96boards,secure96", + }, + {}, +}; + +struct ls_driver secure96_driver = { + .drv = { + .owner = THIS_MODULE, + .name = "secure96", + .of_match_table = of_match_ptr(secure96_of_match), + }, + .probe = secure96_probe, + .remove = secure96_remove, +}; +module_driver(secure96_driver, ls_driver_register, ls_driver_unregister); diff --git a/drivers/bus/daughterboards/Kconfig b/drivers/bus/daughterboards/Kconfig new file mode 100644 index 000000000000..9855346c8b4d --- /dev/null +++ b/drivers/bus/daughterboards/Kconfig @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Non-discoverable daughterboards + +menuconfig DAUGHTERBOARDS + bool "Non-discoverable daughterboards" + help + These bus drivers deal with non-discoverable daughterboards, + which means daughterboards (plug-in complex logic circuit + boards) that can not reliably be discovered by software. + The physical connector is defined for the host hardware, + but we need to indicate what is on it at runtime using + sysfs. + +if DAUGHTERBOARDS + +menuconfig 96BOARDS_MEZZANINES + bool "96boards mezzanine boards" + +if 96BOARDS_MEZZANINES + +config 96BOARDS_LS_CONNECTOR + bool "96boards low speed connector driver" + depends on OF + depends on I2C + depends on SPI_MASTER + depends on GPIOLIB + help + Driver for the 96boards low speed connector + +config 96BOARDS_SECURE96 + bool "96boards Secure96 board driver" + depends on 96BOARDS_LS_CONNECTOR + select NEW_LEDS + select LEDS_CLASS + select LEDS_GPIO + select EEPROM_AT24 + select CRYPTO_HW + select CRYPTO_DEV_ATMEL_ECC + select HW_RANDOM + select TCG_TPM + select HW_RANDOM_TPM + select TCG_TIS + select TCG_TIS_SPI + help + Driver for the 96boards Secure96 mezzanine + +endif # 96BOARDS_MEZZANINES + +endif # DAUGHTERBOARDS diff --git a/drivers/bus/daughterboards/Makefile b/drivers/bus/daughterboards/Makefile new file mode 100644 index 000000000000..c9691b470fc5 --- /dev/null +++ b/drivers/bus/daughterboards/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for non-discoverable daughterboards +# +obj-$(CONFIG_96BOARDS_LS_CONNECTOR) += 96boards-ls-bus.o 96boards-ls-connector.o +obj-$(CONFIG_96BOARDS_SECURE96) += 96boards-secure96.o
On 08/23/18 03:33, Linus Walleij wrote:
I have been a bit hesitant to reiterate the series, but this is anyways a v1 of the 96Boards Mezzanine Low Speed connector driver framework.
I know the boards have a high speed connector as well, just trying to work stepwise and do the simple things first.
What convinced me to continue was very real usecases that exist today, as this makes the secure96 Mezzanine work:
Get something upstream that makes it possible to without any trouble or extensive ugly hacking probe and use the secure96 mezzanine. This is motivated by the IoT design space which needs a way to plug in proper security and the secure96 offers a TPM chip for root of trust and key handling.
A clear indication that the same approach will work just as fine with ACPI without reinventing the universe. I do not have a definitive proof of this, but it is more plausible that this will be reusable for ACPI than any of the DT-centric ideas I've seen for populating daughterboards. There are 96boards using ACPI today. A secure96 TPM is desireable for things like the ARM developer box which has this LS connector: https://www.96boards.org/product/developerbox/
Some indication that binding the connector like this will not implicate or screw things up for the DT-overlays idea, i.e. a both/and and not either/or approach.
The idea is for this to go upstream through ARM SoC the day noone actively NACK it and someone actively ACK it. Expect some more iterations.
Linus Walleij (4): eeprom: at24: Allow passing gpiodesc from pdata spi: Make of_find_spi_device_by_node() available bus: Add DT bindings for 96Boards low speed connector bus: 96boards Low-Speed Connector
For the moment, NACK since there is not a substantive change from before. This is without having read beyond this introduction.
I will read through the rest of the series and revisit my previous conclusions, but most likely not for a few days.
-Frank
.../bus/96boards,low-speed-connector.txt | 50 +++ drivers/bus/Kconfig | 2 + drivers/bus/Makefile | 4 +- drivers/bus/daughterboards/96boards-ls-bus.c | 39 ++ .../daughterboards/96boards-ls-connector.c | 367 ++++++++++++++++++ .../bus/daughterboards/96boards-mezzanines.h | 77 ++++ .../bus/daughterboards/96boards-secure96.c | 265 +++++++++++++ drivers/bus/daughterboards/Kconfig | 50 +++ drivers/bus/daughterboards/Makefile | 6 + drivers/misc/eeprom/at24.c | 6 +- drivers/spi/spi.c | 33 +- include/linux/platform_data/at24.h | 2 + include/linux/spi/spi.h | 4 + 13 files changed, 888 insertions(+), 17 deletions(-) create mode 100644 Documentation/devicetree/bindings/bus/96boards,low-speed-connector.txt create mode 100644 drivers/bus/daughterboards/96boards-ls-bus.c create mode 100644 drivers/bus/daughterboards/96boards-ls-connector.c create mode 100644 drivers/bus/daughterboards/96boards-mezzanines.h create mode 100644 drivers/bus/daughterboards/96boards-secure96.c create mode 100644 drivers/bus/daughterboards/Kconfig create mode 100644 drivers/bus/daughterboards/Makefile
On Fri, Aug 24, 2018 at 1:06 AM Frank Rowand frowand.list@gmail.com wrote:
On 08/23/18 03:33, Linus Walleij wrote:
- Some indication that binding the connector like this will not implicate or screw things up for the DT-overlays idea, i.e. a both/and and not either/or approach.
(...)
For the moment, NACK since there is not a substantive change from before. This is without having read beyond this introduction.
So I guess you disagree with the previous statement, and I need some elaboration to understand exactly what in this approach works counter to the goals of DT overlays.
It's not like I'm overly infatuated with my own approach, but I want to get to a point where people can start to use these daughterboards no matter whether they use DT or ACPI.
I'm missing ACPI input though, the DT people are more responsive :/
I will read through the rest of the series and revisit my previous conclusions, but most likely not for a few days.
OK no problem there is no immediate hurry.
Yours, Linus Walleij
Hi Linus,
On 8/23/18 4:06 PM, Frank Rowand wrote:
On 08/23/18 03:33, Linus Walleij wrote:
I have been a bit hesitant to reiterate the series, but this is anyways a v1 of the 96Boards Mezzanine Low Speed connector driver framework.
< snip >
I will read through the rest of the series and revisit my previous conclusions, but most likely not for a few days.
-Frank
< snip >
My apologies for continuing to not getting to this task. It has been in the top grouping of my todo list but has been pushed aside by a rather busy schedule of conferences and company internal work. It remains up at the top of my todo list, but most likely will still be shunted aside for three more weeks of other pressing work.
I will get to it, I definitely have not forgotten it.
-Frank
On Thu, Nov 15, 2018 at 5:27 PM Frank Rowand frowand.list@gmail.com wrote:
On 8/23/18 4:06 PM, Frank Rowand wrote:
On 08/23/18 03:33, Linus Walleij wrote:
I have been a bit hesitant to reiterate the series, but this is anyways a v1 of the 96Boards Mezzanine Low Speed connector driver framework.
< snip >
I will read through the rest of the series and revisit my previous conclusions, but most likely not for a few days.
-Frank
< snip >
My apologies for continuing to not getting to this task. It has been in the top grouping of my todo list but has been pushed aside by a rather busy schedule of conferences and company internal work. It remains up at the top of my todo list, but most likely will still be shunted aside for three more weeks of other pressing work.
I will get to it, I definitely have not forgotten it.
It's OK, I might get to rebasing the series even.
We discussed it in a session with Linaro in Vancouver recently (some month ago). What we took away from it is that there are many precedents of populating devices ad hoc, what really makes this one special is that it takes something device tree and ad hoc populates something on top of it, not defined in the device tree itself.
On a related note, Heikki Krogerus is making a software FWnode population series. I ran into this when converting board files to use more abstract descriptions. Check it out: https://marc.info/?l=linux-kernel&m=154177331200561&w=2
The idea with the series is to expand FWnode so that it doesn't only populate Linux devices from device tree or ACPI but also by software, where needed, further expanding the fwnode abstraction. I will probably look into using that.
Yours, Linus Walleij
On 11/15/18 2:59 PM, Linus Walleij wrote:
On Thu, Nov 15, 2018 at 5:27 PM Frank Rowand frowand.list@gmail.com wrote:
On 8/23/18 4:06 PM, Frank Rowand wrote:
On 08/23/18 03:33, Linus Walleij wrote:
I have been a bit hesitant to reiterate the series, but this is anyways a v1 of the 96Boards Mezzanine Low Speed connector driver framework.
< snip >
I will read through the rest of the series and revisit my previous conclusions, but most likely not for a few days.
-Frank
< snip >
My apologies for continuing to not getting to this task. It has been in the top grouping of my todo list but has been pushed aside by a rather busy schedule of conferences and company internal work. It remains up at the top of my todo list, but most likely will still be shunted aside for three more weeks of other pressing work.
I will get to it, I definitely have not forgotten it.
It's OK, I might get to rebasing the series even.
We discussed it in a session with Linaro in Vancouver recently (some month ago). What we took away from it
It would be helpful for me to look at that. What was the title of the session, or a pointer to the resource page for it?
-Frank
is that there are many precedents of populating devices ad hoc, what really makes this one special is that it takes something device tree and ad hoc populates something on top of it, not defined in the device tree itself.
On a related note, Heikki Krogerus is making a software FWnode population series. I ran into this when converting board files to use more abstract descriptions. Check it out: https://marc.info/?l=linux-kernel&m=154177331200561&w=2
The idea with the series is to expand FWnode so that it doesn't only populate Linux devices from device tree or ACPI but also by software, where needed, further expanding the fwnode abstraction. I will probably look into using that.
Yours, Linus Walleij