[PATCH v4 0/2] Use NVMEM as reboot-mode write interface
Description --- Extend the reboot mode driver to use a NVMEM cell as writing interface. Testing --- The testing is done by configuring DT from a custom board. The NVMEM cell is configured in an RTC non-volatile memory. Kernel: 4.14.60 (the patchset was rebased on kernel master) DT configurations: ` ... reboot-mode-nvmem@0 { compatible = "simple-mfd"; reboot-mode { compatible = "nvmem-reboot-mode"; nvmem-cells = <_mode>; nvmem-cell-names = "reboot-mode"; mode-test = <0x21969147>; }; }; ... reboot_mode: nvmem_reboot_mode@0 { reg = <0x00 0x4>; }; ... ` 1. Reboot the system using the command `reboot test` 2. Verify that kernel logs show that reboot was done in mode `test`: PASS `[ 413.957172] reboot: Restarting system with command 'test' ` 3. Stop in U-Boot and verify that mode `test` magic value is present in RTCs non-volatile memory: PASS Kernel: 5.1.0-rc3 1. Configure `arch/arm/configs/imx_v6_v7_defconfig` to contain `CONFIG_NVMEM_REBOOT_MODE=y` 2. Verify that Kernel compiles successful: PASS ` make ARCH=arm CROSS_COMPILE=arm-linux-gnu- imx_v6_v7_defconfig zImage ... CC drivers/power/reset/nvmem-reboot-mode.o ... Kernel: arch/arm/boot/zImage is ready ` Changes since v1: - - split the documentation on a separate patch - add a missing header Changes since v2: - change the module license to GPL since GPL v2 is deprecated Changes since v3: - documentation updated according to the comments Nandor Han (2): power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface dt-bindings: power: reset: add document for NVMEM based reboot-mode .../power/reset/nvmem-reboot-mode.txt | 26 +++ drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 +++ 4 files changed, 112 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt create mode 100644 drivers/power/reset/nvmem-reboot-mode.c -- 2.17.2
[PATCH v4 2/2] dt-bindings: power: reset: add document for NVMEM based reboot-mode
Add the device tree bindings document for the NVMEM based reboot-mode driver. Signed-off-by: Nandor Han --- .../power/reset/nvmem-reboot-mode.txt | 26 +++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt new file mode 100644 index ..752d6126d5da --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt @@ -0,0 +1,26 @@ +NVMEM reboot mode driver + +This driver gets reboot mode magic value from reboot-mode driver +and stores it in a NVMEM cell named "reboot-mode". Then the bootloader +can read it and take different action according to the magic +value stored. + +Required properties: +- compatible: should be "nvmem-reboot-mode". +- nvmem-cells: A phandle to the reboot mode provided by a nvmem device. +- nvmem-cell-names: Should be "reboot-mode". + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + reboot-mode { + compatible = "nvmem-reboot-mode"; + nvmem-cells = <_mode>; + nvmem-cell-names = "reboot-mode"; + + mode-normal = <0x5501>; + mode-bootloader = <0x5500>; + mode-recovery = <0x5502>; + mode-test = <0x5503>; + }; -- 2.17.2
[PATCH v4 1/2] power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface
Add a new reboot mode write interface that is using an NVMEM cell to store the reboot mode magic. Signed-off-by: Nandor Han --- drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile| 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 + 3 files changed, 86 insertions(+) create mode 100644 drivers/power/reset/nvmem-reboot-mode.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 6533aa560aa1..bb4a4e854f96 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -245,5 +245,14 @@ config POWER_RESET_SC27XX PMICs includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. +config NVMEM_REBOOT_MODE + tristate "Generic NVMEM reboot mode driver" + select REBOOT_MODE + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in a NVMEM cell, + then the bootloader can read it and take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0aebee954ac1..85da3198e4e0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o +obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index ..e229308d43e2 --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; + struct nvmem_cell *cell; +}; + +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + + ret = nvmem_cell_write(nvmem_rbm->cell, , sizeof(magic)); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int nvmem_reboot_mode_probe(struct platform_device *pdev) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = devm_kzalloc(>dev, sizeof(*nvmem_rbm), GFP_KERNEL); + if (!nvmem_rbm) + return -ENOMEM; + + nvmem_rbm->reboot.dev = >dev; + nvmem_rbm->reboot.write = nvmem_reboot_mode_write; + + nvmem_rbm->cell = devm_nvmem_cell_get(>dev, "reboot-mode"); + if (IS_ERR(nvmem_rbm->cell)) { + dev_err(>dev, "failed to get the nvmem cell reboot-mode\n"); + return PTR_ERR(nvmem_rbm->cell); + } + + ret = devm_reboot_mode_register(>dev, _rbm->reboot); + if (ret) + dev_err(>dev, "can't register reboot mode\n"); + + return ret; +} + +static const struct of_device_id nvmem_reboot_mode_of_match[] = { + { .compatible = "nvmem-reboot-mode" }, + {} +}; +MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match); + +static struct platform_driver nvmem_reboot_mode_driver = { + .probe = nvmem_reboot_mode_probe, + .driver = { + .name = "nvmem-reboot-mode", + .of_match_table = nvmem_reboot_mode_of_match, + }, +}; +module_platform_driver(nvmem_reboot_mode_driver); + +MODULE_AUTHOR("Nandor Han "); +MODULE_DESCRIPTION("NVMEM reboot mode driver"); +MODULE_LICENSE("GPL"); -- 2.17.2
[PATCH v3 2/2] dt-bindings: power: reset: add document for NVMEM based reboot-mode
Add the device tree bindings document for the NVMEM based reboot-mode driver. Signed-off-by: Nandor Han --- .../power/reset/nvmem-reboot-mode.txt | 32 +++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt new file mode 100644 index ..2e1b86c31cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt @@ -0,0 +1,32 @@ +NVMEM reboot mode driver + +This driver gets reboot mode magic value from reboot-mode driver +and stores it in a NVMEM cell named "reboot-mode". Then the bootloader +can read it and take different action according to the magic +value stored. + +This DT node should be represented as a sub-node of a "simple-mfd" +node. + +Required properties: +- compatible: should be "nvmem-reboot-mode". +- nvmem-cells: A phandle to the reboot mode provided by a nvmem device. +- nvmem-cell-names: Should be "reboot-mode". + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + reboot-mode-nvmem@0 { + compatible = "simple-mfd"; + reboot-mode { + compatible = "nvmem-reboot-mode"; + nvmem-cells = <_mode>; + nvmem-cell-names = "reboot-mode"; + + mode-normal = <0x5501>; + mode-bootloader = <0x5500>; + mode-recovery = <0x5502>; + mode-test = <0x5503>; + }; + }; -- 2.17.2
[PATCH v3 0/2] Use NVMEM as reboot-mode write interface
Description --- Extend the reboot mode driver to use a NVMEM cell as writing interface. Testing --- The testing is done by configuring DT from a custom board. The NVMEM cell is configured in an RTC non-volatile memory. Kernel: 4.14.60 (the patchset was rebased on kernel master) DT configurations: ` ... reboot-mode-nvmem@0 { compatible = "simple-mfd"; reboot-mode { compatible = "nvmem-reboot-mode"; nvmem-cells = <_mode>; nvmem-cell-names = "reboot-mode"; mode-test = <0x21969147>; }; }; ... reboot_mode: nvmem_reboot_mode@0 { reg = <0x00 0x4>; }; ... ` 1. Reboot the system using the command `reboot test` 2. Verify that kernel logs show that reboot was done in mode `test`: PASS `[ 413.957172] reboot: Restarting system with command 'test' ` 3. Stop in U-Boot and verify that mode `test` magic value is present in RTCs non-volatile memory: PASS Kernel: 5.1.0-rc3 1. Configure `arch/arm/configs/imx_v6_v7_defconfig` to contain `CONFIG_NVMEM_REBOOT_MODE=y` 2. Verify that Kernel compiles successful: PASS ` make ARCH=arm CROSS_COMPILE=arm-linux-gnu- imx_v6_v7_defconfig zImage ... CC drivers/power/reset/nvmem-reboot-mode.o ... Kernel: arch/arm/boot/zImage is ready ` Changes since v1: - - split the documentation on a separate patch - add a missing header Changes since v2: - change the module license to GPL since GPL v2 is deprecated Nandor Han (2): power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface dt-bindings: power: reset: add document for NVMEM based reboot-mode .../power/reset/nvmem-reboot-mode.txt | 32 drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 +++ 4 files changed, 118 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt create mode 100644 drivers/power/reset/nvmem-reboot-mode.c -- 2.17.2
[PATCH v3 1/2] power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface
Add a new reboot mode write interface that is using an NVMEM cell to store the reboot mode magic. Signed-off-by: Nandor Han --- drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile| 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 + 3 files changed, 86 insertions(+) create mode 100644 drivers/power/reset/nvmem-reboot-mode.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 6533aa560aa1..bb4a4e854f96 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -245,5 +245,14 @@ config POWER_RESET_SC27XX PMICs includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. +config NVMEM_REBOOT_MODE + tristate "Generic NVMEM reboot mode driver" + select REBOOT_MODE + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in a NVMEM cell, + then the bootloader can read it and take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0aebee954ac1..85da3198e4e0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o +obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index ..e229308d43e2 --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; + struct nvmem_cell *cell; +}; + +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + + ret = nvmem_cell_write(nvmem_rbm->cell, , sizeof(magic)); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int nvmem_reboot_mode_probe(struct platform_device *pdev) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = devm_kzalloc(>dev, sizeof(*nvmem_rbm), GFP_KERNEL); + if (!nvmem_rbm) + return -ENOMEM; + + nvmem_rbm->reboot.dev = >dev; + nvmem_rbm->reboot.write = nvmem_reboot_mode_write; + + nvmem_rbm->cell = devm_nvmem_cell_get(>dev, "reboot-mode"); + if (IS_ERR(nvmem_rbm->cell)) { + dev_err(>dev, "failed to get the nvmem cell reboot-mode\n"); + return PTR_ERR(nvmem_rbm->cell); + } + + ret = devm_reboot_mode_register(>dev, _rbm->reboot); + if (ret) + dev_err(>dev, "can't register reboot mode\n"); + + return ret; +} + +static const struct of_device_id nvmem_reboot_mode_of_match[] = { + { .compatible = "nvmem-reboot-mode" }, + {} +}; +MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match); + +static struct platform_driver nvmem_reboot_mode_driver = { + .probe = nvmem_reboot_mode_probe, + .driver = { + .name = "nvmem-reboot-mode", + .of_match_table = nvmem_reboot_mode_of_match, + }, +}; +module_platform_driver(nvmem_reboot_mode_driver); + +MODULE_AUTHOR("Nandor Han "); +MODULE_DESCRIPTION("NVMEM reboot mode driver"); +MODULE_LICENSE("GPL"); -- 2.17.2
[PATCH v3 1/1] rtc: ds3232: get SRAM access using NVMEM Framework
DS3232 RTC has 236 bytes of persistent memory. Add RTC SRAM read and write access using the NVMEM Framework. Signed-off-by: Nandor Han --- Description --- Provides DS3232 RTC SRAM access using NVMEM framework. Testing --- The test was done on a custom board which contains a DS3232 RTC device. Kernel Version: 4.14.60 (Just for clarity, the patch is against master) 1. Verify that SRAM is accessible using NVMEM interface: PASS ` # hexdump /sys/bus/nvmem/devices/ds3232_sram0/nvmem 000 * 0e0 ` 2. Modify the content. ` # echo testing > /sys/bus/nvmem/devices/ds3232_sram0/nvmem # ` 3. Power cycle the board and verify that contents are preserved: PASS ` # hexdump -n 10 -C /sys/bus/nvmem/devices/ds3232_sram0/nvmem 74 65 73 74 69 6e 67 0a 00 00|testing...| 000a ` Testing on Kernel v5.1.0-rc3 1. Update `arch/arm/configs/imx_v6_v7_defconfig` to contain `CONFIG_RTC_DRV_DS3232=y` 2. Verify that building the kernel is successful: PASS ` make ARCH=arm CROSS_COMPILE=arm-linux-gnu- imx_v6_v7_defconfig zImage ... CC drivers/rtc/rtc-ds3232.o ... Kernel: arch/arm/boot/zImage is ready ` Changes since v1 - remove the unnecessary header "rtc-core.h" - use nvmem_config from the stack - configure the nvmem type - remove the `of_node` configuration Changes since v2 - init unused struct nvmem_cfg members to 0 - use regmap as private data to nvmem struct drivers/rtc/rtc-ds3232.c | 40 ++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7184e5145f12..1e9312f96021 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -48,6 +48,10 @@ # define DS3232_REG_SR_A1F 0x01 #define DS3232_REG_TEMPERATURE 0x11 +#define DS3232_REG_SRAM_START 0x14 +#define DS3232_REG_SRAM_END 0xFF + +#define DS3232_REG_SRAM_SIZE236 struct ds3232 { struct device *dev; @@ -461,11 +465,39 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; +static int ds3232_nvmem_read(void *priv, unsigned int offset, void *val, +size_t bytes) +{ + struct regmap *ds3232_regmap = (struct regmap *)priv; + + return regmap_bulk_read(ds3232_regmap, DS3232_REG_SRAM_START + offset, + val, bytes); +} + +static int ds3232_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct regmap *ds3232_regmap = (struct regmap *)priv; + + return regmap_bulk_write(ds3232_regmap, DS3232_REG_SRAM_START + offset, +val, bytes); +} + static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { struct ds3232 *ds3232; int ret; + struct nvmem_config nvmem_cfg = { + .name = "ds3232_sram", + .stride = 1, + .size = DS3232_REG_SRAM_SIZE, + .word_size = 1, + .reg_read = ds3232_nvmem_read, + .reg_write = ds3232_nvmem_write, + .priv = regmap, + .type = NVMEM_TYPE_BATTERY_BACKED + }; ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL); if (!ds3232) @@ -490,6 +522,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, if (IS_ERR(ds3232->rtc)) return PTR_ERR(ds3232->rtc); + ret = rtc_nvmem_register(ds3232->rtc, _cfg); + if(ret) + return ret; + if (ds3232->irq > 0) { ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, ds3232_irq, @@ -542,7 +578,7 @@ static int ds3232_i2c_probe(struct i2c_client *client, static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, }; regmap = devm_regmap_init_i2c(client, ); @@ -609,7 +645,7 @@ static int ds3234_probe(struct spi_device *spi) static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, .write_flag_mask = 0x80, }; struct regmap *regmap; -- 2.17.2
[PATCH v2 2/2] dt-bindings: power: reset: add document for NVMEM based reboot-mode
Add the device tree bindings document for the NVMEM based reboot-mode driver. Signed-off-by: Nandor Han --- .../power/reset/nvmem-reboot-mode.txt | 32 +++ 1 file changed, 32 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt new file mode 100644 index ..2e1b86c31cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt @@ -0,0 +1,32 @@ +NVMEM reboot mode driver + +This driver gets reboot mode magic value from reboot-mode driver +and stores it in a NVMEM cell named "reboot-mode". Then the bootloader +can read it and take different action according to the magic +value stored. + +This DT node should be represented as a sub-node of a "simple-mfd" +node. + +Required properties: +- compatible: should be "nvmem-reboot-mode". +- nvmem-cells: A phandle to the reboot mode provided by a nvmem device. +- nvmem-cell-names: Should be "reboot-mode". + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + reboot-mode-nvmem@0 { + compatible = "simple-mfd"; + reboot-mode { + compatible = "nvmem-reboot-mode"; + nvmem-cells = <_mode>; + nvmem-cell-names = "reboot-mode"; + + mode-normal = <0x5501>; + mode-bootloader = <0x5500>; + mode-recovery = <0x5502>; + mode-test = <0x5503>; + }; + }; -- 2.17.2
[PATCH v2 1/2] power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface
Add a new reboot mode write interface that is using an NVMEM cell to store the reboot mode magic. Signed-off-by: Nandor Han --- drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile| 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 + 3 files changed, 86 insertions(+) create mode 100644 drivers/power/reset/nvmem-reboot-mode.c diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 6533aa560aa1..bb4a4e854f96 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -245,5 +245,14 @@ config POWER_RESET_SC27XX PMICs includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. +config NVMEM_REBOOT_MODE + tristate "Generic NVMEM reboot mode driver" + select REBOOT_MODE + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in a NVMEM cell, + then the bootloader can read it and take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0aebee954ac1..85da3198e4e0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o +obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index ..816cfdab16a7 --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include + +struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; + struct nvmem_cell *cell; +}; + +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + + ret = nvmem_cell_write(nvmem_rbm->cell, , sizeof(magic)); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return ret; +} + +static int nvmem_reboot_mode_probe(struct platform_device *pdev) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = devm_kzalloc(>dev, sizeof(*nvmem_rbm), GFP_KERNEL); + if (!nvmem_rbm) + return -ENOMEM; + + nvmem_rbm->reboot.dev = >dev; + nvmem_rbm->reboot.write = nvmem_reboot_mode_write; + + nvmem_rbm->cell = devm_nvmem_cell_get(>dev, "reboot-mode"); + if (IS_ERR(nvmem_rbm->cell)) { + dev_err(>dev, "failed to get the nvmem cell reboot-mode\n"); + return PTR_ERR(nvmem_rbm->cell); + } + + ret = devm_reboot_mode_register(>dev, _rbm->reboot); + if (ret) + dev_err(>dev, "can't register reboot mode\n"); + + return ret; +} + +static const struct of_device_id nvmem_reboot_mode_of_match[] = { + { .compatible = "nvmem-reboot-mode" }, + {} +}; +MODULE_DEVICE_TABLE(of, nvmem_reboot_mode_of_match); + +static struct platform_driver nvmem_reboot_mode_driver = { + .probe = nvmem_reboot_mode_probe, + .driver = { + .name = "nvmem-reboot-mode", + .of_match_table = nvmem_reboot_mode_of_match, + }, +}; +module_platform_driver(nvmem_reboot_mode_driver); + +MODULE_AUTHOR("Nandor Han "); +MODULE_DESCRIPTION("NVMEM reboot mode driver"); +MODULE_LICENSE("GPL v2"); -- 2.17.2
[PATCH v2 0/2] Use NVMEM as reboot-mode write interface
Description --- Extend the reboot mode driver to use a NVMEM cell as writing interface. Testing --- The testing is done by configuring DT from a custom board. The NVMEM cell is configured in an RTC non-volatile memory. Kernel: 4.14.60 (the patchset was rebased on kernel master) DT configurations: ` ... reboot-mode-nvmem@0 { compatible = "simple-mfd"; reboot-mode { compatible = "nvmem-reboot-mode"; nvmem-cells = <_mode>; nvmem-cell-names = "reboot-mode"; mode-test = <0x21969147>; }; }; ... reboot_mode: nvmem_reboot_mode@0 { reg = <0x00 0x4>; }; ... ` 1. Reboot the system using the command `reboot test` 2. Verify that kernel logs show that reboot was done in mode `test`: PASS `[ 413.957172] reboot: Restarting system with command 'test' ` 3. Stop in U-Boot and verify that mode `test` magic value is present in RTCs non-volatile memory: PASS Kernel: 5.1.0-rc3 1. Configure `arch/arm/configs/imx_v6_v7_defconfig` to contain `CONFIG_NVMEM_REBOOT_MODE=y` 2. Verify that Kernel compiles successful: PASS ` make ARCH=arm CROSS_COMPILE=arm-linux-gnu- imx_v6_v7_defconfig zImage ... CC drivers/power/reset/nvmem-reboot-mode.o ... Kernel: arch/arm/boot/zImage is ready ` Changes since v1: - - split the documentation on a separate patch - add a missing header Nandor Han (2): power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface dt-bindings: power: reset: add document for NVMEM based reboot-mode .../power/reset/nvmem-reboot-mode.txt | 32 drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/nvmem-reboot-mode.c | 76 +++ 4 files changed, 118 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt create mode 100644 drivers/power/reset/nvmem-reboot-mode.c -- 2.17.2
[PATCH v2 1/1] rtc: ds3232: get SRAM access using NVMEM Framework
DS3232 RTC has 236 bytes of persistent memory. Add RTC SRAM read and write access using the NVMEM Framework. Signed-off-by: Nandor Han --- Description --- Provides DS3232 RTC SRAM access using NVMEM framework. Testing --- The test was done on a custom board which contains a DS3232 RTC device. Kernel Version: 4.14.60 (Just for clarity, the patch is against master) 1. Verify that SRAM is accessible using NVMEM interface: PASS ` # hexdump /sys/bus/nvmem/devices/ds3232_sram0/nvmem 000 * 0e0 ` 2. Modify the content. ` # echo testing > /sys/bus/nvmem/devices/ds3232_sram0/nvmem # ` 3. Power cycle the board and verify that contents are preserved: PASS ` # hexdump -n 10 -C /sys/bus/nvmem/devices/ds3232_sram0/nvmem 74 65 73 74 69 6e 67 0a 00 00|testing...| 000a ` Testing on Kernel v5.1.0-rc3 1. Update `arch/arm/configs/imx_v6_v7_defconfig` to contain `CONFIG_RTC_DRV_DS3232=y` 2. Verify that building the kernel is successful: PASS ` make ARCH=arm CROSS_COMPILE=arm-linux-gnu- imx_v6_v7_defconfig zImage ... CC drivers/rtc/rtc-ds3232.o ... Kernel: arch/arm/boot/zImage is ready ` Changes since v1 - remove the unnecessary header "rtc-core.h" - use nvmem_config from the stack - configure the nvmem type - remove the `of_node` configuration drivers/rtc/rtc-ds3232.c | 40 ++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7184e5145f12..77908c9e5e09 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -48,6 +48,10 @@ # define DS3232_REG_SR_A1F 0x01 #define DS3232_REG_TEMPERATURE 0x11 +#define DS3232_REG_SRAM_START 0x14 +#define DS3232_REG_SRAM_END 0xFF + +#define DS3232_REG_SRAM_SIZE236 struct ds3232 { struct device *dev; @@ -461,11 +465,30 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; +static int ds3232_nvmem_read(void *priv, unsigned int offset, void *val, +size_t bytes) +{ + struct ds3232 *ds3232 = (struct ds3232 *)priv; + + return regmap_bulk_read(ds3232->regmap, DS3232_REG_SRAM_START + offset, + val, bytes); +} + +static int ds3232_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct ds3232 *ds3232 = (struct ds3232 *)priv; + + return regmap_bulk_write(ds3232->regmap, DS3232_REG_SRAM_START + offset, +val, bytes); +} + static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { struct ds3232 *ds3232; int ret; + struct nvmem_config nvmem_cfg; ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL); if (!ds3232) @@ -476,6 +499,15 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, ds3232->dev = dev; dev_set_drvdata(dev, ds3232); + nvmem_cfg.name = "ds3232_sram"; + nvmem_cfg.stride = 1; + nvmem_cfg.size = DS3232_REG_SRAM_SIZE; + nvmem_cfg.word_size = 1; + nvmem_cfg.reg_read = ds3232_nvmem_read; + nvmem_cfg.reg_write = ds3232_nvmem_write; + nvmem_cfg.priv = ds3232; + nvmem_cfg.type = NVMEM_TYPE_BATTERY_BACKED; + ret = ds3232_check_rtc_status(dev); if (ret) return ret; @@ -490,6 +522,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, if (IS_ERR(ds3232->rtc)) return PTR_ERR(ds3232->rtc); + ret = rtc_nvmem_register(ds3232->rtc, _cfg); + if(ret) + return ret; + if (ds3232->irq > 0) { ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, ds3232_irq, @@ -542,7 +578,7 @@ static int ds3232_i2c_probe(struct i2c_client *client, static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, }; regmap = devm_regmap_init_i2c(client, ); @@ -609,7 +645,7 @@ static int ds3234_probe(struct spi_device *spi) static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, .write_flag_mask = 0x80, }; struct regmap *regmap; -- 2.17.2
[PATCH 1/1] rtc: ds3232: get SRAM access using NVMEM Framework
DS3232 RTC has 236 bytes of persistent memory. Add RTC SRAM read and write access using the NVMEM Framework. Signed-off-by: Nandor Han --- Description --- Provides DS3232 RTC SRAM access using NVMEM framework. Testing --- The test was done on a custom board which contains a DS3232 RTC device. Kernel Version: 4.14.60 (Just for clarity, the patch is against master) 1. Verify that SRAM is accessible using NVMEM interface: PASS ` # hexdump /sys/bus/nvmem/devices/ds3232_sram0/nvmem 000 * 0e0 ` 2. Modify the content. ` # echo testing > /sys/bus/nvmem/devices/ds3232_sram0/nvmem # ` 3. Power cycle the board and verify that contents are preserved: PASS ` # hexdump -n 10 -C /sys/bus/nvmem/devices/ds3232_sram0/nvmem 74 65 73 74 69 6e 67 0a 00 00|testing...| 000a ` drivers/rtc/rtc-ds3232.c | 41 ++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7184e5145f12..fe615aedaa9a 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -24,6 +24,8 @@ #include #include +#include "rtc-core.h" + #define DS3232_REG_SECONDS 0x00 #define DS3232_REG_MINUTES 0x01 #define DS3232_REG_HOURS0x02 @@ -48,12 +50,17 @@ # define DS3232_REG_SR_A1F 0x01 #define DS3232_REG_TEMPERATURE 0x11 +#define DS3232_REG_SRAM_START 0x14 +#define DS3232_REG_SRAM_END 0xFF + +#define DS3232_REG_SRAM_SIZE236 struct ds3232 { struct device *dev; struct regmap *regmap; int irq; struct rtc_device *rtc; + struct nvmem_config nvmem_cfg; bool suspended; }; @@ -461,6 +468,24 @@ static const struct rtc_class_ops ds3232_rtc_ops = { .alarm_irq_enable = ds3232_alarm_irq_enable, }; +static int ds3232_nvmem_read(void *priv, unsigned int offset, void *val, +size_t bytes) +{ + struct ds3232 *ds3232 = (struct ds3232 *)priv; + + return regmap_bulk_read(ds3232->regmap, DS3232_REG_SRAM_START + offset, + val, bytes); +} + +static int ds3232_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct ds3232 *ds3232 = (struct ds3232 *)priv; + + return regmap_bulk_write(ds3232->regmap, DS3232_REG_SRAM_START + offset, +val, bytes); +} + static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, const char *name) { @@ -476,6 +501,14 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, ds3232->dev = dev; dev_set_drvdata(dev, ds3232); + ds3232->nvmem_cfg.name = "ds3232_sram"; + ds3232->nvmem_cfg.stride = 1; + ds3232->nvmem_cfg.size = DS3232_REG_SRAM_SIZE; + ds3232->nvmem_cfg.word_size = 1; + ds3232->nvmem_cfg.reg_read = ds3232_nvmem_read; + ds3232->nvmem_cfg.reg_write = ds3232_nvmem_write; + ds3232->nvmem_cfg.priv = ds3232; + ret = ds3232_check_rtc_status(dev); if (ret) return ret; @@ -490,6 +523,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq, if (IS_ERR(ds3232->rtc)) return PTR_ERR(ds3232->rtc); + ds3232->rtc->dev.of_node = dev->of_node; + ds3232->rtc->nvmem_config = >nvmem_cfg; + rtc_nvmem_register(ds3232->rtc); + if (ds3232->irq > 0) { ret = devm_request_threaded_irq(dev, ds3232->irq, NULL, ds3232_irq, @@ -542,7 +579,7 @@ static int ds3232_i2c_probe(struct i2c_client *client, static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, }; regmap = devm_regmap_init_i2c(client, ); @@ -609,7 +646,7 @@ static int ds3234_probe(struct spi_device *spi) static const struct regmap_config config = { .reg_bits = 8, .val_bits = 8, - .max_register = 0x13, + .max_register = DS3232_REG_SRAM_END, .write_flag_mask = 0x80, }; struct regmap *regmap; -- 2.17.2
[PATCH 1/1] power: reset: nvmem-reboot-mode: use NVMEM as reboot mode write interface
Add a new reboot mode write interface that is using a NVMEM cell, called "reboot-mode", to store the reboot mode magic. Signed-off-by: Nandor Han --- Description --- Extend the reboot mode driver to use a NVMEM cell as writing interface. Testing --- The testing is done by configuring DT from a custom board. The NVMEM cell is configured in an RTC non-volatile memory. DT configurations: ` ... reboot-mode-nvmem@0 { compatible = "simple-mfd"; reboot-mode { compatible = "nvmem-reboot-mode"; nvmem-cells = <_mode>; nvmem-cell-names = "reboot-mode"; mode-test = <0x21969147>; }; }; ... reboot_mode: nvmem_reboot_mode@0 { reg = <0x00 0x4>; }; ... ` 1. Reboot the system using the command `reboot test` 2. Verify that kernel logs show that reboot was done in mode `test`: PASS `[ 413.957172] reboot: Restarting system with command 'test' ` 3. Stop in U-Boot and verify that mode `test` magic value is present in RTCs non-volatile memory: PASS .../power/reset/nvmem-reboot-mode.txt | 32 drivers/power/reset/Kconfig | 9 +++ drivers/power/reset/Makefile | 1 + drivers/power/reset/nvmem-reboot-mode.c | 75 +++ 4 files changed, 117 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt create mode 100644 drivers/power/reset/nvmem-reboot-mode.c diff --git a/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt new file mode 100644 index ..2e1b86c31cb3 --- /dev/null +++ b/Documentation/devicetree/bindings/power/reset/nvmem-reboot-mode.txt @@ -0,0 +1,32 @@ +NVMEM reboot mode driver + +This driver gets reboot mode magic value from reboot-mode driver +and stores it in a NVMEM cell named "reboot-mode". Then the bootloader +can read it and take different action according to the magic +value stored. + +This DT node should be represented as a sub-node of a "simple-mfd" +node. + +Required properties: +- compatible: should be "nvmem-reboot-mode". +- nvmem-cells: A phandle to the reboot mode provided by a nvmem device. +- nvmem-cell-names: Should be "reboot-mode". + +The rest of the properties should follow the generic reboot-mode description +found in reboot-mode.txt + +Example: + reboot-mode-nvmem@0 { + compatible = "simple-mfd"; + reboot-mode { + compatible = "nvmem-reboot-mode"; + nvmem-cells = <_mode>; + nvmem-cell-names = "reboot-mode"; + + mode-normal = <0x5501>; + mode-bootloader = <0x5500>; + mode-recovery = <0x5502>; + mode-test = <0x5503>; + }; + }; diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig index 6533aa560aa1..bb4a4e854f96 100644 --- a/drivers/power/reset/Kconfig +++ b/drivers/power/reset/Kconfig @@ -245,5 +245,14 @@ config POWER_RESET_SC27XX PMICs includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips. +config NVMEM_REBOOT_MODE + tristate "Generic NVMEM reboot mode driver" + select REBOOT_MODE + help + Say y here will enable reboot mode driver. This will + get reboot mode arguments and store it in a NVMEM cell, + then the bootloader can read it and take different + action according to the mode. + endif diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile index 0aebee954ac1..85da3198e4e0 100644 --- a/drivers/power/reset/Makefile +++ b/drivers/power/reset/Makefile @@ -29,3 +29,4 @@ obj-$(CONFIG_POWER_RESET_ZX) += zx-reboot.o obj-$(CONFIG_REBOOT_MODE) += reboot-mode.o obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o +obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o diff --git a/drivers/power/reset/nvmem-reboot-mode.c b/drivers/power/reset/nvmem-reboot-mode.c new file mode 100644 index ..31b73c7a0dad --- /dev/null +++ b/drivers/power/reset/nvmem-reboot-mode.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) Vaisala Oyj. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include + +struct nvmem_reboot_mode { + struct reboot_mode_driver reboot; + struct nvmem_cell *cell; +}; + +static int nvmem_reboot_mode_write(struct reboot_mode_driver *reboot, + unsigned int magic) +{ + int ret; + struct nvmem_reboot_mode *nvmem_rbm; + + nvmem_rbm = container_of(reboot, struct nvmem_reboot_mode, reboot); + + ret = nvmem_cell_write(nvmem_rbm->cell, , sizeof(magic)); + if (ret < 0) + dev_err(reboot->dev, "update reboot mode bits failed\n"); + + return
[RFC PATCH 1/1] regmap: verify if register is writeable before writing operations
regmap provides a couple of ways to validate the register range used. a) maxim allowed register, b) writable/readable register tables, c) callback function that can be provided by the driver to validate a register. regmap framework should verify if registers are writeable before every write operation. However this doesn't seems to happen in every situation. The method `_regmap_raw_write_impl` is only using the `writeable_reg` callback to verify if register is writeable, ignoring the other two. This can lead to undefined behaviour since this allows to write to registers that could be declared un-writeable by using any other option. Change `_regmap_raw_write_impl` to use the `regmap_writeable` method to verify if registers are writable before the write operation. Signed-off-by: Nandor Han --- drivers/base/regmap/regmap.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 4f822e087def..42d8404bc8cc 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c @@ -1493,11 +1493,10 @@ static int _regmap_raw_write_impl(struct regmap *map, unsigned int reg, WARN_ON(!map->bus); /* Check for unwritable registers before we start */ - if (map->writeable_reg) - for (i = 0; i < val_len / map->format.val_bytes; i++) - if (!map->writeable_reg(map->dev, - reg + regmap_get_offset(map, i))) - return -EINVAL; + for (i = 0; i < val_len / map->format.val_bytes; i++) + if (!regmap_writeable(map, +reg + regmap_get_offset(map, i))) + return -EINVAL; if (!map->cache_bypass && map->format.parse_val) { unsigned int ival; -- 2.17.2
[RFC PATCH 0/1] Verify if register is writeable before a write operation
Description --- This is an RFC because I don't know if this is a bug or a normal use case. It seems that the function `_regmap_raw_write_impl` from the regmap framework verifies that a register is writable only using the callback function, ignoring the other two (max allowed register, register ranges) Note: As a left right look I did check also `_regmap_raw_read` function, and it seems that is missing this checks completely. Is this a problem as well? Device/Subsystems Impacted - This will impact drivers that end up using raw writes (firmware download, ...) Testing --- Test configuration: - Kernel Version: 4.14.60 (just for clarification, the patch is rebased on master) - The testing was done using a driver that has NVMEM support and is using `regmap_bulk_write` method to write data to registers. - The valid register range is 0x00->0xFF. 1. Configure a nvcell (4 bytes long) in DT which is outside the valid register range. 2. Write data to NVMEM using the nvcell 3. Verify the result: 3.1 Without the patch the data write in registers is successful with no error displayed. 3.2 With the patch the data write is denied and an error is displayed. Nandor Han (1): regmap: verify if register is writeable before writing operations drivers/base/regmap/regmap.c | 9 - 1 file changed, 4 insertions(+), 5 deletions(-) -- 2.17.2
RE: [PATCH] gpio: xra1403: select REGMAP_SPI
> -Original Message- > From: Arnd Bergmann [mailto:a...@arndb.de] > Sent: 30 May 2017 14:13 > To: Linus Walleij <linus.wall...@linaro.org> > Cc: Han, Nandor (GE Healthcare) <nandor@ge.com>; Arnd Bergmann > <a...@arndb.de>; linux-g...@vger.kernel.org; > linux-kernel@vger.kernel.org > Subject: EXT: [PATCH] gpio: xra1403: select REGMAP_SPI > > Without the regmap code, we get a link error: > > drivers/gpio/built-in.o: In function `xra1403_probe': > (.text+0x132e0): undefined reference to `__devm_regmap_init_spi' > > Fixes: 5704520d7880 ("gpio: xra1403: Add EXAR XRA1403 SPI GPIO expander > driver") > Signed-off-by: Arnd Bergmann <a...@arndb.de> Reviewed-by: Nandor Han <nandor@ge.com> > --- > drivers/gpio/Kconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 66d1f353ca73..238fc231081a 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -1241,6 +1241,7 @@ config GPIO_PISOSR > > config GPIO_XRA1403 > tristate "EXAR XRA1403 16-bit GPIO expander" > + select REGMAP_SPI > help > GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. > > -- > 2.9.0
RE: [PATCH] gpio: xra1403: select REGMAP_SPI
> -Original Message- > From: Arnd Bergmann [mailto:a...@arndb.de] > Sent: 30 May 2017 14:13 > To: Linus Walleij > Cc: Han, Nandor (GE Healthcare) ; Arnd Bergmann > ; linux-g...@vger.kernel.org; > linux-kernel@vger.kernel.org > Subject: EXT: [PATCH] gpio: xra1403: select REGMAP_SPI > > Without the regmap code, we get a link error: > > drivers/gpio/built-in.o: In function `xra1403_probe': > (.text+0x132e0): undefined reference to `__devm_regmap_init_spi' > > Fixes: 5704520d7880 ("gpio: xra1403: Add EXAR XRA1403 SPI GPIO expander > driver") > Signed-off-by: Arnd Bergmann Reviewed-by: Nandor Han > --- > drivers/gpio/Kconfig | 1 + > 1 file changed, 1 insertion(+) > > diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig > index 66d1f353ca73..238fc231081a 100644 > --- a/drivers/gpio/Kconfig > +++ b/drivers/gpio/Kconfig > @@ -1241,6 +1241,7 @@ config GPIO_PISOSR > > config GPIO_XRA1403 > tristate "EXAR XRA1403 16-bit GPIO expander" > + select REGMAP_SPI > help > GPIO driver for EXAR XRA1403 16-bit SPI-based GPIO expander. > > -- > 2.9.0
[PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 24 April 2017 16:47 > To: Han, Nandor (GE Healthcare) <nandor@ge.com> > Cc: Greg KH <gre...@linuxfoundation.org>; David S. Miller > <da...@davemloft.net>; Geert Uytterhoeven <geert@linux- > m68k.org>; Mauro Carvalho Chehab <mche...@kernel.org>; Daniel Vetter > <daniel.vet...@ffwll.ch>; Alexandre Courbot > <gnu...@gmail.com>; Rob Herring <robh...@kernel.org>; Mark Rutland > <mark.rutl...@arm.com>; linux- > g...@vger.kernel.org; devicet...@vger.kernel.org; > linux-kernel@vger.kernel.org; Malinen, Semi (GE Healthcare) > <semi.mali...@ge.com> > Subject: EXT: Re: [PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander > driver > > On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han <nandor@ge.com> wrote: > > > This is a simple driver that provides a /sys/class/gpio > > interface for controlling and configuring the GPIO lines. > > It does not provide support for chip select or interrupts. > > > > Signed-off-by: Nandor Han <nandor@ge.com> > > Signed-off-by: Semi Malinen <semi.mali...@ge.com> > > I almost want to make the driver depend on !GPIO_SYSFS because > of this commit message. > > DO NOT USE OR ENCOURAGE THE USE OF THE GPIO SYSFS > INTERFACE. > Ahh.. I forgot to change this commit message. Sorry I will change it ASAP. > Use the character device. > > Use the example in tools/gpio/* as a guideline and testbed. > > Use libgpiod as a rich userspace. > > And the commit message should state that this is a driver > for such and such Exar hardware instead. > > Thanks. > > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > You are missing > #include > > and that is why the build robot is complaining. > I've noticed that. I will change it in the next rev. > Yours, > Linus Walleij Thanks, Nandy
[PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 24 April 2017 16:47 > To: Han, Nandor (GE Healthcare) > Cc: Greg KH ; David S. Miller > ; Geert Uytterhoeven m68k.org>; Mauro Carvalho Chehab ; Daniel Vetter > ; Alexandre Courbot > ; Rob Herring ; Mark Rutland > ; linux- > g...@vger.kernel.org; devicet...@vger.kernel.org; > linux-kernel@vger.kernel.org; Malinen, Semi (GE Healthcare) > > Subject: EXT: Re: [PATCH v2 2/4] gpio - Add EXAR XRA1403 SPI GPIO expander > driver > > On Thu, Apr 13, 2017 at 12:27 PM, Nandor Han wrote: > > > This is a simple driver that provides a /sys/class/gpio > > interface for controlling and configuring the GPIO lines. > > It does not provide support for chip select or interrupts. > > > > Signed-off-by: Nandor Han > > Signed-off-by: Semi Malinen > > I almost want to make the driver depend on !GPIO_SYSFS because > of this commit message. > > DO NOT USE OR ENCOURAGE THE USE OF THE GPIO SYSFS > INTERFACE. > Ahh.. I forgot to change this commit message. Sorry I will change it ASAP. > Use the character device. > > Use the example in tools/gpio/* as a guideline and testbed. > > Use libgpiod as a rich userspace. > > And the commit message should state that this is a driver > for such and such Exar hardware instead. > > Thanks. > > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > +#include > > You are missing > #include > > and that is why the build robot is complaining. > I've noticed that. I will change it in the next rev. > Yours, > Linus Walleij Thanks, Nandy
[PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 07 April 2017 13:07 > To: Han, Nandor (GE Healthcare) <nandor@ge.com> > Cc: Alexandre Courbot <gnu...@gmail.com>; Rob Herring <robh...@kernel.org>; > Mark Rutland > <mark.rutl...@arm.com>; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; > Malinen, Semi (GE Healthcare) <semi.mali...@ge.com> > Subject: EXT: Re: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver > > On Wed, Apr 5, 2017 at 3:24 PM, Han, Nandor (GE Healthcare) > <nandor@ge.com> wrote: > > [Me] > >> > + /* bring the chip out of reset */ > >> > + reset_gpio = gpiod_get_optional(>dev, "reset", > >> > GPIOD_OUT_LOW); > >> > + if (IS_ERR(reset_gpio)) > >> > + dev_warn(>dev, "could not get reset-gpios\n"); > >> > + else if (reset_gpio) > >> > + gpiod_put(reset_gpio); > >> > >> I don't think you should put it, other than in the remove() > >> function and in that case you need to have it in the > >> state container. > > > > Can you please be more explicit here. > > > > Currently I'm trying to bring the device out from reset in case reset GPIO > > is provided. > > I don't see how this could be done in remove() :) > > If you issue gpiod_put() you release the GPIO hande so something else > can go in and grab the GPIO and assert the reset. > > This is not what you want to make possible: you want to hold this gpiod handle > as long as the driver is running. devm_gpiod_get_optional() will do the > trick if you don't want to put the handle under explicit control. > That was my first intention to release the reset line in case somebody else wants to control it. I did it like that because usually reset line controls multiple devices and probably some upper layer wants to control that. After your comment I did some analysing and I will follow your advice and change the reset line handling. Once the GPIO is provided to the driver the driver will own it and bring out the device from reset. In case not provided the reset line is somebody else responsibility. This way we are able to cover multiple use-cases. Thanks Linus, Nandy > Yours, > Linus Walleij
[PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 07 April 2017 13:07 > To: Han, Nandor (GE Healthcare) > Cc: Alexandre Courbot ; Rob Herring ; > Mark Rutland > ; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; > Malinen, Semi (GE Healthcare) > Subject: EXT: Re: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver > > On Wed, Apr 5, 2017 at 3:24 PM, Han, Nandor (GE Healthcare) > wrote: > > [Me] > >> > + /* bring the chip out of reset */ > >> > + reset_gpio = gpiod_get_optional(>dev, "reset", > >> > GPIOD_OUT_LOW); > >> > + if (IS_ERR(reset_gpio)) > >> > + dev_warn(>dev, "could not get reset-gpios\n"); > >> > + else if (reset_gpio) > >> > + gpiod_put(reset_gpio); > >> > >> I don't think you should put it, other than in the remove() > >> function and in that case you need to have it in the > >> state container. > > > > Can you please be more explicit here. > > > > Currently I'm trying to bring the device out from reset in case reset GPIO > > is provided. > > I don't see how this could be done in remove() :) > > If you issue gpiod_put() you release the GPIO hande so something else > can go in and grab the GPIO and assert the reset. > > This is not what you want to make possible: you want to hold this gpiod handle > as long as the driver is running. devm_gpiod_get_optional() will do the > trick if you don't want to put the handle under explicit control. > That was my first intention to release the reset line in case somebody else wants to control it. I did it like that because usually reset line controls multiple devices and probably some upper layer wants to control that. After your comment I did some analysing and I will follow your advice and change the reset line handling. Once the GPIO is provided to the driver the driver will own it and bring out the device from reset. In case not provided the reset line is somebody else responsibility. This way we are able to cover multiple use-cases. Thanks Linus, Nandy > Yours, > Linus Walleij
[PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 29 March 2017 05:07 > To: Han, Nandor (GE Healthcare) <nandor@ge.com> > Cc: Alexandre Courbot <gnu...@gmail.com>; Rob Herring <robh...@kernel.org>; > Mark Rutland > <mark.rutl...@arm.com>; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; > Malinen, Semi (GE Healthcare) <semi.mali...@ge.com> > Subject: EXT: Re: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver > > On Mon, Mar 27, 2017 at 8:23 AM, Nandor Han <nandor@ge.com> wrote: > > > This is a simple driver that provides a /sys/class/gpio > > interface for controlling and configuring the GPIO lines. > > Use the gpio tools in tools/gpio, use the characcter device. > Do not use sysfs. Change this to reference the tools. > > > It does not provide support for chip select or interrupts. > > > > Signed-off-by: Nandor Han <nandor@ge.com> > > Signed-off-by: Semi Malinen <semi.mali...@ge.com> > (...) > > +exar Exar Corporation > > Send this as a separate patch to the DT bindings maintainer > (Rob Herring.) > OK. I will create a separate patch with this one. I guess is not an issue to send all the patches to Rob as well. > > + > > + ret = xra1403_get_byte(xra, addr + (bit > 7)); > > + if (ret < 0) > > + return ret; > > + > > + return !!(ret & BIT(bit % 8)); > > +} > > This looks like it can use regmap-spi right off, do you agree? > Yes. Using regmap-spi will definitely improve the code readability and reduce boilerplate. Done. > git grep devm_regmap_init_spi > should give you some examples of how to use it. > > If it's not off-the shelf regmap drivers like > drivers/iio/pressure/mpl115_spi.c > give examples of how to make more elaborate custom > SPI transfers with regmap. > Thanks, I did check other drivers as examples. Not that I needed for this driver, but ...mpl115_spi.c doesn't seem to use regmap (checked on next-20170327) > > + > > + if (value != ret) { > > + tx[0] = addr << 1; > > + tx[1] = value; > > + ret = spi_write(xra->spi, tx, sizeof(tx)); > > + } else { > > + ret = 0; > > + } > > + > > +out_unlock: > > + mutex_unlock(>lock); > > + > > + return ret; > > +} > > Classical mask-and-set implementation right? > With regmap this becomes simply regmap_update_bits(map, addr, mask, set) > True. :) > > + /* bring the chip out of reset */ > > + reset_gpio = gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW); > > + if (IS_ERR(reset_gpio)) > > + dev_warn(>dev, "could not get reset-gpios\n"); > > + else if (reset_gpio) > > + gpiod_put(reset_gpio); > > I don't think you should put it, other than in the remove() > function and in that case you need to have it in the > state container. Can you please be more explicit here. Currently I'm trying to bring the device out from reset in case reset GPIO is provided. I don't see how this could be done in remove() :) > > > + mutex_init(>lock); > > + > > + xra->chip.direction_input = xra1403_direction_input; > > + xra->chip.direction_output = xra1403_direction_output; > > Please implement .get_direction(). This is very nice to have. > Done > > +static int xra1403_remove(struct spi_device *spi) > > +{ > > + struct xra1403 *xra = spi_get_drvdata(spi); > > + > > + gpiochip_remove(>chip); > > Use devm_gpiochip_add_data() and this remove is not > needed at all. > True. Done > > +subsys_initcall(xra1403_init); > > + > > +static void __exit xra1403_exit(void) > > +{ > > + spi_unregister_driver(_driver); > > +} > > +module_exit(xra1403_exit); > > This seems like tricksy. Just module_spi_driver() > should be fine don't you think? Yeah. TBH I don't have a strong reason why module_spi_driver init level shouldn't be enough. Done. Regards, Nandor
[PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 29 March 2017 05:07 > To: Han, Nandor (GE Healthcare) > Cc: Alexandre Courbot ; Rob Herring ; > Mark Rutland > ; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org; > Malinen, Semi (GE Healthcare) > Subject: EXT: Re: [PATCH 1/3] gpio - Add EXAR XRA1403 SPI GPIO expander driver > > On Mon, Mar 27, 2017 at 8:23 AM, Nandor Han wrote: > > > This is a simple driver that provides a /sys/class/gpio > > interface for controlling and configuring the GPIO lines. > > Use the gpio tools in tools/gpio, use the characcter device. > Do not use sysfs. Change this to reference the tools. > > > It does not provide support for chip select or interrupts. > > > > Signed-off-by: Nandor Han > > Signed-off-by: Semi Malinen > (...) > > +exar Exar Corporation > > Send this as a separate patch to the DT bindings maintainer > (Rob Herring.) > OK. I will create a separate patch with this one. I guess is not an issue to send all the patches to Rob as well. > > + > > + ret = xra1403_get_byte(xra, addr + (bit > 7)); > > + if (ret < 0) > > + return ret; > > + > > + return !!(ret & BIT(bit % 8)); > > +} > > This looks like it can use regmap-spi right off, do you agree? > Yes. Using regmap-spi will definitely improve the code readability and reduce boilerplate. Done. > git grep devm_regmap_init_spi > should give you some examples of how to use it. > > If it's not off-the shelf regmap drivers like > drivers/iio/pressure/mpl115_spi.c > give examples of how to make more elaborate custom > SPI transfers with regmap. > Thanks, I did check other drivers as examples. Not that I needed for this driver, but ...mpl115_spi.c doesn't seem to use regmap (checked on next-20170327) > > + > > + if (value != ret) { > > + tx[0] = addr << 1; > > + tx[1] = value; > > + ret = spi_write(xra->spi, tx, sizeof(tx)); > > + } else { > > + ret = 0; > > + } > > + > > +out_unlock: > > + mutex_unlock(>lock); > > + > > + return ret; > > +} > > Classical mask-and-set implementation right? > With regmap this becomes simply regmap_update_bits(map, addr, mask, set) > True. :) > > + /* bring the chip out of reset */ > > + reset_gpio = gpiod_get_optional(>dev, "reset", GPIOD_OUT_LOW); > > + if (IS_ERR(reset_gpio)) > > + dev_warn(>dev, "could not get reset-gpios\n"); > > + else if (reset_gpio) > > + gpiod_put(reset_gpio); > > I don't think you should put it, other than in the remove() > function and in that case you need to have it in the > state container. Can you please be more explicit here. Currently I'm trying to bring the device out from reset in case reset GPIO is provided. I don't see how this could be done in remove() :) > > > + mutex_init(>lock); > > + > > + xra->chip.direction_input = xra1403_direction_input; > > + xra->chip.direction_output = xra1403_direction_output; > > Please implement .get_direction(). This is very nice to have. > Done > > +static int xra1403_remove(struct spi_device *spi) > > +{ > > + struct xra1403 *xra = spi_get_drvdata(spi); > > + > > + gpiochip_remove(>chip); > > Use devm_gpiochip_add_data() and this remove is not > needed at all. > True. Done > > +subsys_initcall(xra1403_init); > > + > > +static void __exit xra1403_exit(void) > > +{ > > + spi_unregister_driver(_driver); > > +} > > +module_exit(xra1403_exit); > > This seems like tricksy. Just module_spi_driver() > should be fine don't you think? Yeah. TBH I don't have a strong reason why module_spi_driver init level shouldn't be enough. Done. Regards, Nandor
[PATCH 0/3] XRA1403,gpio - add XRA1403 gpio expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 29 March 2017 04:51 > To: Han, Nandor (GE Healthcare) <nandor@ge.com> > Cc: Alexandre Courbot <gnu...@gmail.com>; Rob Herring <robh...@kernel.org>; > Mark Rutland > <mark.rutl...@arm.com>; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org > Subject: EXT: Re: [PATCH 0/3] XRA1403,gpio - add XRA1403 gpio expander driver > > Do *NOT* use the sysfs for testing GPIO. > This is being phased out. > > Use the tools in tools/gpio/* so that you exercise the > character device instead of the old deprecated ABI. > Thanks Linus, really good and helpful comments. I agree that make more sense to test with tools/gpio/*. > Yours, > Linus Walleij
[PATCH 0/3] XRA1403,gpio - add XRA1403 gpio expander driver
> -Original Message- > From: Linus Walleij [mailto:linus.wall...@linaro.org] > Sent: 29 March 2017 04:51 > To: Han, Nandor (GE Healthcare) > Cc: Alexandre Courbot ; Rob Herring ; > Mark Rutland > ; linux-g...@vger.kernel.org; > devicet...@vger.kernel.org; linux-kernel@vger.kernel.org > Subject: EXT: Re: [PATCH 0/3] XRA1403,gpio - add XRA1403 gpio expander driver > > Do *NOT* use the sysfs for testing GPIO. > This is being phased out. > > Use the tools in tools/gpio/* so that you exercise the > character device instead of the old deprecated ABI. > Thanks Linus, really good and helpful comments. I agree that make more sense to test with tools/gpio/*. > Yours, > Linus Walleij
Re: EXT: pre 4.9-rc dma regression, imx6 sound etc
On 12/10/2016 16:25, Mika Penttilä wrote: Hi! Bisected that commit 5881826 - "dmaengine: imx-sdma - update the residue calculation for cyclic channels" is first bad commit to cause audio regression on imx6q, sgtl5000 codec. It causes audible disturbing background noise when playing wavs. Unfortunately, reverting only 5881826 causes uarts to fail, so another fix is needed. Thanks, Mika Hi Mika, Thanks for info. I have already posted a patch that will fix this issue. https://lkml.org/lkml/2016/10/11/319 It was already tested on imx6 and imx53. Let me know how it works. -- Regards, Nandor
Re: EXT: pre 4.9-rc dma regression, imx6 sound etc
On 12/10/2016 16:25, Mika Penttilä wrote: Hi! Bisected that commit 5881826 - "dmaengine: imx-sdma - update the residue calculation for cyclic channels" is first bad commit to cause audio regression on imx6q, sgtl5000 codec. It causes audible disturbing background noise when playing wavs. Unfortunately, reverting only 5881826 causes uarts to fail, so another fix is needed. Thanks, Mika Hi Mika, Thanks for info. I have already posted a patch that will fix this issue. https://lkml.org/lkml/2016/10/11/319 It was already tested on imx6 and imx53. Let me know how it works. -- Regards, Nandor