* [PATCH v2 0/4] Add support for NXP LPC18xx EEPROM using nvmem @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Ariel D'Alessandro This patch series adds support for NXP LPC18xx EEPROM memory found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. This patchset is based on tag next-20151019 of the linux-next repository. It has been successfully tested on a LPC4337 CIAA-NXP Board. EEPROM notes: ------------ EEPROM size is 16384 bytes and it can be entirely read and written/erased with 1 word (4 bytes) granularity. The last page (128 bytes) contains the EEPROM initialization data and is not writable. Erase/program time is less than 3ms. The EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing the system bus clock by the division factor, contained in the divider register (minus 1 encoded). Changeset: --------- v1 -> v2: * Moved dt-bindings to be the first patch. * Changed compatible name from lpc1850 to lpc1857 as the former doesn't have EEPROM. * Fix hardware description which contained SoCs models without EEPROM. * Disabled fast_io and changed mdelay for msleep in regmap writes. * Replaced BUG_ON() in write function for an -EINVAL return. * Add patches for defconfig and devicetree files. Thanks, Ariel D'Alessandro (4): DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation nvmem: NXP LPC18xx EEPROM memory NVMEM driver ARM: dts: lpc18xx: add EEPROM memory node ARM: configs: lpc18xx: enable EEPROM NVMEM driver .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++ arch/arm/boot/dts/lpc18xx.dtsi | 12 + arch/arm/configs/lpc18xx_defconfig | 2 + drivers/nvmem/Kconfig | 9 + drivers/nvmem/Makefile | 2 + drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++ 6 files changed, 317 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt create mode 100644 drivers/nvmem/lpc18xx_eeprom.c -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 0/4] Add support for NXP LPC18xx EEPROM using nvmem @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel This patch series adds support for NXP LPC18xx EEPROM memory found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. This patchset is based on tag next-20151019 of the linux-next repository. It has been successfully tested on a LPC4337 CIAA-NXP Board. EEPROM notes: ------------ EEPROM size is 16384 bytes and it can be entirely read and written/erased with 1 word (4 bytes) granularity. The last page (128 bytes) contains the EEPROM initialization data and is not writable. Erase/program time is less than 3ms. The EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing the system bus clock by the division factor, contained in the divider register (minus 1 encoded). Changeset: --------- v1 -> v2: * Moved dt-bindings to be the first patch. * Changed compatible name from lpc1850 to lpc1857 as the former doesn't have EEPROM. * Fix hardware description which contained SoCs models without EEPROM. * Disabled fast_io and changed mdelay for msleep in regmap writes. * Replaced BUG_ON() in write function for an -EINVAL return. * Add patches for defconfig and devicetree files. Thanks, Ariel D'Alessandro (4): DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation nvmem: NXP LPC18xx EEPROM memory NVMEM driver ARM: dts: lpc18xx: add EEPROM memory node ARM: configs: lpc18xx: enable EEPROM NVMEM driver .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++ arch/arm/boot/dts/lpc18xx.dtsi | 12 + arch/arm/configs/lpc18xx_defconfig | 2 + drivers/nvmem/Kconfig | 9 + drivers/nvmem/Makefile | 2 + drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++ 6 files changed, 317 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt create mode 100644 drivers/nvmem/lpc18xx_eeprom.c -- 2.6.1 ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <1445275946-32653-1-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-19 17:32 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Ariel D'Alessandro Add the devicetree binding document for NXP LPC18xx EEPROM memory. Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> --- .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt new file mode 100644 index 0000000..01cde0d --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt @@ -0,0 +1,26 @@ +* NXP LPC18xx EEPROM memory NVMEM driver + +Required properties: + - compatible: Should be "nxp,lpc1857-eeprom" + - reg: Must contain an entry with the physical base address and length + for each entry in reg-names. + - reg-names: Must include the following entries. + - reg: EEPROM registers. + - mem: EEPROM address space. + - clocks: Must contain an entry for each entry in clock-names. + - clock-names: Must include the following entries. + - eeprom: EEPROM operating clock. + - interrupts: Should contain EEPROM interrupt. + +Example: + + eeprom: eeprom@4000e000 { + compatible = "nxp,lpc1857-eeprom"; + reg = <0x4000e000 0x1000>, + <0x20040000 0x4000>; + reg-names = "reg", "mem"; + clocks = <&ccu1 CLK_CPU_EEPROM>; + clock-names = "eeprom"; + resets = <&rgu 27>; + interrupts = <4>; + }; -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel Add the devicetree binding document for NXP LPC18xx EEPROM memory. Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> --- .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt new file mode 100644 index 0000000..01cde0d --- /dev/null +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt @@ -0,0 +1,26 @@ +* NXP LPC18xx EEPROM memory NVMEM driver + +Required properties: + - compatible: Should be "nxp,lpc1857-eeprom" + - reg: Must contain an entry with the physical base address and length + for each entry in reg-names. + - reg-names: Must include the following entries. + - reg: EEPROM registers. + - mem: EEPROM address space. + - clocks: Must contain an entry for each entry in clock-names. + - clock-names: Must include the following entries. + - eeprom: EEPROM operating clock. + - interrupts: Should contain EEPROM interrupt. + +Example: + + eeprom: eeprom at 4000e000 { + compatible = "nxp,lpc1857-eeprom"; + reg = <0x4000e000 0x1000>, + <0x20040000 0x4000>; + reg-names = "reg", "mem"; + clocks = <&ccu1 CLK_CPU_EEPROM>; + clock-names = "eeprom"; + resets = <&rgu 27>; + interrupts = <4>; + }; -- 2.6.1 ^ permalink raw reply related [flat|nested] 50+ messages in thread
[parent not found: <1445275946-32653-2-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-24 21:44 ` Joachim Eastwood -1 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:44 UTC (permalink / raw) To: Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > Add the devicetree binding document for NXP LPC18xx EEPROM memory. > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> > --- > .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > > diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > new file mode 100644 > index 0000000..01cde0d > --- /dev/null > +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > @@ -0,0 +1,26 @@ > +* NXP LPC18xx EEPROM memory NVMEM driver > + > +Required properties: > + - compatible: Should be "nxp,lpc1857-eeprom" > + - reg: Must contain an entry with the physical base address and length > + for each entry in reg-names. > + - reg-names: Must include the following entries. > + - reg: EEPROM registers. > + - mem: EEPROM address space. > + - clocks: Must contain an entry for each entry in clock-names. > + - clock-names: Must include the following entries. > + - eeprom: EEPROM operating clock. > + - interrupts: Should contain EEPROM interrupt. You should document the 'reset' property as well. > +Example: > + > + eeprom: eeprom@4000e000 { > + compatible = "nxp,lpc1857-eeprom"; > + reg = <0x4000e000 0x1000>, > + <0x20040000 0x4000>; > + reg-names = "reg", "mem"; > + clocks = <&ccu1 CLK_CPU_EEPROM>; > + clock-names = "eeprom"; > + resets = <&rgu 27>; > + interrupts = <4>; > + }; Other than that this looks good to me. Acked-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> regards, Joachim Eastwood -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation @ 2015-10-24 21:44 ` Joachim Eastwood 0 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:44 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > Add the devicetree binding document for NXP LPC18xx EEPROM memory. > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > --- > .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > > diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > new file mode 100644 > index 0000000..01cde0d > --- /dev/null > +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > @@ -0,0 +1,26 @@ > +* NXP LPC18xx EEPROM memory NVMEM driver > + > +Required properties: > + - compatible: Should be "nxp,lpc1857-eeprom" > + - reg: Must contain an entry with the physical base address and length > + for each entry in reg-names. > + - reg-names: Must include the following entries. > + - reg: EEPROM registers. > + - mem: EEPROM address space. > + - clocks: Must contain an entry for each entry in clock-names. > + - clock-names: Must include the following entries. > + - eeprom: EEPROM operating clock. > + - interrupts: Should contain EEPROM interrupt. You should document the 'reset' property as well. > +Example: > + > + eeprom: eeprom at 4000e000 { > + compatible = "nxp,lpc1857-eeprom"; > + reg = <0x4000e000 0x1000>, > + <0x20040000 0x4000>; > + reg-names = "reg", "mem"; > + clocks = <&ccu1 CLK_CPU_EEPROM>; > + clock-names = "eeprom"; > + resets = <&rgu 27>; > + interrupts = <4>; > + }; Other than that this looks good to me. Acked-by: Joachim Eastwood <manabian@gmail.com> regards, Joachim Eastwood ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <CAGhQ9VyCBTWh6qgZ__eNLqooNURsYr9ZVtDz2qCKoa0MoVgXtA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation 2015-10-24 21:44 ` Joachim Eastwood @ 2015-10-30 12:45 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 12:45 UTC (permalink / raw) To: Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Joachim, El 24/10/15 a las 18:44, Joachim Eastwood escribió: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >> Add the devicetree binding document for NXP LPC18xx EEPROM memory. >> >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >> --- >> .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ >> 1 file changed, 26 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> >> diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> new file mode 100644 >> index 0000000..01cde0d >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> @@ -0,0 +1,26 @@ >> +* NXP LPC18xx EEPROM memory NVMEM driver >> + >> +Required properties: >> + - compatible: Should be "nxp,lpc1857-eeprom" >> + - reg: Must contain an entry with the physical base address and length >> + for each entry in reg-names. >> + - reg-names: Must include the following entries. >> + - reg: EEPROM registers. >> + - mem: EEPROM address space. >> + - clocks: Must contain an entry for each entry in clock-names. >> + - clock-names: Must include the following entries. >> + - eeprom: EEPROM operating clock. >> + - interrupts: Should contain EEPROM interrupt. > > You should document the 'reset' property as well. Ok. Will do. > >> +Example: >> + >> + eeprom: eeprom@4000e000 { >> + compatible = "nxp,lpc1857-eeprom"; >> + reg = <0x4000e000 0x1000>, >> + <0x20040000 0x4000>; >> + reg-names = "reg", "mem"; >> + clocks = <&ccu1 CLK_CPU_EEPROM>; >> + clock-names = "eeprom"; >> + resets = <&rgu 27>; >> + interrupts = <4>; >> + }; > > Other than that this looks good to me. > > Acked-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > Great, thanks. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation @ 2015-10-30 12:45 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 12:45 UTC (permalink / raw) To: linux-arm-kernel Joachim, El 24/10/15 a las 18:44, Joachim Eastwood escribi?: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel@vanguardiasur.com.ar> wrote: >> Add the devicetree binding document for NXP LPC18xx EEPROM memory. >> >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >> --- >> .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ >> 1 file changed, 26 insertions(+) >> create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> >> diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> new file mode 100644 >> index 0000000..01cde0d >> --- /dev/null >> +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt >> @@ -0,0 +1,26 @@ >> +* NXP LPC18xx EEPROM memory NVMEM driver >> + >> +Required properties: >> + - compatible: Should be "nxp,lpc1857-eeprom" >> + - reg: Must contain an entry with the physical base address and length >> + for each entry in reg-names. >> + - reg-names: Must include the following entries. >> + - reg: EEPROM registers. >> + - mem: EEPROM address space. >> + - clocks: Must contain an entry for each entry in clock-names. >> + - clock-names: Must include the following entries. >> + - eeprom: EEPROM operating clock. >> + - interrupts: Should contain EEPROM interrupt. > > You should document the 'reset' property as well. Ok. Will do. > >> +Example: >> + >> + eeprom: eeprom at 4000e000 { >> + compatible = "nxp,lpc1857-eeprom"; >> + reg = <0x4000e000 0x1000>, >> + <0x20040000 0x4000>; >> + reg-names = "reg", "mem"; >> + clocks = <&ccu1 CLK_CPU_EEPROM>; >> + clock-names = "eeprom"; >> + resets = <&rgu 27>; >> + interrupts = <4>; >> + }; > > Other than that this looks good to me. > > Acked-by: Joachim Eastwood <manabian@gmail.com> > Great, thanks. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-27 7:49 ` Rob Herring -1 siblings, 0 replies; 50+ messages in thread From: Rob Herring @ 2015-10-27 7:49 UTC (permalink / raw) To: Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Joachim Eastwood, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll On Mon, Oct 19, 2015 at 12:32 PM, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > Add the devicetree binding document for NXP LPC18xx EEPROM memory. > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> > --- > .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > > diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > new file mode 100644 > index 0000000..01cde0d > --- /dev/null > +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > @@ -0,0 +1,26 @@ > +* NXP LPC18xx EEPROM memory NVMEM driver > + > +Required properties: > + - compatible: Should be "nxp,lpc1857-eeprom" > + - reg: Must contain an entry with the physical base address and length > + for each entry in reg-names. > + - reg-names: Must include the following entries. > + - reg: EEPROM registers. > + - mem: EEPROM address space. > + - clocks: Must contain an entry for each entry in clock-names. > + - clock-names: Must include the following entries. > + - eeprom: EEPROM operating clock. > + - interrupts: Should contain EEPROM interrupt. > + > +Example: > + > + eeprom: eeprom@4000e000 { > + compatible = "nxp,lpc1857-eeprom"; > + reg = <0x4000e000 0x1000>, > + <0x20040000 0x4000>; > + reg-names = "reg", "mem"; > + clocks = <&ccu1 CLK_CPU_EEPROM>; > + clock-names = "eeprom"; > + resets = <&rgu 27>; > + interrupts = <4>; > + }; > -- > 2.6.1 > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation @ 2015-10-27 7:49 ` Rob Herring 0 siblings, 0 replies; 50+ messages in thread From: Rob Herring @ 2015-10-27 7:49 UTC (permalink / raw) To: linux-arm-kernel On Mon, Oct 19, 2015 at 12:32 PM, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > Add the devicetree binding document for NXP LPC18xx EEPROM memory. > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> Acked-by: Rob Herring <robh@kernel.org> > --- > .../devicetree/bindings/nvmem/lpc1857-eeprom.txt | 26 ++++++++++++++++++++++ > 1 file changed, 26 insertions(+) > create mode 100644 Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > > diff --git a/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > new file mode 100644 > index 0000000..01cde0d > --- /dev/null > +++ b/Documentation/devicetree/bindings/nvmem/lpc1857-eeprom.txt > @@ -0,0 +1,26 @@ > +* NXP LPC18xx EEPROM memory NVMEM driver > + > +Required properties: > + - compatible: Should be "nxp,lpc1857-eeprom" > + - reg: Must contain an entry with the physical base address and length > + for each entry in reg-names. > + - reg-names: Must include the following entries. > + - reg: EEPROM registers. > + - mem: EEPROM address space. > + - clocks: Must contain an entry for each entry in clock-names. > + - clock-names: Must include the following entries. > + - eeprom: EEPROM operating clock. > + - interrupts: Should contain EEPROM interrupt. > + > +Example: > + > + eeprom: eeprom at 4000e000 { > + compatible = "nxp,lpc1857-eeprom"; > + reg = <0x4000e000 0x1000>, > + <0x20040000 0x4000>; > + reg-names = "reg", "mem"; > + clocks = <&ccu1 CLK_CPU_EEPROM>; > + clock-names = "eeprom"; > + resets = <&rgu 27>; > + interrupts = <4>; > + }; > -- > 2.6.1 > ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-19 17:32 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Ariel D'Alessandro This commit adds support for NXP LPC18xx EEPROM memory found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. EEPROM size is 16384 bytes and it can be entirely read and written/erased with 1 word (4 bytes) granularity. The last page (128 bytes) contains the EEPROM initialization data and is not writable. Erase/program time is less than 3ms. The EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing the system bus clock by the division factor, contained in the divider register (minus 1 encoded). Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> --- drivers/nvmem/Kconfig | 9 ++ drivers/nvmem/Makefile | 2 + drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/nvmem/lpc18xx_eeprom.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index bc4ea58..6ff1b50 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -25,6 +25,15 @@ config NVMEM_IMX_OCOTP This driver can also be built as a module. If so, the module will be called nvmem-imx-ocotp. +config NVMEM_LPC18XX_EEPROM + tristate "NXP LPC18XX EEPROM Memory Support" + depends on ARCH_LPC18XX || COMPILE_TEST + help + Say Y here to include support for NXP LPC18xx EEPROM memory found in + NXP LPC185x/3x and LPC435x/3x/2x/1x devices. + To compile this driver as a module, choose M here: the module + will be called nvmem_lpc18xx_eeprom. + config NVMEM_MXS_OCOTP tristate "Freescale MXS On-Chip OTP Memory Support" depends on ARCH_MXS || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 95dde3f..c14a556 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -8,6 +8,8 @@ nvmem_core-y := core.o # Devices obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o nvmem-imx-ocotp-y := imx-ocotp.o +obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o +nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o nvmem-mxs-ocotp-y := mxs-ocotp.o obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c new file mode 100644 index 0000000..ccdda66 --- /dev/null +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -0,0 +1,266 @@ +/* + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver + * + * Copyright (c) 2015 Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgC/G2K4zDHf@public.gmane.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +/* Registers */ +#define LPC18XX_EEPROM_AUTOPROG 0x00c +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 + +#define LPC18XX_EEPROM_CLKDIV 0x014 + +#define LPC18XX_EEPROM_PWRDWN 0x018 +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 + +/* Fixed page size (bytes) */ +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 + +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */ +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 + +struct lpc18xx_eeprom_dev { + struct clk *clk; + void __iomem *reg_base; + void __iomem *mem_base; + struct nvmem_device *nvmem; + unsigned reg_bytes; + unsigned val_bytes; +}; + +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom, + u32 reg, u32 val) +{ + writel(val, eeprom->reg_base + reg); +} + +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, + size_t reg_size, const void *val, + size_t val_size) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = *(u32 *)reg; + + /* 3 ms of erase/program time between each writing */ + while (val_size) { + writel(*(u32 *)val, eeprom->mem_base + offset); + usleep_range(3000, 4000); + val_size -= eeprom->val_bytes; + val += eeprom->val_bytes; + offset += eeprom->val_bytes; + } + + return 0; +} + +static int lpc18xx_eeprom_write(void *context, const void *data, size_t count) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = eeprom->reg_bytes; + + if (count <= offset) + return -EINVAL; + + + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, + data + offset, count - offset); +} + +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = *(u32 *)reg; + + while (val_size) { + *(u32 *)val = readl(eeprom->mem_base + offset); + val_size -= eeprom->val_bytes; + val += eeprom->val_bytes; + offset += eeprom->val_bytes; + } + + return 0; +} + +static struct regmap_bus lpc18xx_eeprom_bus = { + .write = lpc18xx_eeprom_write, + .gather_write = lpc18xx_eeprom_gather_write, + .read = lpc18xx_eeprom_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static struct regmap_config lpc18xx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static bool lpc18xx_eeprom_writeable_reg(struct device *dev, unsigned int reg) +{ + /* + * The last page contains the EEPROM initialization data and is not + * writable. + */ + return reg <= lpc18xx_regmap_config.max_register - + LPC18XX_EEPROM_PAGE_SIZE; +} + +static bool lpc18xx_eeprom_readable_reg(struct device *dev, unsigned int reg) +{ + return reg <= lpc18xx_regmap_config.max_register; +} + +static struct nvmem_config lpc18xx_nvmem_config = { + .name = "lpc18xx-eeprom", + .owner = THIS_MODULE, +}; + +static const struct of_device_id lpc18xx_eeprom_of_match[] = { + { .compatible = "nxp,lpc1857-eeprom" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); + +static int lpc18xx_eeprom_probe(struct platform_device *pdev) +{ + struct lpc18xx_eeprom_dev *eeprom; + struct device *dev = &pdev->dev; + struct reset_control *rst; + unsigned long clk_rate; + struct regmap *regmap; + struct resource *res; + int ret; + + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); + eeprom->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(eeprom->reg_base)) + return PTR_ERR(eeprom->reg_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); + eeprom->mem_base = devm_ioremap_resource(dev, res); + if (IS_ERR(eeprom->mem_base)) + return PTR_ERR(eeprom->mem_base); + + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); + if (IS_ERR(eeprom->clk)) { + dev_err(&pdev->dev, "failed to get eeprom clock\n"); + return PTR_ERR(eeprom->clk); + } + + ret = clk_prepare_enable(eeprom->clk); + if (ret < 0) { + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); + return ret; + } + + rst = devm_reset_control_get(dev, NULL); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); + ret = PTR_ERR(rst); + goto err_clk; + } + + ret = reset_control_deassert(rst); + if (ret < 0) { + dev_err(dev, "failed to deassert reset: %d\n", ret); + goto err_clk; + } + + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; + + /* + * Clock rate is generated by dividing the system bus clock by the + * division factor, contained in the divider register (minus 1 encoded). + */ + clk_rate = clk_get_rate(eeprom->clk); + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); + + /* + * Writing a single word to the page will start the erase/program cycle + * automatically + */ + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, + LPC18XX_EEPROM_AUTOPROG_WORD); + + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, + LPC18XX_EEPROM_PWRDWN_NO); + + lpc18xx_regmap_config.max_register = resource_size(res) - 1; + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; + + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, + &lpc18xx_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); + ret = PTR_ERR(regmap); + goto err_clk; + } + + lpc18xx_nvmem_config.dev = dev; + + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); + if (IS_ERR(eeprom->nvmem)) { + ret = PTR_ERR(eeprom->nvmem); + goto err_clk; + } + + platform_set_drvdata(pdev, eeprom); + + return 0; + +err_clk: + clk_disable_unprepare(eeprom->clk); + + return ret; +} + +static int lpc18xx_eeprom_remove(struct platform_device *pdev) +{ + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); + + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, + LPC18XX_EEPROM_PWRDWN_YES); + + clk_disable_unprepare(eeprom->clk); + + return nvmem_unregister(eeprom->nvmem); +} + +static struct platform_driver lpc18xx_eeprom_driver = { + .probe = lpc18xx_eeprom_probe, + .remove = lpc18xx_eeprom_remove, + .driver = { + .name = "lpc18xx-eeprom", + .of_match_table = lpc18xx_eeprom_of_match, + }, +}; + +module_platform_driver(lpc18xx_eeprom_driver); + +MODULE_AUTHOR("Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>"); +MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver"); +MODULE_LICENSE("GPL v2"); -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel This commit adds support for NXP LPC18xx EEPROM memory found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. EEPROM size is 16384 bytes and it can be entirely read and written/erased with 1 word (4 bytes) granularity. The last page (128 bytes) contains the EEPROM initialization data and is not writable. Erase/program time is less than 3ms. The EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing the system bus clock by the division factor, contained in the divider register (minus 1 encoded). Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> --- drivers/nvmem/Kconfig | 9 ++ drivers/nvmem/Makefile | 2 + drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 277 insertions(+) create mode 100644 drivers/nvmem/lpc18xx_eeprom.c diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig index bc4ea58..6ff1b50 100644 --- a/drivers/nvmem/Kconfig +++ b/drivers/nvmem/Kconfig @@ -25,6 +25,15 @@ config NVMEM_IMX_OCOTP This driver can also be built as a module. If so, the module will be called nvmem-imx-ocotp. +config NVMEM_LPC18XX_EEPROM + tristate "NXP LPC18XX EEPROM Memory Support" + depends on ARCH_LPC18XX || COMPILE_TEST + help + Say Y here to include support for NXP LPC18xx EEPROM memory found in + NXP LPC185x/3x and LPC435x/3x/2x/1x devices. + To compile this driver as a module, choose M here: the module + will be called nvmem_lpc18xx_eeprom. + config NVMEM_MXS_OCOTP tristate "Freescale MXS On-Chip OTP Memory Support" depends on ARCH_MXS || COMPILE_TEST diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile index 95dde3f..c14a556 100644 --- a/drivers/nvmem/Makefile +++ b/drivers/nvmem/Makefile @@ -8,6 +8,8 @@ nvmem_core-y := core.o # Devices obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o nvmem-imx-ocotp-y := imx-ocotp.o +obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o +nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o nvmem-mxs-ocotp-y := mxs-ocotp.o obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c new file mode 100644 index 0000000..ccdda66 --- /dev/null +++ b/drivers/nvmem/lpc18xx_eeprom.c @@ -0,0 +1,266 @@ +/* + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver + * + * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + */ + +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/nvmem-provider.h> +#include <linux/of_device.h> +#include <linux/regmap.h> +#include <linux/reset.h> + +/* Registers */ +#define LPC18XX_EEPROM_AUTOPROG 0x00c +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 + +#define LPC18XX_EEPROM_CLKDIV 0x014 + +#define LPC18XX_EEPROM_PWRDWN 0x018 +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 + +/* Fixed page size (bytes) */ +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 + +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */ +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 + +struct lpc18xx_eeprom_dev { + struct clk *clk; + void __iomem *reg_base; + void __iomem *mem_base; + struct nvmem_device *nvmem; + unsigned reg_bytes; + unsigned val_bytes; +}; + +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom, + u32 reg, u32 val) +{ + writel(val, eeprom->reg_base + reg); +} + +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, + size_t reg_size, const void *val, + size_t val_size) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = *(u32 *)reg; + + /* 3 ms of erase/program time between each writing */ + while (val_size) { + writel(*(u32 *)val, eeprom->mem_base + offset); + usleep_range(3000, 4000); + val_size -= eeprom->val_bytes; + val += eeprom->val_bytes; + offset += eeprom->val_bytes; + } + + return 0; +} + +static int lpc18xx_eeprom_write(void *context, const void *data, size_t count) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = eeprom->reg_bytes; + + if (count <= offset) + return -EINVAL; + + + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, + data + offset, count - offset); +} + +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, + void *val, size_t val_size) +{ + struct lpc18xx_eeprom_dev *eeprom = context; + unsigned int offset = *(u32 *)reg; + + while (val_size) { + *(u32 *)val = readl(eeprom->mem_base + offset); + val_size -= eeprom->val_bytes; + val += eeprom->val_bytes; + offset += eeprom->val_bytes; + } + + return 0; +} + +static struct regmap_bus lpc18xx_eeprom_bus = { + .write = lpc18xx_eeprom_write, + .gather_write = lpc18xx_eeprom_gather_write, + .read = lpc18xx_eeprom_read, + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, +}; + +static struct regmap_config lpc18xx_regmap_config = { + .reg_bits = 32, + .reg_stride = 4, + .val_bits = 32, +}; + +static bool lpc18xx_eeprom_writeable_reg(struct device *dev, unsigned int reg) +{ + /* + * The last page contains the EEPROM initialization data and is not + * writable. + */ + return reg <= lpc18xx_regmap_config.max_register - + LPC18XX_EEPROM_PAGE_SIZE; +} + +static bool lpc18xx_eeprom_readable_reg(struct device *dev, unsigned int reg) +{ + return reg <= lpc18xx_regmap_config.max_register; +} + +static struct nvmem_config lpc18xx_nvmem_config = { + .name = "lpc18xx-eeprom", + .owner = THIS_MODULE, +}; + +static const struct of_device_id lpc18xx_eeprom_of_match[] = { + { .compatible = "nxp,lpc1857-eeprom" }, + { }, +}; +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); + +static int lpc18xx_eeprom_probe(struct platform_device *pdev) +{ + struct lpc18xx_eeprom_dev *eeprom; + struct device *dev = &pdev->dev; + struct reset_control *rst; + unsigned long clk_rate; + struct regmap *regmap; + struct resource *res; + int ret; + + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); + if (!eeprom) + return -ENOMEM; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); + eeprom->reg_base = devm_ioremap_resource(dev, res); + if (IS_ERR(eeprom->reg_base)) + return PTR_ERR(eeprom->reg_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); + eeprom->mem_base = devm_ioremap_resource(dev, res); + if (IS_ERR(eeprom->mem_base)) + return PTR_ERR(eeprom->mem_base); + + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); + if (IS_ERR(eeprom->clk)) { + dev_err(&pdev->dev, "failed to get eeprom clock\n"); + return PTR_ERR(eeprom->clk); + } + + ret = clk_prepare_enable(eeprom->clk); + if (ret < 0) { + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); + return ret; + } + + rst = devm_reset_control_get(dev, NULL); + if (IS_ERR(rst)) { + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); + ret = PTR_ERR(rst); + goto err_clk; + } + + ret = reset_control_deassert(rst); + if (ret < 0) { + dev_err(dev, "failed to deassert reset: %d\n", ret); + goto err_clk; + } + + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; + + /* + * Clock rate is generated by dividing the system bus clock by the + * division factor, contained in the divider register (minus 1 encoded). + */ + clk_rate = clk_get_rate(eeprom->clk); + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); + + /* + * Writing a single word to the page will start the erase/program cycle + * automatically + */ + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, + LPC18XX_EEPROM_AUTOPROG_WORD); + + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, + LPC18XX_EEPROM_PWRDWN_NO); + + lpc18xx_regmap_config.max_register = resource_size(res) - 1; + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; + + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, + &lpc18xx_regmap_config); + if (IS_ERR(regmap)) { + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); + ret = PTR_ERR(regmap); + goto err_clk; + } + + lpc18xx_nvmem_config.dev = dev; + + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); + if (IS_ERR(eeprom->nvmem)) { + ret = PTR_ERR(eeprom->nvmem); + goto err_clk; + } + + platform_set_drvdata(pdev, eeprom); + + return 0; + +err_clk: + clk_disable_unprepare(eeprom->clk); + + return ret; +} + +static int lpc18xx_eeprom_remove(struct platform_device *pdev) +{ + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); + + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, + LPC18XX_EEPROM_PWRDWN_YES); + + clk_disable_unprepare(eeprom->clk); + + return nvmem_unregister(eeprom->nvmem); +} + +static struct platform_driver lpc18xx_eeprom_driver = { + .probe = lpc18xx_eeprom_probe, + .remove = lpc18xx_eeprom_remove, + .driver = { + .name = "lpc18xx-eeprom", + .of_match_table = lpc18xx_eeprom_of_match, + }, +}; + +module_platform_driver(lpc18xx_eeprom_driver); + +MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>"); +MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver"); +MODULE_LICENSE("GPL v2"); -- 2.6.1 ^ permalink raw reply related [flat|nested] 50+ messages in thread
[parent not found: <1445275946-32653-3-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-24 22:04 ` Joachim Eastwood -1 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 22:04 UTC (permalink / raw) To: Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } What happens here if 'val_size' is less than 4 or not dividable by 4? Same thing for 'offset'. I tested the driver from sysfs by writing strings into the nvmem-file with echo. Writing a string not dividable by 4 seems to hang the system. > +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, > + void *val, size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + while (val_size) { > + *(u32 *)val = readl(eeprom->mem_base + offset); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} Same comments as for lpc18xx_eeprom_gather_write(). > +static const struct of_device_id lpc18xx_eeprom_of_match[] = { > + { .compatible = "nxp,lpc1857-eeprom" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); nit: It's usual to place of_device_id struct just above the platform_driver struct. > + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; > + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; There is a BITS_PER_BYTE define in bitops.h that you might want to use here. > + /* > + * Clock rate is generated by dividing the system bus clock by the > + * division factor, contained in the divider register (minus 1 encoded). > + */ > + clk_rate = clk_get_rate(eeprom->clk); > + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); > + > + /* > + * Writing a single word to the page will start the erase/program cycle > + * automatically > + */ > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, > + LPC18XX_EEPROM_AUTOPROG_WORD); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_NO); > + > + lpc18xx_regmap_config.max_register = resource_size(res) - 1; > + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; > + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; > + > + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, > + &lpc18xx_regmap_config); > + if (IS_ERR(regmap)) { > + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); > + ret = PTR_ERR(regmap); > + goto err_clk; > + } > + > + lpc18xx_nvmem_config.dev = dev; > + > + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); > + if (IS_ERR(eeprom->nvmem)) { > + ret = PTR_ERR(eeprom->nvmem); > + goto err_clk; > + } > + > + platform_set_drvdata(pdev, eeprom); > + > + return 0; > + > +err_clk: > + clk_disable_unprepare(eeprom->clk); > + > + return ret; > +} > + > +static int lpc18xx_eeprom_remove(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_YES); > + > + clk_disable_unprepare(eeprom->clk); > + > + return nvmem_unregister(eeprom->nvmem); Normally you do tear down in the reverse order of initialization. Consider what happens here when you power down and disable the clock while there still are nvmem users of the eeprom. regards, Joachim Eastwood -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-24 22:04 ` Joachim Eastwood 0 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 22:04 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } What happens here if 'val_size' is less than 4 or not dividable by 4? Same thing for 'offset'. I tested the driver from sysfs by writing strings into the nvmem-file with echo. Writing a string not dividable by 4 seems to hang the system. > +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, > + void *val, size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + while (val_size) { > + *(u32 *)val = readl(eeprom->mem_base + offset); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} Same comments as for lpc18xx_eeprom_gather_write(). > +static const struct of_device_id lpc18xx_eeprom_of_match[] = { > + { .compatible = "nxp,lpc1857-eeprom" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); nit: It's usual to place of_device_id struct just above the platform_driver struct. > + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; > + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; There is a BITS_PER_BYTE define in bitops.h that you might want to use here. > + /* > + * Clock rate is generated by dividing the system bus clock by the > + * division factor, contained in the divider register (minus 1 encoded). > + */ > + clk_rate = clk_get_rate(eeprom->clk); > + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); > + > + /* > + * Writing a single word to the page will start the erase/program cycle > + * automatically > + */ > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, > + LPC18XX_EEPROM_AUTOPROG_WORD); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_NO); > + > + lpc18xx_regmap_config.max_register = resource_size(res) - 1; > + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; > + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; > + > + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, > + &lpc18xx_regmap_config); > + if (IS_ERR(regmap)) { > + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); > + ret = PTR_ERR(regmap); > + goto err_clk; > + } > + > + lpc18xx_nvmem_config.dev = dev; > + > + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); > + if (IS_ERR(eeprom->nvmem)) { > + ret = PTR_ERR(eeprom->nvmem); > + goto err_clk; > + } > + > + platform_set_drvdata(pdev, eeprom); > + > + return 0; > + > +err_clk: > + clk_disable_unprepare(eeprom->clk); > + > + return ret; > +} > + > +static int lpc18xx_eeprom_remove(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_YES); > + > + clk_disable_unprepare(eeprom->clk); > + > + return nvmem_unregister(eeprom->nvmem); Normally you do tear down in the reverse order of initialization. Consider what happens here when you power down and disable the clock while there still are nvmem users of the eeprom. regards, Joachim Eastwood ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <CAGhQ9Vyg6sScq7yM=7judsMPHOc5VF2zf=7LPxmbmL7wF=vvgw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-24 22:04 ` Joachim Eastwood @ 2015-10-26 13:37 ` Srinivas Kandagatla -1 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-10-26 13:37 UTC (permalink / raw) To: Joachim Eastwood, Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring On 24/10/15 23:04, Joachim Eastwood wrote: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } > > What happens here if 'val_size' is less than 4 or not dividable by 4? > Same thing for 'offset'. > > I tested the driver from sysfs by writing strings into the nvmem-file > with echo. Writing a string not dividable by 4 seems to hang the > system. > I think I know the issue here: Could you try this patch: -------------------------------->cut<---------------------------------- From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Date: Mon, 26 Oct 2015 13:30:24 +0000 Subject: [PATCH] nvmem: core: return error for non word aligned bytes nvmem providers have restrictions on register strides, so return error code when users attempt to read/write buffers with sizes which are not aligned to the word boundary. Without this patch the userspace would continue to try as it does not get any error from the nvmem core, resulting in a hang. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/nvmem/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 6fd4e5a..9d11d98 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, if (pos >= nvmem->size) return 0; + if (count < nvmem->word_size) + return -EINVAL; + if (pos + count > nvmem->size) count = nvmem->size - pos; @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, if (pos >= nvmem->size) return 0; + if (count < nvmem->word_size) + return -EINVAL; + if (pos + count > nvmem->size) count = nvmem->size - pos; -- 1.9.1 -------------------------------->cut<---------------------------------- --srini > >> +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, >> + void *val, size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + while (val_size) { >> + *(u32 *)val = readl(eeprom->mem_base + offset); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} > > Same comments as for lpc18xx_eeprom_gather_write(). > > >> +static const struct of_device_id lpc18xx_eeprom_of_match[] = { >> + { .compatible = "nxp,lpc1857-eeprom" }, >> + { }, >> +}; >> +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > > nit: It's usual to place of_device_id struct just above the > platform_driver struct. > > >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > > There is a BITS_PER_BYTE define in bitops.h that you might want to use here. > > >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Normally you do tear down in the reverse order of initialization. > > Consider what happens here when you power down and disable the clock > while there still are nvmem users of the eeprom. > > > regards, > Joachim Eastwood > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-26 13:37 ` Srinivas Kandagatla 0 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-10-26 13:37 UTC (permalink / raw) To: linux-arm-kernel On 24/10/15 23:04, Joachim Eastwood wrote: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel@vanguardiasur.com.ar> wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } > > What happens here if 'val_size' is less than 4 or not dividable by 4? > Same thing for 'offset'. > > I tested the driver from sysfs by writing strings into the nvmem-file > with echo. Writing a string not dividable by 4 seems to hang the > system. > I think I know the issue here: Could you try this patch: -------------------------------->cut<---------------------------------- From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> Date: Mon, 26 Oct 2015 13:30:24 +0000 Subject: [PATCH] nvmem: core: return error for non word aligned bytes nvmem providers have restrictions on register strides, so return error code when users attempt to read/write buffers with sizes which are not aligned to the word boundary. Without this patch the userspace would continue to try as it does not get any error from the nvmem core, resulting in a hang. Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> --- drivers/nvmem/core.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c index 6fd4e5a..9d11d98 100644 --- a/drivers/nvmem/core.c +++ b/drivers/nvmem/core.c @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj, if (pos >= nvmem->size) return 0; + if (count < nvmem->word_size) + return -EINVAL; + if (pos + count > nvmem->size) count = nvmem->size - pos; @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj, if (pos >= nvmem->size) return 0; + if (count < nvmem->word_size) + return -EINVAL; + if (pos + count > nvmem->size) count = nvmem->size - pos; -- 1.9.1 -------------------------------->cut<---------------------------------- --srini > >> +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, >> + void *val, size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + while (val_size) { >> + *(u32 *)val = readl(eeprom->mem_base + offset); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} > > Same comments as for lpc18xx_eeprom_gather_write(). > > >> +static const struct of_device_id lpc18xx_eeprom_of_match[] = { >> + { .compatible = "nxp,lpc1857-eeprom" }, >> + { }, >> +}; >> +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > > nit: It's usual to place of_device_id struct just above the > platform_driver struct. > > >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > > There is a BITS_PER_BYTE define in bitops.h that you might want to use here. > > >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Normally you do tear down in the reverse order of initialization. > > Consider what happens here when you power down and disable the clock > while there still are nvmem users of the eeprom. > > > regards, > Joachim Eastwood > ^ permalink raw reply related [flat|nested] 50+ messages in thread
[parent not found: <562E2CB1.80706-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-26 13:37 ` Srinivas Kandagatla @ 2015-10-30 14:58 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 14:58 UTC (permalink / raw) To: Srinivas Kandagatla, Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Srinivas, El 26/10/15 a las 10:37, Srinivas Kandagatla escribió: > > > On 24/10/15 23:04, Joachim Eastwood wrote: >> Hi Ariel, >> >> On 19 October 2015 at 19:32, Ariel D'Alessandro >> <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>> >>> EEPROM size is 16384 bytes and it can be entirely read and >>> written/erased with 1 word (4 bytes) granularity. The last page >>> (128 bytes) contains the EEPROM initialization data and is not writable. >>> >>> Erase/program time is less than 3ms. The EEPROM device requires a >>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>> the system bus clock by the division factor, contained in the divider >>> register (minus 1 encoded). >>> >>> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >>> --- >>> drivers/nvmem/Kconfig | 9 ++ >>> drivers/nvmem/Makefile | 2 + >>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>> +++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 277 insertions(+) >>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> >>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>> + size_t reg_size, const void *val, >>> + size_t val_size) >>> +{ >>> + struct lpc18xx_eeprom_dev *eeprom = context; >>> + unsigned int offset = *(u32 *)reg; >>> + >>> + /* 3 ms of erase/program time between each writing */ >>> + while (val_size) { >>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>> + usleep_range(3000, 4000); >>> + val_size -= eeprom->val_bytes; >>> + val += eeprom->val_bytes; >>> + offset += eeprom->val_bytes; >>> + } >> >> What happens here if 'val_size' is less than 4 or not dividable by 4? >> Same thing for 'offset'. >> >> I tested the driver from sysfs by writing strings into the nvmem-file >> with echo. Writing a string not dividable by 4 seems to hang the >> system. >> > > I think I know the issue here: > Could you try this patch: > > -------------------------------->cut<---------------------------------- > From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 > From: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > Date: Mon, 26 Oct 2015 13:30:24 +0000 > Subject: [PATCH] nvmem: core: return error for non word aligned bytes > > nvmem providers have restrictions on register strides, so return error > code when users attempt to read/write buffers with sizes which are not > aligned to the word boundary. > > Without this patch the userspace would continue to try as it does not > get any error from the nvmem core, resulting in a hang. > > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> > --- > drivers/nvmem/core.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c > index 6fd4e5a..9d11d98 100644 > --- a/drivers/nvmem/core.c > +++ b/drivers/nvmem/core.c > @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, > struct kobject *kobj, > if (pos >= nvmem->size) > return 0; > > + if (count < nvmem->word_size) > + return -EINVAL; > + > if (pos + count > nvmem->size) > count = nvmem->size - pos; > > @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, > struct kobject *kobj, > if (pos >= nvmem->size) > return 0; > > + if (count < nvmem->word_size) > + return -EINVAL; > + > if (pos + count > nvmem->size) > count = nvmem->size - pos; > Patch looks good to me. I think that it solves the issue. I don't have the board here right now, so I'll check it ASAP and give some feedback. Thanks! -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-30 14:58 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 14:58 UTC (permalink / raw) To: linux-arm-kernel Srinivas, El 26/10/15 a las 10:37, Srinivas Kandagatla escribi?: > > > On 24/10/15 23:04, Joachim Eastwood wrote: >> Hi Ariel, >> >> On 19 October 2015 at 19:32, Ariel D'Alessandro >> <ariel@vanguardiasur.com.ar> wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>> >>> EEPROM size is 16384 bytes and it can be entirely read and >>> written/erased with 1 word (4 bytes) granularity. The last page >>> (128 bytes) contains the EEPROM initialization data and is not writable. >>> >>> Erase/program time is less than 3ms. The EEPROM device requires a >>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>> the system bus clock by the division factor, contained in the divider >>> register (minus 1 encoded). >>> >>> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >>> --- >>> drivers/nvmem/Kconfig | 9 ++ >>> drivers/nvmem/Makefile | 2 + >>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>> +++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 277 insertions(+) >>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> >>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>> + size_t reg_size, const void *val, >>> + size_t val_size) >>> +{ >>> + struct lpc18xx_eeprom_dev *eeprom = context; >>> + unsigned int offset = *(u32 *)reg; >>> + >>> + /* 3 ms of erase/program time between each writing */ >>> + while (val_size) { >>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>> + usleep_range(3000, 4000); >>> + val_size -= eeprom->val_bytes; >>> + val += eeprom->val_bytes; >>> + offset += eeprom->val_bytes; >>> + } >> >> What happens here if 'val_size' is less than 4 or not dividable by 4? >> Same thing for 'offset'. >> >> I tested the driver from sysfs by writing strings into the nvmem-file >> with echo. Writing a string not dividable by 4 seems to hang the >> system. >> > > I think I know the issue here: > Could you try this patch: > > -------------------------------->cut<---------------------------------- > From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 > From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> > Date: Mon, 26 Oct 2015 13:30:24 +0000 > Subject: [PATCH] nvmem: core: return error for non word aligned bytes > > nvmem providers have restrictions on register strides, so return error > code when users attempt to read/write buffers with sizes which are not > aligned to the word boundary. > > Without this patch the userspace would continue to try as it does not > get any error from the nvmem core, resulting in a hang. > > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> > --- > drivers/nvmem/core.c | 6 ++++++ > 1 file changed, 6 insertions(+) > > diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c > index 6fd4e5a..9d11d98 100644 > --- a/drivers/nvmem/core.c > +++ b/drivers/nvmem/core.c > @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, > struct kobject *kobj, > if (pos >= nvmem->size) > return 0; > > + if (count < nvmem->word_size) > + return -EINVAL; > + > if (pos + count > nvmem->size) > count = nvmem->size - pos; > > @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, > struct kobject *kobj, > if (pos >= nvmem->size) > return 0; > > + if (count < nvmem->word_size) > + return -EINVAL; > + > if (pos + count > nvmem->size) > count = nvmem->size - pos; > Patch looks good to me. I think that it solves the issue. I don't have the board here right now, so I'll check it ASAP and give some feedback. Thanks! -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <563385B2.90403-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-30 14:58 ` Ariel D'Alessandro @ 2015-11-16 15:33 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:33 UTC (permalink / raw) To: Srinivas Kandagatla, Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Srinivas, Sorry for the delay, I finally got the hardware again. El 30/10/15 a las 11:58, Ariel D'Alessandro escribió: > Srinivas, > > El 26/10/15 a las 10:37, Srinivas Kandagatla escribió: >> >> >> On 24/10/15 23:04, Joachim Eastwood wrote: >>> Hi Ariel, >>> >>> On 19 October 2015 at 19:32, Ariel D'Alessandro >>> <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >>>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>>> >>>> EEPROM size is 16384 bytes and it can be entirely read and >>>> written/erased with 1 word (4 bytes) granularity. The last page >>>> (128 bytes) contains the EEPROM initialization data and is not writable. >>>> >>>> Erase/program time is less than 3ms. The EEPROM device requires a >>>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>>> the system bus clock by the division factor, contained in the divider >>>> register (minus 1 encoded). >>>> >>>> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >>>> --- >>>> drivers/nvmem/Kconfig | 9 ++ >>>> drivers/nvmem/Makefile | 2 + >>>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>>> +++++++++++++++++++++++++++++++++++++++++ >>>> 3 files changed, 277 insertions(+) >>>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >>> >>>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>>> + size_t reg_size, const void *val, >>>> + size_t val_size) >>>> +{ >>>> + struct lpc18xx_eeprom_dev *eeprom = context; >>>> + unsigned int offset = *(u32 *)reg; >>>> + >>>> + /* 3 ms of erase/program time between each writing */ >>>> + while (val_size) { >>>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>>> + usleep_range(3000, 4000); >>>> + val_size -= eeprom->val_bytes; >>>> + val += eeprom->val_bytes; >>>> + offset += eeprom->val_bytes; >>>> + } >>> >>> What happens here if 'val_size' is less than 4 or not dividable by 4? >>> Same thing for 'offset'. >>> >>> I tested the driver from sysfs by writing strings into the nvmem-file >>> with echo. Writing a string not dividable by 4 seems to hang the >>> system. >>> >> >> I think I know the issue here: >> Could you try this patch: >> >> -------------------------------->cut<---------------------------------- >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 >> From: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> Date: Mon, 26 Oct 2015 13:30:24 +0000 >> Subject: [PATCH] nvmem: core: return error for non word aligned bytes >> >> nvmem providers have restrictions on register strides, so return error >> code when users attempt to read/write buffers with sizes which are not >> aligned to the word boundary. >> >> Without this patch the userspace would continue to try as it does not >> get any error from the nvmem core, resulting in a hang. >> >> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >> --- >> drivers/nvmem/core.c | 6 ++++++ >> 1 file changed, 6 insertions(+) >> >> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >> index 6fd4e5a..9d11d98 100644 >> --- a/drivers/nvmem/core.c >> +++ b/drivers/nvmem/core.c >> @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, >> struct kobject *kobj, >> if (pos >= nvmem->size) >> return 0; >> >> + if (count < nvmem->word_size) >> + return -EINVAL; >> + >> if (pos + count > nvmem->size) >> count = nvmem->size - pos; >> >> @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, >> struct kobject *kobj, >> if (pos >= nvmem->size) >> return 0; >> >> + if (count < nvmem->word_size) >> + return -EINVAL; >> + >> if (pos + count > nvmem->size) >> count = nvmem->size - pos; >> > > Patch looks good to me. I think that it solves the issue. > I don't have the board here right now, so I'll check it ASAP and give > some feedback. Finally tested this. As it seemed, it solved the issue. Are you submitting a patch for this? Thanks again. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-16 15:33 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:33 UTC (permalink / raw) To: linux-arm-kernel Srinivas, Sorry for the delay, I finally got the hardware again. El 30/10/15 a las 11:58, Ariel D'Alessandro escribi?: > Srinivas, > > El 26/10/15 a las 10:37, Srinivas Kandagatla escribi?: >> >> >> On 24/10/15 23:04, Joachim Eastwood wrote: >>> Hi Ariel, >>> >>> On 19 October 2015 at 19:32, Ariel D'Alessandro >>> <ariel@vanguardiasur.com.ar> wrote: >>>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>>> >>>> EEPROM size is 16384 bytes and it can be entirely read and >>>> written/erased with 1 word (4 bytes) granularity. The last page >>>> (128 bytes) contains the EEPROM initialization data and is not writable. >>>> >>>> Erase/program time is less than 3ms. The EEPROM device requires a >>>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>>> the system bus clock by the division factor, contained in the divider >>>> register (minus 1 encoded). >>>> >>>> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >>>> --- >>>> drivers/nvmem/Kconfig | 9 ++ >>>> drivers/nvmem/Makefile | 2 + >>>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>>> +++++++++++++++++++++++++++++++++++++++++ >>>> 3 files changed, 277 insertions(+) >>>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >>> >>>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>>> + size_t reg_size, const void *val, >>>> + size_t val_size) >>>> +{ >>>> + struct lpc18xx_eeprom_dev *eeprom = context; >>>> + unsigned int offset = *(u32 *)reg; >>>> + >>>> + /* 3 ms of erase/program time between each writing */ >>>> + while (val_size) { >>>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>>> + usleep_range(3000, 4000); >>>> + val_size -= eeprom->val_bytes; >>>> + val += eeprom->val_bytes; >>>> + offset += eeprom->val_bytes; >>>> + } >>> >>> What happens here if 'val_size' is less than 4 or not dividable by 4? >>> Same thing for 'offset'. >>> >>> I tested the driver from sysfs by writing strings into the nvmem-file >>> with echo. Writing a string not dividable by 4 seems to hang the >>> system. >>> >> >> I think I know the issue here: >> Could you try this patch: >> >> -------------------------------->cut<---------------------------------- >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 >> From: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> >> Date: Mon, 26 Oct 2015 13:30:24 +0000 >> Subject: [PATCH] nvmem: core: return error for non word aligned bytes >> >> nvmem providers have restrictions on register strides, so return error >> code when users attempt to read/write buffers with sizes which are not >> aligned to the word boundary. >> >> Without this patch the userspace would continue to try as it does not >> get any error from the nvmem core, resulting in a hang. >> >> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org> >> --- >> drivers/nvmem/core.c | 6 ++++++ >> 1 file changed, 6 insertions(+) >> >> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >> index 6fd4e5a..9d11d98 100644 >> --- a/drivers/nvmem/core.c >> +++ b/drivers/nvmem/core.c >> @@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, >> struct kobject *kobj, >> if (pos >= nvmem->size) >> return 0; >> >> + if (count < nvmem->word_size) >> + return -EINVAL; >> + >> if (pos + count > nvmem->size) >> count = nvmem->size - pos; >> >> @@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, >> struct kobject *kobj, >> if (pos >= nvmem->size) >> return 0; >> >> + if (count < nvmem->word_size) >> + return -EINVAL; >> + >> if (pos + count > nvmem->size) >> count = nvmem->size - pos; >> > > Patch looks good to me. I think that it solves the issue. > I don't have the board here right now, so I'll check it ASAP and give > some feedback. Finally tested this. As it seemed, it solved the issue. Are you submitting a patch for this? Thanks again. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <5649F74A.9020706-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-11-16 15:33 ` Ariel D'Alessandro @ 2015-11-16 15:37 ` Srinivas Kandagatla -1 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-11-16 15:37 UTC (permalink / raw) To: Ariel D'Alessandro, Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring On 16/11/15 15:33, Ariel D'Alessandro wrote: >>> >>-------------------------------->cut<---------------------------------- >>> >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 >>> >>From: Srinivas Kandagatla<srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >>> >>Date: Mon, 26 Oct 2015 13:30:24 +0000 >>> >>Subject: [PATCH] nvmem: core: return error for non word aligned bytes >>> >> >>> >>nvmem providers have restrictions on register strides, so return error >>> >>code when users attempt to read/write buffers with sizes which are not >>> >>aligned to the word boundary. >>> >> >>> >>Without this patch the userspace would continue to try as it does not >>> >>get any error from the nvmem core, resulting in a hang. >>> >> >>> >>Signed-off-by: Srinivas Kandagatla<srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >>> >>--- >>> >> drivers/nvmem/core.c | 6 ++++++ >>> >> 1 file changed, 6 insertions(+) >>> >> >>> >>diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >>> >>index 6fd4e5a..9d11d98 100644 >>> >>--- a/drivers/nvmem/core.c >>> >>+++ b/drivers/nvmem/core.c >>> >>@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, >>> >>struct kobject *kobj, >>> >> if (pos >= nvmem->size) >>> >> return 0; >>> >> >>> >>+ if (count < nvmem->word_size) >>> >>+ return -EINVAL; >>> >>+ >>> >> if (pos + count > nvmem->size) >>> >> count = nvmem->size - pos; >>> >> >>> >>@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, >>> >>struct kobject *kobj, >>> >> if (pos >= nvmem->size) >>> >> return 0; >>> >> >>> >>+ if (count < nvmem->word_size) >>> >>+ return -EINVAL; >>> >>+ >>> >> if (pos + count > nvmem->size) >>> >> count = nvmem->size - pos; >>> >> >> > >> >Patch looks good to me. I think that it solves the issue. >> >I don't have the board here right now, so I'll check it ASAP and give >> >some feedback. > Finally tested this. As it seemed, it solved the issue. > Are you submitting a patch for this? Yes, I will send a patch to the mailing list. --srini > > Thanks again. -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-16 15:37 ` Srinivas Kandagatla 0 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-11-16 15:37 UTC (permalink / raw) To: linux-arm-kernel On 16/11/15 15:33, Ariel D'Alessandro wrote: >>> >>-------------------------------->cut<---------------------------------- >>> >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 2001 >>> >>From: Srinivas Kandagatla<srinivas.kandagatla@linaro.org> >>> >>Date: Mon, 26 Oct 2015 13:30:24 +0000 >>> >>Subject: [PATCH] nvmem: core: return error for non word aligned bytes >>> >> >>> >>nvmem providers have restrictions on register strides, so return error >>> >>code when users attempt to read/write buffers with sizes which are not >>> >>aligned to the word boundary. >>> >> >>> >>Without this patch the userspace would continue to try as it does not >>> >>get any error from the nvmem core, resulting in a hang. >>> >> >>> >>Signed-off-by: Srinivas Kandagatla<srinivas.kandagatla@linaro.org> >>> >>--- >>> >> drivers/nvmem/core.c | 6 ++++++ >>> >> 1 file changed, 6 insertions(+) >>> >> >>> >>diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >>> >>index 6fd4e5a..9d11d98 100644 >>> >>--- a/drivers/nvmem/core.c >>> >>+++ b/drivers/nvmem/core.c >>> >>@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, >>> >>struct kobject *kobj, >>> >> if (pos >= nvmem->size) >>> >> return 0; >>> >> >>> >>+ if (count < nvmem->word_size) >>> >>+ return -EINVAL; >>> >>+ >>> >> if (pos + count > nvmem->size) >>> >> count = nvmem->size - pos; >>> >> >>> >>@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, >>> >>struct kobject *kobj, >>> >> if (pos >= nvmem->size) >>> >> return 0; >>> >> >>> >>+ if (count < nvmem->word_size) >>> >>+ return -EINVAL; >>> >>+ >>> >> if (pos + count > nvmem->size) >>> >> count = nvmem->size - pos; >>> >> >> > >> >Patch looks good to me. I think that it solves the issue. >> >I don't have the board here right now, so I'll check it ASAP and give >> >some feedback. > Finally tested this. As it seemed, it solved the issue. > Are you submitting a patch for this? Yes, I will send a patch to the mailing list. --srini > > Thanks again. ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <5649F856.9000101-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-11-16 15:37 ` Srinivas Kandagatla @ 2015-12-03 18:39 ` Ezequiel Garcia -1 siblings, 0 replies; 50+ messages in thread From: Ezequiel Garcia @ 2015-12-03 18:39 UTC (permalink / raw) To: Srinivas Kandagatla Cc: Ariel D'Alessandro, Joachim Eastwood, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Srinivas, On 16 November 2015 at 12:37, Srinivas Kandagatla <srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote: > > > On 16/11/15 15:33, Ariel D'Alessandro wrote: >>>> >>>> >>>> >> >>-------------------------------->cut<---------------------------------- >>>> >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 >>>> >> 2001 >>>> >>From: Srinivas Kandagatla<srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> >>>> >>Date: Mon, 26 Oct 2015 13:30:24 +0000 >>>> >>Subject: [PATCH] nvmem: core: return error for non word aligned bytes >>>> >> >>>> >>nvmem providers have restrictions on register strides, so return error >>>> >>code when users attempt to read/write buffers with sizes which are not >>>> >>aligned to the word boundary. >>>> >> >>>> >>Without this patch the userspace would continue to try as it does not >>>> >>get any error from the nvmem core, resulting in a hang. >>>> >> >>>> >>Signed-off-by: Srinivas Kandagatla<srinivas.kandagatla-QSEj5FYQhm5QFI55V6+gNQ@public.gmane.orgg> >>>> >>--- >>>> >> drivers/nvmem/core.c | 6 ++++++ >>>> >> 1 file changed, 6 insertions(+) >>>> >> >>>> >>diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >>>> >>index 6fd4e5a..9d11d98 100644 >>>> >>--- a/drivers/nvmem/core.c >>>> >>+++ b/drivers/nvmem/core.c >>>> >>@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file >>>> >> *filp, >>>> >>struct kobject *kobj, >>>> >> if (pos >= nvmem->size) >>>> >> return 0; >>>> >> >>>> >>+ if (count < nvmem->word_size) >>>> >>+ return -EINVAL; >>>> >>+ >>>> >> if (pos + count > nvmem->size) >>>> >> count = nvmem->size - pos; >>>> >> >>>> >>@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file >>>> >> *filp, >>>> >>struct kobject *kobj, >>>> >> if (pos >= nvmem->size) >>>> >> return 0; >>>> >> >>>> >>+ if (count < nvmem->word_size) >>>> >>+ return -EINVAL; >>>> >>+ >>>> >> if (pos + count > nvmem->size) >>>> >> count = nvmem->size - pos; >>>> >> >>> >>> > >>> >Patch looks good to me. I think that it solves the issue. >>> >I don't have the board here right now, so I'll check it ASAP and give >>> >some feedback. >> >> Finally tested this. As it seemed, it solved the issue. >> Are you submitting a patch for this? > > Yes, I will send a patch to the mailing list. > Ping? It would be good to have that patch and be able to merge this lpc18xx-nvmem driver in time for the next merge window. Thanks! -- Ezequiel García, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-12-03 18:39 ` Ezequiel Garcia 0 siblings, 0 replies; 50+ messages in thread From: Ezequiel Garcia @ 2015-12-03 18:39 UTC (permalink / raw) To: linux-arm-kernel Hi Srinivas, On 16 November 2015 at 12:37, Srinivas Kandagatla <srinivas.kandagatla@linaro.org> wrote: > > > On 16/11/15 15:33, Ariel D'Alessandro wrote: >>>> >>>> >>>> >> >>-------------------------------->cut<---------------------------------- >>>> >> From 8cae10eff8ea8da9c5a8058ff75abeeddd8a8224 Mon Sep 17 00:00:00 >>>> >> 2001 >>>> >>From: Srinivas Kandagatla<srinivas.kandagatla@linaro.org> >>>> >>Date: Mon, 26 Oct 2015 13:30:24 +0000 >>>> >>Subject: [PATCH] nvmem: core: return error for non word aligned bytes >>>> >> >>>> >>nvmem providers have restrictions on register strides, so return error >>>> >>code when users attempt to read/write buffers with sizes which are not >>>> >>aligned to the word boundary. >>>> >> >>>> >>Without this patch the userspace would continue to try as it does not >>>> >>get any error from the nvmem core, resulting in a hang. >>>> >> >>>> >>Signed-off-by: Srinivas Kandagatla<srinivas.kandagatla@linaro.org> >>>> >>--- >>>> >> drivers/nvmem/core.c | 6 ++++++ >>>> >> 1 file changed, 6 insertions(+) >>>> >> >>>> >>diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c >>>> >>index 6fd4e5a..9d11d98 100644 >>>> >>--- a/drivers/nvmem/core.c >>>> >>+++ b/drivers/nvmem/core.c >>>> >>@@ -70,6 +70,9 @@ static ssize_t bin_attr_nvmem_read(struct file >>>> >> *filp, >>>> >>struct kobject *kobj, >>>> >> if (pos >= nvmem->size) >>>> >> return 0; >>>> >> >>>> >>+ if (count < nvmem->word_size) >>>> >>+ return -EINVAL; >>>> >>+ >>>> >> if (pos + count > nvmem->size) >>>> >> count = nvmem->size - pos; >>>> >> >>>> >>@@ -95,6 +98,9 @@ static ssize_t bin_attr_nvmem_write(struct file >>>> >> *filp, >>>> >>struct kobject *kobj, >>>> >> if (pos >= nvmem->size) >>>> >> return 0; >>>> >> >>>> >>+ if (count < nvmem->word_size) >>>> >>+ return -EINVAL; >>>> >>+ >>>> >> if (pos + count > nvmem->size) >>>> >> count = nvmem->size - pos; >>>> >> >>> >>> > >>> >Patch looks good to me. I think that it solves the issue. >>> >I don't have the board here right now, so I'll check it ASAP and give >>> >some feedback. >> >> Finally tested this. As it seemed, it solved the issue. >> Are you submitting a patch for this? > > Yes, I will send a patch to the mailing list. > Ping? It would be good to have that patch and be able to merge this lpc18xx-nvmem driver in time for the next merge window. Thanks! -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-24 22:04 ` Joachim Eastwood @ 2015-10-30 14:55 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 14:55 UTC (permalink / raw) To: Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Joachim, El 24/10/15 a las 19:04, Joachim Eastwood escribió: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } > > What happens here if 'val_size' is less than 4 or not dividable by 4? AFAIK, before calling to gather_write, the caller ensures that 'val_size' % map->format.val_bytes == 0 Like nvmem_device_write() do this in drivers/base/regmap/regmap.c:regmap_raw_write() Then, if val_size == 0, nothing will happen. > Same thing for 'offset'. Let me check this one. > > I tested the driver from sysfs by writing strings into the nvmem-file > with echo. Writing a string not dividable by 4 seems to hang the > system. Yeah, I saw that too. I think that's a nvmem core issue and Srinivas's patch solves this. Will confirm that as soon as I have the board back. > > >> +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, >> + void *val, size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + while (val_size) { >> + *(u32 *)val = readl(eeprom->mem_base + offset); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} > > Same comments as for lpc18xx_eeprom_gather_write(). Same answer. > > >> +static const struct of_device_id lpc18xx_eeprom_of_match[] = { >> + { .compatible = "nxp,lpc1857-eeprom" }, >> + { }, >> +}; >> +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > > nit: It's usual to place of_device_id struct just above the > platform_driver struct. I see. > > >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > > There is a BITS_PER_BYTE define in bitops.h that you might want to use here. Right. Thanks. > > >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Normally you do tear down in the reverse order of initialization. > > Consider what happens here when you power down and disable the clock > while there still are nvmem users of the eeprom. You're right! Will fix this. Thanks again. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-30 14:55 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 14:55 UTC (permalink / raw) To: linux-arm-kernel Joachim, El 24/10/15 a las 19:04, Joachim Eastwood escribi?: > Hi Ariel, > > On 19 October 2015 at 19:32, Ariel D'Alessandro > <ariel@vanguardiasur.com.ar> wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } > > What happens here if 'val_size' is less than 4 or not dividable by 4? AFAIK, before calling to gather_write, the caller ensures that 'val_size' % map->format.val_bytes == 0 Like nvmem_device_write() do this in drivers/base/regmap/regmap.c:regmap_raw_write() Then, if val_size == 0, nothing will happen. > Same thing for 'offset'. Let me check this one. > > I tested the driver from sysfs by writing strings into the nvmem-file > with echo. Writing a string not dividable by 4 seems to hang the > system. Yeah, I saw that too. I think that's a nvmem core issue and Srinivas's patch solves this. Will confirm that as soon as I have the board back. > > >> +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, >> + void *val, size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + while (val_size) { >> + *(u32 *)val = readl(eeprom->mem_base + offset); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} > > Same comments as for lpc18xx_eeprom_gather_write(). Same answer. > > >> +static const struct of_device_id lpc18xx_eeprom_of_match[] = { >> + { .compatible = "nxp,lpc1857-eeprom" }, >> + { }, >> +}; >> +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > > nit: It's usual to place of_device_id struct just above the > platform_driver struct. I see. > > >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > > There is a BITS_PER_BYTE define in bitops.h that you might want to use here. Right. Thanks. > > >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Normally you do tear down in the reverse order of initialization. > > Consider what happens here when you power down and disable the clock > while there still are nvmem users of the eeprom. You're right! Will fix this. Thanks again. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <563384CB.3070607-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-30 14:55 ` Ariel D'Alessandro @ 2015-11-16 15:24 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:24 UTC (permalink / raw) To: Joachim Eastwood Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Joachim, Sorry for the delay, I finally got the hardware again. El 30/10/15 a las 11:55, Ariel D'Alessandro escribió: > Joachim, > > El 24/10/15 a las 19:04, Joachim Eastwood escribió: >> Hi Ariel, >> >> On 19 October 2015 at 19:32, Ariel D'Alessandro >> <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>> >>> EEPROM size is 16384 bytes and it can be entirely read and >>> written/erased with 1 word (4 bytes) granularity. The last page >>> (128 bytes) contains the EEPROM initialization data and is not writable. >>> >>> Erase/program time is less than 3ms. The EEPROM device requires a >>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>> the system bus clock by the division factor, contained in the divider >>> register (minus 1 encoded). >>> >>> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >>> --- >>> drivers/nvmem/Kconfig | 9 ++ >>> drivers/nvmem/Makefile | 2 + >>> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 277 insertions(+) >>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> >>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>> + size_t reg_size, const void *val, >>> + size_t val_size) >>> +{ >>> + struct lpc18xx_eeprom_dev *eeprom = context; >>> + unsigned int offset = *(u32 *)reg; >>> + >>> + /* 3 ms of erase/program time between each writing */ >>> + while (val_size) { >>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>> + usleep_range(3000, 4000); >>> + val_size -= eeprom->val_bytes; >>> + val += eeprom->val_bytes; >>> + offset += eeprom->val_bytes; >>> + } >> >> What happens here if 'val_size' is less than 4 or not dividable by 4? > > AFAIK, before calling to gather_write, the caller ensures that > 'val_size' % map->format.val_bytes == 0 > > Like nvmem_device_write() do this in > drivers/base/regmap/regmap.c:regmap_raw_write() > > Then, if val_size == 0, nothing will happen. > >> Same thing for 'offset'. > > Let me check this one. As I said regmap will ensure that val_len % map->format.val_bytes == 0 in both read and write. However, it will only ensure that reg % map->reg_stride == 0 in read calls, not in write. A non-word aligned write to the EEPROM will fail, so I'm adding a check for this. Thanks for pointing this out. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-16 15:24 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:24 UTC (permalink / raw) To: linux-arm-kernel Joachim, Sorry for the delay, I finally got the hardware again. El 30/10/15 a las 11:55, Ariel D'Alessandro escribi?: > Joachim, > > El 24/10/15 a las 19:04, Joachim Eastwood escribi?: >> Hi Ariel, >> >> On 19 October 2015 at 19:32, Ariel D'Alessandro >> <ariel@vanguardiasur.com.ar> wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>> >>> EEPROM size is 16384 bytes and it can be entirely read and >>> written/erased with 1 word (4 bytes) granularity. The last page >>> (128 bytes) contains the EEPROM initialization data and is not writable. >>> >>> Erase/program time is less than 3ms. The EEPROM device requires a >>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>> the system bus clock by the division factor, contained in the divider >>> register (minus 1 encoded). >>> >>> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >>> --- >>> drivers/nvmem/Kconfig | 9 ++ >>> drivers/nvmem/Makefile | 2 + >>> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 277 insertions(+) >>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> >>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>> + size_t reg_size, const void *val, >>> + size_t val_size) >>> +{ >>> + struct lpc18xx_eeprom_dev *eeprom = context; >>> + unsigned int offset = *(u32 *)reg; >>> + >>> + /* 3 ms of erase/program time between each writing */ >>> + while (val_size) { >>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>> + usleep_range(3000, 4000); >>> + val_size -= eeprom->val_bytes; >>> + val += eeprom->val_bytes; >>> + offset += eeprom->val_bytes; >>> + } >> >> What happens here if 'val_size' is less than 4 or not dividable by 4? > > AFAIK, before calling to gather_write, the caller ensures that > 'val_size' % map->format.val_bytes == 0 > > Like nvmem_device_write() do this in > drivers/base/regmap/regmap.c:regmap_raw_write() > > Then, if val_size == 0, nothing will happen. > >> Same thing for 'offset'. > > Let me check this one. As I said regmap will ensure that val_len % map->format.val_bytes == 0 in both read and write. However, it will only ensure that reg % map->reg_stride == 0 in read calls, not in write. A non-word aligned write to the EEPROM will fail, so I'm adding a check for this. Thanks for pointing this out. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-26 14:23 ` Srinivas Kandagatla -1 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-10-26 14:23 UTC (permalink / raw) To: Ariel D'Alessandro, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A On 19/10/15 18:32, Ariel D'Alessandro wrote: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP s/commit/patch > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > > diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig > index bc4ea58..6ff1b50 100644 > --- a/drivers/nvmem/Kconfig > +++ b/drivers/nvmem/Kconfig > @@ -25,6 +25,15 @@ config NVMEM_IMX_OCOTP > This driver can also be built as a module. If so, the module > will be called nvmem-imx-ocotp. > > +config NVMEM_LPC18XX_EEPROM > + tristate "NXP LPC18XX EEPROM Memory Support" > + depends on ARCH_LPC18XX || COMPILE_TEST > + help > + Say Y here to include support for NXP LPC18xx EEPROM memory found in > + NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > + To compile this driver as a module, choose M here: the module > + will be called nvmem_lpc18xx_eeprom. > + > config NVMEM_MXS_OCOTP > tristate "Freescale MXS On-Chip OTP Memory Support" > depends on ARCH_MXS || COMPILE_TEST > diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile > index 95dde3f..c14a556 100644 > --- a/drivers/nvmem/Makefile > +++ b/drivers/nvmem/Makefile > @@ -8,6 +8,8 @@ nvmem_core-y := core.o > # Devices > obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o > nvmem-imx-ocotp-y := imx-ocotp.o > +obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o > +nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o > obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o > nvmem-mxs-ocotp-y := mxs-ocotp.o > obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o > diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c > new file mode 100644 > index 0000000..ccdda66 > --- /dev/null > +++ b/drivers/nvmem/lpc18xx_eeprom.c > @@ -0,0 +1,266 @@ > +/* > + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver > + * > + * Copyright (c) 2015 Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgC/G2K4zDHf@public.gmane.org> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + */ > + > +#include <linux/clk.h> > +#include <linux/device.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/nvmem-provider.h> > +#include <linux/of_device.h> Why do you need above? Also you should probably include #include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/reset.h> > + > +/* Registers */ > +#define LPC18XX_EEPROM_AUTOPROG 0x00c > +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 > + > +#define LPC18XX_EEPROM_CLKDIV 0x014 > + > +#define LPC18XX_EEPROM_PWRDWN 0x018 > +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 > +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 > + > +/* Fixed page size (bytes) */ > +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 > + > +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */ > +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 > + > +struct lpc18xx_eeprom_dev { > + struct clk *clk; > + void __iomem *reg_base; > + void __iomem *mem_base; > + struct nvmem_device *nvmem; > + unsigned reg_bytes; > + unsigned val_bytes; > +}; > + > +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom, > + u32 reg, u32 val) > +{ > + writel(val, eeprom->reg_base + reg); > +} I don't have a strong feeling but, I see no point to have a wrapper for writel which is only used in probe function. > + > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} > + > +static int lpc18xx_eeprom_write(void *context, const void *data, size_t count) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = eeprom->reg_bytes; > + > + if (count <= offset) > + return -EINVAL; > + > + unnecessary new line. > + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, > + data + offset, count - offset); > +} > + > +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, > + void *val, size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + while (val_size) { > + *(u32 *)val = readl(eeprom->mem_base + offset); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} > + > +static struct regmap_bus lpc18xx_eeprom_bus = { > + .write = lpc18xx_eeprom_write, > + .gather_write = lpc18xx_eeprom_gather_write, > + .read = lpc18xx_eeprom_read, > + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, > + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, > +}; > + > +static struct regmap_config lpc18xx_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > +}; > + > +static bool lpc18xx_eeprom_writeable_reg(struct device *dev, unsigned int reg) > +{ > + /* > + * The last page contains the EEPROM initialization data and is not > + * writable. > + */ > + return reg <= lpc18xx_regmap_config.max_register - > + LPC18XX_EEPROM_PAGE_SIZE; > +} > + > +static bool lpc18xx_eeprom_readable_reg(struct device *dev, unsigned int reg) > +{ > + return reg <= lpc18xx_regmap_config.max_register; > +} > + > +static struct nvmem_config lpc18xx_nvmem_config = { > + .name = "lpc18xx-eeprom", > + .owner = THIS_MODULE, > +}; > + > +static const struct of_device_id lpc18xx_eeprom_of_match[] = { > + { .compatible = "nxp,lpc1857-eeprom" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > + > +static int lpc18xx_eeprom_probe(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom; > + struct device *dev = &pdev->dev; > + struct reset_control *rst; > + unsigned long clk_rate; > + struct regmap *regmap; > + struct resource *res; > + int ret; > + > + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); > + if (!eeprom) > + return -ENOMEM; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); > + eeprom->reg_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(eeprom->reg_base)) > + return PTR_ERR(eeprom->reg_base); > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); > + eeprom->mem_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(eeprom->mem_base)) > + return PTR_ERR(eeprom->mem_base); > + > + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); > + if (IS_ERR(eeprom->clk)) { > + dev_err(&pdev->dev, "failed to get eeprom clock\n"); > + return PTR_ERR(eeprom->clk); > + } > + > + ret = clk_prepare_enable(eeprom->clk); > + if (ret < 0) { > + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); > + return ret; > + } > + > + rst = devm_reset_control_get(dev, NULL); > + if (IS_ERR(rst)) { > + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); > + ret = PTR_ERR(rst); > + goto err_clk; > + } > + > + ret = reset_control_deassert(rst); > + if (ret < 0) { > + dev_err(dev, "failed to deassert reset: %d\n", ret); > + goto err_clk; > + } > + > + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; > + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > + > + /* > + * Clock rate is generated by dividing the system bus clock by the > + * division factor, contained in the divider register (minus 1 encoded). > + */ > + clk_rate = clk_get_rate(eeprom->clk); > + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); > + > + /* > + * Writing a single word to the page will start the erase/program cycle > + * automatically > + */ > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, > + LPC18XX_EEPROM_AUTOPROG_WORD); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_NO); Any reason not power up/dowm dynamically in lpc18xx_eeprom_write()/lpc18xx_eeprom_read(). This can potentially save some power. > + > + lpc18xx_regmap_config.max_register = resource_size(res) - 1; > + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; > + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; > + > + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, > + &lpc18xx_regmap_config); > + if (IS_ERR(regmap)) { > + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); > + ret = PTR_ERR(regmap); > + goto err_clk; > + } > + > + lpc18xx_nvmem_config.dev = dev; > + > + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); > + if (IS_ERR(eeprom->nvmem)) { > + ret = PTR_ERR(eeprom->nvmem); > + goto err_clk; > + } > + > + platform_set_drvdata(pdev, eeprom); > + > + return 0; > + > +err_clk: Should this error path also include power down/reset assert the eeprom? > + clk_disable_unprepare(eeprom->clk); > + > + return ret; > +} > + > +static int lpc18xx_eeprom_remove(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_YES); > + > + clk_disable_unprepare(eeprom->clk); > + > + return nvmem_unregister(eeprom->nvmem); Same comment as Joachim, should the reset be asserted too? > +} > + > +static struct platform_driver lpc18xx_eeprom_driver = { > + .probe = lpc18xx_eeprom_probe, > + .remove = lpc18xx_eeprom_remove, > + .driver = { > + .name = "lpc18xx-eeprom", > + .of_match_table = lpc18xx_eeprom_of_match, > + }, > +}; > + > +module_platform_driver(lpc18xx_eeprom_driver); > + > +MODULE_AUTHOR("Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>"); > +MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver"); > +MODULE_LICENSE("GPL v2"); > -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-26 14:23 ` Srinivas Kandagatla 0 siblings, 0 replies; 50+ messages in thread From: Srinivas Kandagatla @ 2015-10-26 14:23 UTC (permalink / raw) To: linux-arm-kernel On 19/10/15 18:32, Ariel D'Alessandro wrote: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP s/commit/patch > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > > diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig > index bc4ea58..6ff1b50 100644 > --- a/drivers/nvmem/Kconfig > +++ b/drivers/nvmem/Kconfig > @@ -25,6 +25,15 @@ config NVMEM_IMX_OCOTP > This driver can also be built as a module. If so, the module > will be called nvmem-imx-ocotp. > > +config NVMEM_LPC18XX_EEPROM > + tristate "NXP LPC18XX EEPROM Memory Support" > + depends on ARCH_LPC18XX || COMPILE_TEST > + help > + Say Y here to include support for NXP LPC18xx EEPROM memory found in > + NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > + To compile this driver as a module, choose M here: the module > + will be called nvmem_lpc18xx_eeprom. > + > config NVMEM_MXS_OCOTP > tristate "Freescale MXS On-Chip OTP Memory Support" > depends on ARCH_MXS || COMPILE_TEST > diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile > index 95dde3f..c14a556 100644 > --- a/drivers/nvmem/Makefile > +++ b/drivers/nvmem/Makefile > @@ -8,6 +8,8 @@ nvmem_core-y := core.o > # Devices > obj-$(CONFIG_NVMEM_IMX_OCOTP) += nvmem-imx-ocotp.o > nvmem-imx-ocotp-y := imx-ocotp.o > +obj-$(CONFIG_NVMEM_LPC18XX_EEPROM) += nvmem_lpc18xx_eeprom.o > +nvmem_lpc18xx_eeprom-y := lpc18xx_eeprom.o > obj-$(CONFIG_NVMEM_MXS_OCOTP) += nvmem-mxs-ocotp.o > nvmem-mxs-ocotp-y := mxs-ocotp.o > obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o > diff --git a/drivers/nvmem/lpc18xx_eeprom.c b/drivers/nvmem/lpc18xx_eeprom.c > new file mode 100644 > index 0000000..ccdda66 > --- /dev/null > +++ b/drivers/nvmem/lpc18xx_eeprom.c > @@ -0,0 +1,266 @@ > +/* > + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver > + * > + * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published by > + * the Free Software Foundation. > + */ > + > +#include <linux/clk.h> > +#include <linux/device.h> > +#include <linux/delay.h> > +#include <linux/err.h> > +#include <linux/io.h> > +#include <linux/module.h> > +#include <linux/nvmem-provider.h> > +#include <linux/of_device.h> Why do you need above? Also you should probably include #include <linux/platform_device.h> > +#include <linux/regmap.h> > +#include <linux/reset.h> > + > +/* Registers */ > +#define LPC18XX_EEPROM_AUTOPROG 0x00c > +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 > + > +#define LPC18XX_EEPROM_CLKDIV 0x014 > + > +#define LPC18XX_EEPROM_PWRDWN 0x018 > +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 > +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 > + > +/* Fixed page size (bytes) */ > +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 > + > +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 kHz) */ > +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 > + > +struct lpc18xx_eeprom_dev { > + struct clk *clk; > + void __iomem *reg_base; > + void __iomem *mem_base; > + struct nvmem_device *nvmem; > + unsigned reg_bytes; > + unsigned val_bytes; > +}; > + > +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev *eeprom, > + u32 reg, u32 val) > +{ > + writel(val, eeprom->reg_base + reg); > +} I don't have a strong feeling but, I see no point to have a wrapper for writel which is only used in probe function. > + > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} > + > +static int lpc18xx_eeprom_write(void *context, const void *data, size_t count) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = eeprom->reg_bytes; > + > + if (count <= offset) > + return -EINVAL; > + > + unnecessary new line. > + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, > + data + offset, count - offset); > +} > + > +static int lpc18xx_eeprom_read(void *context, const void *reg, size_t reg_size, > + void *val, size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + while (val_size) { > + *(u32 *)val = readl(eeprom->mem_base + offset); > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} > + > +static struct regmap_bus lpc18xx_eeprom_bus = { > + .write = lpc18xx_eeprom_write, > + .gather_write = lpc18xx_eeprom_gather_write, > + .read = lpc18xx_eeprom_read, > + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE, > + .val_format_endian_default = REGMAP_ENDIAN_NATIVE, > +}; > + > +static struct regmap_config lpc18xx_regmap_config = { > + .reg_bits = 32, > + .reg_stride = 4, > + .val_bits = 32, > +}; > + > +static bool lpc18xx_eeprom_writeable_reg(struct device *dev, unsigned int reg) > +{ > + /* > + * The last page contains the EEPROM initialization data and is not > + * writable. > + */ > + return reg <= lpc18xx_regmap_config.max_register - > + LPC18XX_EEPROM_PAGE_SIZE; > +} > + > +static bool lpc18xx_eeprom_readable_reg(struct device *dev, unsigned int reg) > +{ > + return reg <= lpc18xx_regmap_config.max_register; > +} > + > +static struct nvmem_config lpc18xx_nvmem_config = { > + .name = "lpc18xx-eeprom", > + .owner = THIS_MODULE, > +}; > + > +static const struct of_device_id lpc18xx_eeprom_of_match[] = { > + { .compatible = "nxp,lpc1857-eeprom" }, > + { }, > +}; > +MODULE_DEVICE_TABLE(of, lpc18xx_eeprom_of_match); > + > +static int lpc18xx_eeprom_probe(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom; > + struct device *dev = &pdev->dev; > + struct reset_control *rst; > + unsigned long clk_rate; > + struct regmap *regmap; > + struct resource *res; > + int ret; > + > + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); > + if (!eeprom) > + return -ENOMEM; > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); > + eeprom->reg_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(eeprom->reg_base)) > + return PTR_ERR(eeprom->reg_base); > + > + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); > + eeprom->mem_base = devm_ioremap_resource(dev, res); > + if (IS_ERR(eeprom->mem_base)) > + return PTR_ERR(eeprom->mem_base); > + > + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); > + if (IS_ERR(eeprom->clk)) { > + dev_err(&pdev->dev, "failed to get eeprom clock\n"); > + return PTR_ERR(eeprom->clk); > + } > + > + ret = clk_prepare_enable(eeprom->clk); > + if (ret < 0) { > + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); > + return ret; > + } > + > + rst = devm_reset_control_get(dev, NULL); > + if (IS_ERR(rst)) { > + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); > + ret = PTR_ERR(rst); > + goto err_clk; > + } > + > + ret = reset_control_deassert(rst); > + if (ret < 0) { > + dev_err(dev, "failed to deassert reset: %d\n", ret); > + goto err_clk; > + } > + > + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; > + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; > + > + /* > + * Clock rate is generated by dividing the system bus clock by the > + * division factor, contained in the divider register (minus 1 encoded). > + */ > + clk_rate = clk_get_rate(eeprom->clk); > + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); > + > + /* > + * Writing a single word to the page will start the erase/program cycle > + * automatically > + */ > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, > + LPC18XX_EEPROM_AUTOPROG_WORD); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_NO); Any reason not power up/dowm dynamically in lpc18xx_eeprom_write()/lpc18xx_eeprom_read(). This can potentially save some power. > + > + lpc18xx_regmap_config.max_register = resource_size(res) - 1; > + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; > + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; > + > + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, > + &lpc18xx_regmap_config); > + if (IS_ERR(regmap)) { > + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); > + ret = PTR_ERR(regmap); > + goto err_clk; > + } > + > + lpc18xx_nvmem_config.dev = dev; > + > + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); > + if (IS_ERR(eeprom->nvmem)) { > + ret = PTR_ERR(eeprom->nvmem); > + goto err_clk; > + } > + > + platform_set_drvdata(pdev, eeprom); > + > + return 0; > + > +err_clk: Should this error path also include power down/reset assert the eeprom? > + clk_disable_unprepare(eeprom->clk); > + > + return ret; > +} > + > +static int lpc18xx_eeprom_remove(struct platform_device *pdev) > +{ > + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); > + > + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, > + LPC18XX_EEPROM_PWRDWN_YES); > + > + clk_disable_unprepare(eeprom->clk); > + > + return nvmem_unregister(eeprom->nvmem); Same comment as Joachim, should the reset be asserted too? > +} > + > +static struct platform_driver lpc18xx_eeprom_driver = { > + .probe = lpc18xx_eeprom_probe, > + .remove = lpc18xx_eeprom_remove, > + .driver = { > + .name = "lpc18xx-eeprom", > + .of_match_table = lpc18xx_eeprom_of_match, > + }, > +}; > + > +module_platform_driver(lpc18xx_eeprom_driver); > + > +MODULE_AUTHOR("Ariel D'Alessandro <ariel@vanguardiasur.com.ar>"); > +MODULE_DESCRIPTION("NXP LPC18xx EEPROM memory Driver"); > +MODULE_LICENSE("GPL v2"); > ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <562E377A.3040604-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-26 14:23 ` Srinivas Kandagatla @ 2015-10-30 15:42 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 15:42 UTC (permalink / raw) To: Srinivas Kandagatla, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A Srinivas, El 26/10/15 a las 11:23, Srinivas Kandagatla escribió: > > > On 19/10/15 18:32, Ariel D'Alessandro wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP > s/commit/patch OK. > >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 >> +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> [snip] >> diff --git a/drivers/nvmem/lpc18xx_eeprom.c >> b/drivers/nvmem/lpc18xx_eeprom.c >> new file mode 100644 >> index 0000000..ccdda66 >> --- /dev/null >> +++ b/drivers/nvmem/lpc18xx_eeprom.c >> @@ -0,0 +1,266 @@ >> +/* >> + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver >> + * >> + * Copyright (c) 2015 Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgC/G2K4zDHf@public.gmane.org> >> + * >> + * This program is free software; you can redistribute it and/or >> modify it >> + * under the terms of the GNU General Public License version 2 as >> published by >> + * the Free Software Foundation. >> + */ >> + >> +#include <linux/clk.h> >> +#include <linux/device.h> >> +#include <linux/delay.h> >> +#include <linux/err.h> >> +#include <linux/io.h> >> +#include <linux/module.h> >> +#include <linux/nvmem-provider.h> >> +#include <linux/of_device.h> > Why do you need above? > > Also you should probably include > > #include <linux/platform_device.h> You're right. No need for of_device.h, only platform_device.h. > > >> +#include <linux/regmap.h> >> +#include <linux/reset.h> >> + >> +/* Registers */ >> +#define LPC18XX_EEPROM_AUTOPROG 0x00c >> +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 >> + >> +#define LPC18XX_EEPROM_CLKDIV 0x014 >> + >> +#define LPC18XX_EEPROM_PWRDWN 0x018 >> +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 >> +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 >> + >> +/* Fixed page size (bytes) */ >> +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 >> + >> +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 >> kHz) */ >> +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 >> + >> +struct lpc18xx_eeprom_dev { >> + struct clk *clk; >> + void __iomem *reg_base; >> + void __iomem *mem_base; >> + struct nvmem_device *nvmem; >> + unsigned reg_bytes; >> + unsigned val_bytes; >> +}; >> + >> +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev >> *eeprom, >> + u32 reg, u32 val) >> +{ >> + writel(val, eeprom->reg_base + reg); >> +} > I don't have a strong feeling but, I see no point to have a wrapper for > writel which is only used in probe function. Well, to be correct it's also used in remove function. And I might call it in read()/write() functions to allow dynamic power on/off. I'd prefer keeping the wrapper. > >> + >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} >> + >> +static int lpc18xx_eeprom_write(void *context, const void *data, >> size_t count) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = eeprom->reg_bytes; >> + >> + if (count <= offset) >> + return -EINVAL; >> + >> + > unnecessary new line. ACK. > >> + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, >> + data + offset, count - offset); >> +} >> + [snip] >> + >> +static int lpc18xx_eeprom_probe(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom; >> + struct device *dev = &pdev->dev; >> + struct reset_control *rst; >> + unsigned long clk_rate; >> + struct regmap *regmap; >> + struct resource *res; >> + int ret; >> + >> + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); >> + if (!eeprom) >> + return -ENOMEM; >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); >> + eeprom->reg_base = devm_ioremap_resource(dev, res); >> + if (IS_ERR(eeprom->reg_base)) >> + return PTR_ERR(eeprom->reg_base); >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); >> + eeprom->mem_base = devm_ioremap_resource(dev, res); >> + if (IS_ERR(eeprom->mem_base)) >> + return PTR_ERR(eeprom->mem_base); >> + >> + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); >> + if (IS_ERR(eeprom->clk)) { >> + dev_err(&pdev->dev, "failed to get eeprom clock\n"); >> + return PTR_ERR(eeprom->clk); >> + } >> + >> + ret = clk_prepare_enable(eeprom->clk); >> + if (ret < 0) { >> + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); >> + return ret; >> + } >> + >> + rst = devm_reset_control_get(dev, NULL); >> + if (IS_ERR(rst)) { >> + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); >> + ret = PTR_ERR(rst); >> + goto err_clk; >> + } >> + >> + ret = reset_control_deassert(rst); >> + if (ret < 0) { >> + dev_err(dev, "failed to deassert reset: %d\n", ret); >> + goto err_clk; >> + } >> + >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; >> + >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 >> encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program >> cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); > > Any reason not power up/dowm dynamically in > lpc18xx_eeprom_write()/lpc18xx_eeprom_read(). > > This can potentially save some power. That sounds good. I'll add this feature and check that it works properly. > >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: > > Should this error path also include power down/reset assert the eeprom? Yes, I'll add another cleanup routine. > >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Same comment as Joachim, should the reset be asserted too? No. That would cause a reset, disabling EEPROM power down mode. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-30 15:42 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-30 15:42 UTC (permalink / raw) To: linux-arm-kernel Srinivas, El 26/10/15 a las 11:23, Srinivas Kandagatla escribi?: > > > On 19/10/15 18:32, Ariel D'Alessandro wrote: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP > s/commit/patch OK. > >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 >> +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> [snip] >> diff --git a/drivers/nvmem/lpc18xx_eeprom.c >> b/drivers/nvmem/lpc18xx_eeprom.c >> new file mode 100644 >> index 0000000..ccdda66 >> --- /dev/null >> +++ b/drivers/nvmem/lpc18xx_eeprom.c >> @@ -0,0 +1,266 @@ >> +/* >> + * NXP LPC18xx/LPC43xx EEPROM memory NVMEM driver >> + * >> + * Copyright (c) 2015 Ariel D'Alessandro <ariel@vanguardiasur.com> >> + * >> + * This program is free software; you can redistribute it and/or >> modify it >> + * under the terms of the GNU General Public License version 2 as >> published by >> + * the Free Software Foundation. >> + */ >> + >> +#include <linux/clk.h> >> +#include <linux/device.h> >> +#include <linux/delay.h> >> +#include <linux/err.h> >> +#include <linux/io.h> >> +#include <linux/module.h> >> +#include <linux/nvmem-provider.h> >> +#include <linux/of_device.h> > Why do you need above? > > Also you should probably include > > #include <linux/platform_device.h> You're right. No need for of_device.h, only platform_device.h. > > >> +#include <linux/regmap.h> >> +#include <linux/reset.h> >> + >> +/* Registers */ >> +#define LPC18XX_EEPROM_AUTOPROG 0x00c >> +#define LPC18XX_EEPROM_AUTOPROG_WORD 0x1 >> + >> +#define LPC18XX_EEPROM_CLKDIV 0x014 >> + >> +#define LPC18XX_EEPROM_PWRDWN 0x018 >> +#define LPC18XX_EEPROM_PWRDWN_NO 0x0 >> +#define LPC18XX_EEPROM_PWRDWN_YES 0x1 >> + >> +/* Fixed page size (bytes) */ >> +#define LPC18XX_EEPROM_PAGE_SIZE 0x80 >> + >> +/* EEPROM device requires a ~1500 kHz clock (min 800 kHz, max 1600 >> kHz) */ >> +#define LPC18XX_EEPROM_CLOCK_HZ 1500000 >> + >> +struct lpc18xx_eeprom_dev { >> + struct clk *clk; >> + void __iomem *reg_base; >> + void __iomem *mem_base; >> + struct nvmem_device *nvmem; >> + unsigned reg_bytes; >> + unsigned val_bytes; >> +}; >> + >> +static inline void lpc18xx_eeprom_writel(struct lpc18xx_eeprom_dev >> *eeprom, >> + u32 reg, u32 val) >> +{ >> + writel(val, eeprom->reg_base + reg); >> +} > I don't have a strong feeling but, I see no point to have a wrapper for > writel which is only used in probe function. Well, to be correct it's also used in remove function. And I might call it in read()/write() functions to allow dynamic power on/off. I'd prefer keeping the wrapper. > >> + >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); >> + val_size -= eeprom->val_bytes; >> + val += eeprom->val_bytes; >> + offset += eeprom->val_bytes; >> + } >> + >> + return 0; >> +} >> + >> +static int lpc18xx_eeprom_write(void *context, const void *data, >> size_t count) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = eeprom->reg_bytes; >> + >> + if (count <= offset) >> + return -EINVAL; >> + >> + > unnecessary new line. ACK. > >> + return lpc18xx_eeprom_gather_write(context, data, eeprom->reg_bytes, >> + data + offset, count - offset); >> +} >> + [snip] >> + >> +static int lpc18xx_eeprom_probe(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom; >> + struct device *dev = &pdev->dev; >> + struct reset_control *rst; >> + unsigned long clk_rate; >> + struct regmap *regmap; >> + struct resource *res; >> + int ret; >> + >> + eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); >> + if (!eeprom) >> + return -ENOMEM; >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "reg"); >> + eeprom->reg_base = devm_ioremap_resource(dev, res); >> + if (IS_ERR(eeprom->reg_base)) >> + return PTR_ERR(eeprom->reg_base); >> + >> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mem"); >> + eeprom->mem_base = devm_ioremap_resource(dev, res); >> + if (IS_ERR(eeprom->mem_base)) >> + return PTR_ERR(eeprom->mem_base); >> + >> + eeprom->clk = devm_clk_get(&pdev->dev, "eeprom"); >> + if (IS_ERR(eeprom->clk)) { >> + dev_err(&pdev->dev, "failed to get eeprom clock\n"); >> + return PTR_ERR(eeprom->clk); >> + } >> + >> + ret = clk_prepare_enable(eeprom->clk); >> + if (ret < 0) { >> + dev_err(dev, "failed to prepare/enable eeprom clk: %d\n", ret); >> + return ret; >> + } >> + >> + rst = devm_reset_control_get(dev, NULL); >> + if (IS_ERR(rst)) { >> + dev_err(dev, "failed to get reset: %ld\n", PTR_ERR(rst)); >> + ret = PTR_ERR(rst); >> + goto err_clk; >> + } >> + >> + ret = reset_control_deassert(rst); >> + if (ret < 0) { >> + dev_err(dev, "failed to deassert reset: %d\n", ret); >> + goto err_clk; >> + } >> + >> + eeprom->val_bytes = lpc18xx_regmap_config.val_bits / 8; >> + eeprom->reg_bytes = lpc18xx_regmap_config.reg_bits / 8; >> + >> + /* >> + * Clock rate is generated by dividing the system bus clock by the >> + * division factor, contained in the divider register (minus 1 >> encoded). >> + */ >> + clk_rate = clk_get_rate(eeprom->clk); >> + clk_rate = DIV_ROUND_UP(clk_rate, LPC18XX_EEPROM_CLOCK_HZ) - 1; >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_CLKDIV, clk_rate); >> + >> + /* >> + * Writing a single word to the page will start the erase/program >> cycle >> + * automatically >> + */ >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_AUTOPROG, >> + LPC18XX_EEPROM_AUTOPROG_WORD); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_NO); > > Any reason not power up/dowm dynamically in > lpc18xx_eeprom_write()/lpc18xx_eeprom_read(). > > This can potentially save some power. That sounds good. I'll add this feature and check that it works properly. > >> + >> + lpc18xx_regmap_config.max_register = resource_size(res) - 1; >> + lpc18xx_regmap_config.writeable_reg = lpc18xx_eeprom_writeable_reg; >> + lpc18xx_regmap_config.readable_reg = lpc18xx_eeprom_readable_reg; >> + >> + regmap = devm_regmap_init(dev, &lpc18xx_eeprom_bus, eeprom, >> + &lpc18xx_regmap_config); >> + if (IS_ERR(regmap)) { >> + dev_err(dev, "regmap init failed: %ld\n", PTR_ERR(regmap)); >> + ret = PTR_ERR(regmap); >> + goto err_clk; >> + } >> + >> + lpc18xx_nvmem_config.dev = dev; >> + >> + eeprom->nvmem = nvmem_register(&lpc18xx_nvmem_config); >> + if (IS_ERR(eeprom->nvmem)) { >> + ret = PTR_ERR(eeprom->nvmem); >> + goto err_clk; >> + } >> + >> + platform_set_drvdata(pdev, eeprom); >> + >> + return 0; >> + >> +err_clk: > > Should this error path also include power down/reset assert the eeprom? Yes, I'll add another cleanup routine. > >> + clk_disable_unprepare(eeprom->clk); >> + >> + return ret; >> +} >> + >> +static int lpc18xx_eeprom_remove(struct platform_device *pdev) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = platform_get_drvdata(pdev); >> + >> + lpc18xx_eeprom_writel(eeprom, LPC18XX_EEPROM_PWRDWN, >> + LPC18XX_EEPROM_PWRDWN_YES); >> + >> + clk_disable_unprepare(eeprom->clk); >> + >> + return nvmem_unregister(eeprom->nvmem); > > Same comment as Joachim, should the reset be asserted too? No. That would cause a reset, disabling EEPROM power down mode. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <56338FF4.8050102-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-30 15:42 ` Ariel D'Alessandro @ 2015-10-30 16:00 ` Ezequiel Garcia -1 siblings, 0 replies; 50+ messages in thread From: Ezequiel Garcia @ 2015-10-30 16:00 UTC (permalink / raw) To: Ariel D'Alessandro, Srinivas Kandagatla Cc: linux-arm-kernel, devicetree-u79uwXL29TY76Z2rM5mHXA, Maxime Ripard, Joachim Eastwood, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Srinivas, Ariel, On 30 October 2015 at 12:42, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > El 26/10/15 a las 11:23, Srinivas Kandagatla escribió: >> >> >> On 19/10/15 18:32, Ariel D'Alessandro wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> s/commit/patch > > OK. > What's wrong with using "commit" ? If the patch gets accepted and is merged, it will become a commit. Hence, it's customary to use "commit" in the commit log. I really don't think it's wrong to use either patch or commit. -- Ezequiel García, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-10-30 16:00 ` Ezequiel Garcia 0 siblings, 0 replies; 50+ messages in thread From: Ezequiel Garcia @ 2015-10-30 16:00 UTC (permalink / raw) To: linux-arm-kernel Hi Srinivas, Ariel, On 30 October 2015 at 12:42, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > El 26/10/15 a las 11:23, Srinivas Kandagatla escribi?: >> >> >> On 19/10/15 18:32, Ariel D'Alessandro wrote: >>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> s/commit/patch > > OK. > What's wrong with using "commit" ? If the patch gets accepted and is merged, it will become a commit. Hence, it's customary to use "commit" in the commit log. I really don't think it's wrong to use either patch or commit. -- Ezequiel Garc?a, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-11-03 8:20 ` Stefan Wahren -1 siblings, 0 replies; 50+ messages in thread From: Stefan Wahren @ 2015-11-03 8:20 UTC (permalink / raw) To: Ariel D'Alessandro Cc: mark.rutland, devicetree, pawel.moll, ijc+devicetree, manabian, robh+dt, srinivas.kandagatla, ezequiel, galak, maxime.ripard, linux-arm-kernel Hi Ariel, Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > [...] > + > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); i think it would be good to verify that the EEPROM write operation has really finished. Best regards Stefan > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-03 8:20 ` Stefan Wahren 0 siblings, 0 replies; 50+ messages in thread From: Stefan Wahren @ 2015-11-03 8:20 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: > This commit adds support for NXP LPC18xx EEPROM memory found in NXP > LPC185x/3x and LPC435x/3x/2x/1x devices. > > EEPROM size is 16384 bytes and it can be entirely read and > written/erased with 1 word (4 bytes) granularity. The last page > (128 bytes) contains the EEPROM initialization data and is not writable. > > Erase/program time is less than 3ms. The EEPROM device requires a > ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > the system bus clock by the division factor, contained in the divider > register (minus 1 encoded). > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > --- > drivers/nvmem/Kconfig | 9 ++ > drivers/nvmem/Makefile | 2 + > drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 277 insertions(+) > create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > [...] > + > +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > + size_t reg_size, const void *val, > + size_t val_size) > +{ > + struct lpc18xx_eeprom_dev *eeprom = context; > + unsigned int offset = *(u32 *)reg; > + > + /* 3 ms of erase/program time between each writing */ > + while (val_size) { > + writel(*(u32 *)val, eeprom->mem_base + offset); > + usleep_range(3000, 4000); i think it would be good to verify that the EEPROM write operation has really finished. Best regards Stefan > + val_size -= eeprom->val_bytes; > + val += eeprom->val_bytes; > + offset += eeprom->val_bytes; > + } > + > + return 0; > +} ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <56386E30.4060905-eS4NqCHxEME@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-11-03 8:20 ` Stefan Wahren @ 2015-11-16 15:29 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:29 UTC (permalink / raw) To: Stefan Wahren Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, manabian-Re5JQEeQqe8AvxtiuMwx3w, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, galak-sgV2jX0FEOL9JmXXK+q4OQ, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8 Hi Stefan, Sorry for the delay. El 03/11/15 a las 05:20, Stefan Wahren escribió: > Hi Ariel, > > Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> [...] >> + >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); > > i think it would be good to verify that the EEPROM write operation has > really finished. I'm not sure what are you proposing. Why could the write operation not finish? -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-16 15:29 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-16 15:29 UTC (permalink / raw) To: linux-arm-kernel Hi Stefan, Sorry for the delay. El 03/11/15 a las 05:20, Stefan Wahren escribi?: > Hi Ariel, > > Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >> LPC185x/3x and LPC435x/3x/2x/1x devices. >> >> EEPROM size is 16384 bytes and it can be entirely read and >> written/erased with 1 word (4 bytes) granularity. The last page >> (128 bytes) contains the EEPROM initialization data and is not writable. >> >> Erase/program time is less than 3ms. The EEPROM device requires a >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >> the system bus clock by the division factor, contained in the divider >> register (minus 1 encoded). >> >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >> --- >> drivers/nvmem/Kconfig | 9 ++ >> drivers/nvmem/Makefile | 2 + >> drivers/nvmem/lpc18xx_eeprom.c | 266 +++++++++++++++++++++++++++++++++++++++++ >> 3 files changed, 277 insertions(+) >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >> [...] >> + >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >> + size_t reg_size, const void *val, >> + size_t val_size) >> +{ >> + struct lpc18xx_eeprom_dev *eeprom = context; >> + unsigned int offset = *(u32 *)reg; >> + >> + /* 3 ms of erase/program time between each writing */ >> + while (val_size) { >> + writel(*(u32 *)val, eeprom->mem_base + offset); >> + usleep_range(3000, 4000); > > i think it would be good to verify that the EEPROM write operation has > really finished. I'm not sure what are you proposing. Why could the write operation not finish? -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <5649F64B.5050407-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-11-16 15:29 ` Ariel D'Alessandro @ 2015-11-17 10:01 ` Stefan Wahren -1 siblings, 0 replies; 50+ messages in thread From: Stefan Wahren @ 2015-11-17 10:01 UTC (permalink / raw) To: Ariel D'Alessandro Cc: manabian-Re5JQEeQqe8AvxtiuMwx3w, srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, pawel.moll-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, galak-sgV2jX0FEOL9JmXXK+q4OQ, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, mark.rutland-5wv7dgnIgG8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, devicetree-u79uwXL29TY76Z2rM5mHXA Hi Ariel, > Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> hat am 16. November 2015 um > 16:29 geschrieben: > > > Hi Stefan, > > Sorry for the delay. > > El 03/11/15 a las 05:20, Stefan Wahren escribió: > > Hi Ariel, > > > > Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: > >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP > >> LPC185x/3x and LPC435x/3x/2x/1x devices. > >> > >> EEPROM size is 16384 bytes and it can be entirely read and > >> written/erased with 1 word (4 bytes) granularity. The last page > >> (128 bytes) contains the EEPROM initialization data and is not writable. > >> > >> Erase/program time is less than 3ms. The EEPROM device requires a > >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > >> the system bus clock by the division factor, contained in the divider > >> register (minus 1 encoded). > >> > >> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> > >> --- > >> drivers/nvmem/Kconfig | 9 ++ > >> drivers/nvmem/Makefile | 2 + > >> drivers/nvmem/lpc18xx_eeprom.c | 266 > >> +++++++++++++++++++++++++++++++++++++++++ > >> 3 files changed, 277 insertions(+) > >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> [...] > >> + > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > >> + size_t reg_size, const void *val, > >> + size_t val_size) > >> +{ > >> + struct lpc18xx_eeprom_dev *eeprom = context; > >> + unsigned int offset = *(u32 *)reg; > >> + > >> + /* 3 ms of erase/program time between each writing */ > >> + while (val_size) { > >> + writel(*(u32 *)val, eeprom->mem_base + offset); > >> + usleep_range(3000, 4000); > > > > i think it would be good to verify that the EEPROM write operation has > > really finished. > > I'm not sure what are you proposing. Why could the write operation not > finish? it's always good to keep in sync with the hardware. Here is an extract of chapter "46.6.2.1 Writing and erase/programming" from the datasheet [1]: During programming, the EEPROM is not available for other operations. To prevent undesired loss in performance which would be caused by stalling the bus, the EEPROM instead generates an error for AHB read/writes and APB writes when programming is busy. In order to prevent the error response, the program operation finished interrupt can be enabled or the interrupt status bit can be polled. Please blame me if it doesn't apply. It's only a suggestion: How about checking the interrupt status bit for END_OF_PROG after the 3 ms sleep? Best regards Stefan [1] - http://www.nxp.com/documents/user_manual/UM10430.pdf > > -- > Ariel D'Alessandro, VanguardiaSur > www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-17 10:01 ` Stefan Wahren 0 siblings, 0 replies; 50+ messages in thread From: Stefan Wahren @ 2015-11-17 10:01 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, > Ariel D'Alessandro <ariel@vanguardiasur.com.ar> hat am 16. November 2015 um > 16:29 geschrieben: > > > Hi Stefan, > > Sorry for the delay. > > El 03/11/15 a las 05:20, Stefan Wahren escribi?: > > Hi Ariel, > > > > Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: > >> This commit adds support for NXP LPC18xx EEPROM memory found in NXP > >> LPC185x/3x and LPC435x/3x/2x/1x devices. > >> > >> EEPROM size is 16384 bytes and it can be entirely read and > >> written/erased with 1 word (4 bytes) granularity. The last page > >> (128 bytes) contains the EEPROM initialization data and is not writable. > >> > >> Erase/program time is less than 3ms. The EEPROM device requires a > >> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing > >> the system bus clock by the division factor, contained in the divider > >> register (minus 1 encoded). > >> > >> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> > >> --- > >> drivers/nvmem/Kconfig | 9 ++ > >> drivers/nvmem/Makefile | 2 + > >> drivers/nvmem/lpc18xx_eeprom.c | 266 > >> +++++++++++++++++++++++++++++++++++++++++ > >> 3 files changed, 277 insertions(+) > >> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c > >> [...] > >> + > >> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, > >> + size_t reg_size, const void *val, > >> + size_t val_size) > >> +{ > >> + struct lpc18xx_eeprom_dev *eeprom = context; > >> + unsigned int offset = *(u32 *)reg; > >> + > >> + /* 3 ms of erase/program time between each writing */ > >> + while (val_size) { > >> + writel(*(u32 *)val, eeprom->mem_base + offset); > >> + usleep_range(3000, 4000); > > > > i think it would be good to verify that the EEPROM write operation has > > really finished. > > I'm not sure what are you proposing. Why could the write operation not > finish? it's always good to keep in sync with the hardware. Here is an extract of chapter "46.6.2.1 Writing and erase/programming" from the datasheet [1]: During programming, the EEPROM is not available for other operations. To prevent undesired loss in performance which would be caused by stalling the bus, the EEPROM instead generates an error for AHB read/writes and APB writes when programming is busy. In order to prevent the error response, the program operation finished interrupt can be enabled or the interrupt status bit can be polled. Please blame me if it doesn't apply. It's only a suggestion: How about checking the interrupt status bit for END_OF_PROG after the 3 ms sleep? Best regards Stefan [1] - http://www.nxp.com/documents/user_manual/UM10430.pdf > > -- > Ariel D'Alessandro, VanguardiaSur > www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
[parent not found: <1526033037.5264.1447754499675.JavaMail.open-xchange-h4m1HHXQYNFdfASV6gReHsgmgJlYmuWJ@public.gmane.org>]
* Re: [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver 2015-11-17 10:01 ` Stefan Wahren @ 2015-11-17 19:53 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-17 19:53 UTC (permalink / raw) To: Stefan Wahren Cc: manabian-Re5JQEeQqe8AvxtiuMwx3w, srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, pawel.moll-5wv7dgnIgG8, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, galak-sgV2jX0FEOL9JmXXK+q4OQ, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, mark.rutland-5wv7dgnIgG8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, devicetree-u79uwXL29TY76Z2rM5mHXA Stefan, El 17/11/15 a las 07:01, Stefan Wahren escribió: > Hi Ariel, > >> Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> hat am 16. November 2015 um >> 16:29 geschrieben: >> >> >> Hi Stefan, >> >> Sorry for the delay. >> >> El 03/11/15 a las 05:20, Stefan Wahren escribió: >>> Hi Ariel, >>> >>> Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: >>>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>>> >>>> EEPROM size is 16384 bytes and it can be entirely read and >>>> written/erased with 1 word (4 bytes) granularity. The last page >>>> (128 bytes) contains the EEPROM initialization data and is not writable. >>>> >>>> Erase/program time is less than 3ms. The EEPROM device requires a >>>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>>> the system bus clock by the division factor, contained in the divider >>>> register (minus 1 encoded). >>>> >>>> Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> >>>> --- >>>> drivers/nvmem/Kconfig | 9 ++ >>>> drivers/nvmem/Makefile | 2 + >>>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>>> +++++++++++++++++++++++++++++++++++++++++ >>>> 3 files changed, 277 insertions(+) >>>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >>>> [...] >>>> + >>>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>>> + size_t reg_size, const void *val, >>>> + size_t val_size) >>>> +{ >>>> + struct lpc18xx_eeprom_dev *eeprom = context; >>>> + unsigned int offset = *(u32 *)reg; >>>> + >>>> + /* 3 ms of erase/program time between each writing */ >>>> + while (val_size) { >>>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>>> + usleep_range(3000, 4000); >>> >>> i think it would be good to verify that the EEPROM write operation has >>> really finished. >> >> I'm not sure what are you proposing. Why could the write operation not >> finish? > > it's always good to keep in sync with the hardware. Here is an extract of > chapter > "46.6.2.1 Writing and erase/programming" from the datasheet [1]: > > During programming, the EEPROM is not available for other operations. To > prevent > undesired loss in performance which would be caused by stalling the bus, the > EEPROM > instead generates an error for AHB read/writes and APB writes when programming > is > busy. In order to prevent the error response, the program operation finished > interrupt > can be enabled or the interrupt status bit can be polled. > > Please blame me if it doesn't apply. > > It's only a suggestion: How about checking the interrupt status bit for > END_OF_PROG after the 3 ms sleep? Yeah, I think that's a good idea, pretty simple and it will ensure (although 3ms should be enough) erase/program operation has effectively finished. Thanks for the explanation and suggestion. I'm submitting patchset v4 with this. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver @ 2015-11-17 19:53 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-11-17 19:53 UTC (permalink / raw) To: linux-arm-kernel Stefan, El 17/11/15 a las 07:01, Stefan Wahren escribi?: > Hi Ariel, > >> Ariel D'Alessandro <ariel@vanguardiasur.com.ar> hat am 16. November 2015 um >> 16:29 geschrieben: >> >> >> Hi Stefan, >> >> Sorry for the delay. >> >> El 03/11/15 a las 05:20, Stefan Wahren escribi?: >>> Hi Ariel, >>> >>> Am 19.10.2015 um 19:32 schrieb Ariel D'Alessandro: >>>> This commit adds support for NXP LPC18xx EEPROM memory found in NXP >>>> LPC185x/3x and LPC435x/3x/2x/1x devices. >>>> >>>> EEPROM size is 16384 bytes and it can be entirely read and >>>> written/erased with 1 word (4 bytes) granularity. The last page >>>> (128 bytes) contains the EEPROM initialization data and is not writable. >>>> >>>> Erase/program time is less than 3ms. The EEPROM device requires a >>>> ~1500 kHz clock (min 800 kHz, max 1600 kHz) that is generated dividing >>>> the system bus clock by the division factor, contained in the divider >>>> register (minus 1 encoded). >>>> >>>> Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> >>>> --- >>>> drivers/nvmem/Kconfig | 9 ++ >>>> drivers/nvmem/Makefile | 2 + >>>> drivers/nvmem/lpc18xx_eeprom.c | 266 >>>> +++++++++++++++++++++++++++++++++++++++++ >>>> 3 files changed, 277 insertions(+) >>>> create mode 100644 drivers/nvmem/lpc18xx_eeprom.c >>>> [...] >>>> + >>>> +static int lpc18xx_eeprom_gather_write(void *context, const void *reg, >>>> + size_t reg_size, const void *val, >>>> + size_t val_size) >>>> +{ >>>> + struct lpc18xx_eeprom_dev *eeprom = context; >>>> + unsigned int offset = *(u32 *)reg; >>>> + >>>> + /* 3 ms of erase/program time between each writing */ >>>> + while (val_size) { >>>> + writel(*(u32 *)val, eeprom->mem_base + offset); >>>> + usleep_range(3000, 4000); >>> >>> i think it would be good to verify that the EEPROM write operation has >>> really finished. >> >> I'm not sure what are you proposing. Why could the write operation not >> finish? > > it's always good to keep in sync with the hardware. Here is an extract of > chapter > "46.6.2.1 Writing and erase/programming" from the datasheet [1]: > > During programming, the EEPROM is not available for other operations. To > prevent > undesired loss in performance which would be caused by stalling the bus, the > EEPROM > instead generates an error for AHB read/writes and APB writes when programming > is > busy. In order to prevent the error response, the program operation finished > interrupt > can be enabled or the interrupt status bit can be polled. > > Please blame me if it doesn't apply. > > It's only a suggestion: How about checking the interrupt status bit for > END_OF_PROG after the 3 ms sleep? Yeah, I think that's a good idea, pretty simple and it will ensure (although 3ms should be enough) erase/program operation has effectively finished. Thanks for the explanation and suggestion. I'm submitting patchset v4 with this. -- Ariel D'Alessandro, VanguardiaSur www.vanguardiasur.com.ar ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 3/4] ARM: dts: lpc18xx: add EEPROM memory node 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-19 17:32 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Ariel D'Alessandro Add node for the NXP LPC18xx EEPROM memory which can be found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> --- arch/arm/boot/dts/lpc18xx.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi index 52591d8..43e99cf 100644 --- a/arch/arm/boot/dts/lpc18xx.dtsi +++ b/arch/arm/boot/dts/lpc18xx.dtsi @@ -166,6 +166,18 @@ status = "disabled"; }; + eeprom: eeprom@4000e000 { + compatible = "nxp,lpc1857-eeprom"; + reg = <0x4000e000 0x1000>, + <0x20040000 0x4000>; + reg-names = "reg", "mem"; + clocks = <&ccu1 CLK_CPU_EEPROM>; + clock-names = "eeprom"; + resets = <&rgu 27>; + interrupts = <4>; + status = "disabled"; + }; + mac: ethernet@40010000 { compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac"; reg = <0x40010000 0x2000>; -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 3/4] ARM: dts: lpc18xx: add EEPROM memory node @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel Add node for the NXP LPC18xx EEPROM memory which can be found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> --- arch/arm/boot/dts/lpc18xx.dtsi | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/arch/arm/boot/dts/lpc18xx.dtsi b/arch/arm/boot/dts/lpc18xx.dtsi index 52591d8..43e99cf 100644 --- a/arch/arm/boot/dts/lpc18xx.dtsi +++ b/arch/arm/boot/dts/lpc18xx.dtsi @@ -166,6 +166,18 @@ status = "disabled"; }; + eeprom: eeprom at 4000e000 { + compatible = "nxp,lpc1857-eeprom"; + reg = <0x4000e000 0x1000>, + <0x20040000 0x4000>; + reg-names = "reg", "mem"; + clocks = <&ccu1 CLK_CPU_EEPROM>; + clock-names = "eeprom"; + resets = <&rgu 27>; + interrupts = <4>; + status = "disabled"; + }; + mac: ethernet at 40010000 { compatible = "nxp,lpc1850-dwmac", "snps,dwmac-3.611", "snps,dwmac"; reg = <0x40010000 0x2000>; -- 2.6.1 ^ permalink raw reply related [flat|nested] 50+ messages in thread
[parent not found: <1445275946-32653-4-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 3/4] ARM: dts: lpc18xx: add EEPROM memory node 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-24 21:42 ` Joachim Eastwood -1 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:42 UTC (permalink / raw) To: Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > Add node for the NXP LPC18xx EEPROM memory which can be found in > NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> Acked-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> I'll pick it up once the driver hits next. regards, Joachim Eastwood -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 3/4] ARM: dts: lpc18xx: add EEPROM memory node @ 2015-10-24 21:42 ` Joachim Eastwood 0 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:42 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > Add node for the NXP LPC18xx EEPROM memory which can be found in > NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> Acked-by: Joachim Eastwood <manabian@gmail.com> I'll pick it up once the driver hits next. regards, Joachim Eastwood ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 4/4] ARM: configs: lpc18xx: enable EEPROM NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-19 17:32 ` Ariel D'Alessandro -1 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA Cc: srinivas.kandagatla-QSEj5FYQhm4dnm+yROfE0A, maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8, ezequiel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ, manabian-Re5JQEeQqe8AvxtiuMwx3w, galak-sgV2jX0FEOL9JmXXK+q4OQ, ijc+devicetree-KcIKpvwj1kUDXYZnReoRVg, mark.rutland-5wv7dgnIgG8, pawel.moll-5wv7dgnIgG8, robh+dt-DgEjT+Ai2ygdnm+yROfE0A, Ariel D'Alessandro Enable NVMEM driver for NXP LPC18xx EEPROM, which can be found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> --- arch/arm/configs/lpc18xx_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig index b758a80..2c7e0da 100644 --- a/arch/arm/configs/lpc18xx_defconfig +++ b/arch/arm/configs/lpc18xx_defconfig @@ -149,6 +149,8 @@ CONFIG_ARM_PL172_MPMC=y CONFIG_PWM=y CONFIG_PWM_LPC18XX_SCT=y CONFIG_PHY_LPC18XX_USB_OTG=y +CONFIG_NVMEM=y +CONFIG_NVMEM_LPC18XX_EEPROM=y CONFIG_EXT2_FS=y # CONFIG_FILE_LOCKING is not set # CONFIG_DNOTIFY is not set -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply related [flat|nested] 50+ messages in thread
* [PATCH v2 4/4] ARM: configs: lpc18xx: enable EEPROM NVMEM driver @ 2015-10-19 17:32 ` Ariel D'Alessandro 0 siblings, 0 replies; 50+ messages in thread From: Ariel D'Alessandro @ 2015-10-19 17:32 UTC (permalink / raw) To: linux-arm-kernel Enable NVMEM driver for NXP LPC18xx EEPROM, which can be found in NXP LPC185x/3x and LPC435x/3x/2x/1x devices. Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> --- arch/arm/configs/lpc18xx_defconfig | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/configs/lpc18xx_defconfig b/arch/arm/configs/lpc18xx_defconfig index b758a80..2c7e0da 100644 --- a/arch/arm/configs/lpc18xx_defconfig +++ b/arch/arm/configs/lpc18xx_defconfig @@ -149,6 +149,8 @@ CONFIG_ARM_PL172_MPMC=y CONFIG_PWM=y CONFIG_PWM_LPC18XX_SCT=y CONFIG_PHY_LPC18XX_USB_OTG=y +CONFIG_NVMEM=y +CONFIG_NVMEM_LPC18XX_EEPROM=y CONFIG_EXT2_FS=y # CONFIG_FILE_LOCKING is not set # CONFIG_DNOTIFY is not set -- 2.6.1 ^ permalink raw reply related [flat|nested] 50+ messages in thread
[parent not found: <1445275946-32653-5-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org>]
* Re: [PATCH v2 4/4] ARM: configs: lpc18xx: enable EEPROM NVMEM driver 2015-10-19 17:32 ` Ariel D'Alessandro @ 2015-10-24 21:41 ` Joachim Eastwood -1 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:41 UTC (permalink / raw) To: Ariel D'Alessandro Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, devicetree-u79uwXL29TY76Z2rM5mHXA, Srinivas Kandagatla, Maxime Ripard, Ezequiel Garcia, Kumar Gala, Ian Campbell, Mark Rutland, Pawel Moll, Rob Herring Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> wrote: > Enable NVMEM driver for NXP LPC18xx EEPROM, which can be found in > NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > > Signed-off-by: Ariel D'Alessandro <ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> Acked-by: Joachim Eastwood <manabian-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> I'll pick it up once the driver hits next. regards, Joachim Eastwood -- To unsubscribe from this list: send the line "unsubscribe devicetree" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 50+ messages in thread
* [PATCH v2 4/4] ARM: configs: lpc18xx: enable EEPROM NVMEM driver @ 2015-10-24 21:41 ` Joachim Eastwood 0 siblings, 0 replies; 50+ messages in thread From: Joachim Eastwood @ 2015-10-24 21:41 UTC (permalink / raw) To: linux-arm-kernel Hi Ariel, On 19 October 2015 at 19:32, Ariel D'Alessandro <ariel@vanguardiasur.com.ar> wrote: > Enable NVMEM driver for NXP LPC18xx EEPROM, which can be found in > NXP LPC185x/3x and LPC435x/3x/2x/1x devices. > > Signed-off-by: Ariel D'Alessandro <ariel@vanguardiasur.com.ar> Acked-by: Joachim Eastwood <manabian@gmail.com> I'll pick it up once the driver hits next. regards, Joachim Eastwood ^ permalink raw reply [flat|nested] 50+ messages in thread
end of thread, other threads:[~2015-12-03 18:39 UTC | newest] Thread overview: 50+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-10-19 17:32 [PATCH v2 0/4] Add support for NXP LPC18xx EEPROM using nvmem Ariel D'Alessandro 2015-10-19 17:32 ` Ariel D'Alessandro [not found] ` <1445275946-32653-1-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-19 17:32 ` [PATCH v2 1/4] DT: nvmem: Add NXP LPC18xx EEPROM memory binding documentation Ariel D'Alessandro 2015-10-19 17:32 ` Ariel D'Alessandro [not found] ` <1445275946-32653-2-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-24 21:44 ` Joachim Eastwood 2015-10-24 21:44 ` Joachim Eastwood [not found] ` <CAGhQ9VyCBTWh6qgZ__eNLqooNURsYr9ZVtDz2qCKoa0MoVgXtA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2015-10-30 12:45 ` Ariel D'Alessandro 2015-10-30 12:45 ` Ariel D'Alessandro 2015-10-27 7:49 ` Rob Herring 2015-10-27 7:49 ` Rob Herring 2015-10-19 17:32 ` [PATCH v2 2/4] nvmem: NXP LPC18xx EEPROM memory NVMEM driver Ariel D'Alessandro 2015-10-19 17:32 ` Ariel D'Alessandro [not found] ` <1445275946-32653-3-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-24 22:04 ` Joachim Eastwood 2015-10-24 22:04 ` Joachim Eastwood [not found] ` <CAGhQ9Vyg6sScq7yM=7judsMPHOc5VF2zf=7LPxmbmL7wF=vvgw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2015-10-26 13:37 ` Srinivas Kandagatla 2015-10-26 13:37 ` Srinivas Kandagatla [not found] ` <562E2CB1.80706-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2015-10-30 14:58 ` Ariel D'Alessandro 2015-10-30 14:58 ` Ariel D'Alessandro [not found] ` <563385B2.90403-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-11-16 15:33 ` Ariel D'Alessandro 2015-11-16 15:33 ` Ariel D'Alessandro [not found] ` <5649F74A.9020706-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-11-16 15:37 ` Srinivas Kandagatla 2015-11-16 15:37 ` Srinivas Kandagatla [not found] ` <5649F856.9000101-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2015-12-03 18:39 ` Ezequiel Garcia 2015-12-03 18:39 ` Ezequiel Garcia 2015-10-30 14:55 ` Ariel D'Alessandro 2015-10-30 14:55 ` Ariel D'Alessandro [not found] ` <563384CB.3070607-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-11-16 15:24 ` Ariel D'Alessandro 2015-11-16 15:24 ` Ariel D'Alessandro 2015-10-26 14:23 ` Srinivas Kandagatla 2015-10-26 14:23 ` Srinivas Kandagatla [not found] ` <562E377A.3040604-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2015-10-30 15:42 ` Ariel D'Alessandro 2015-10-30 15:42 ` Ariel D'Alessandro [not found] ` <56338FF4.8050102-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-30 16:00 ` Ezequiel Garcia 2015-10-30 16:00 ` Ezequiel Garcia 2015-11-03 8:20 ` Stefan Wahren 2015-11-03 8:20 ` Stefan Wahren [not found] ` <56386E30.4060905-eS4NqCHxEME@public.gmane.org> 2015-11-16 15:29 ` Ariel D'Alessandro 2015-11-16 15:29 ` Ariel D'Alessandro [not found] ` <5649F64B.5050407-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-11-17 10:01 ` Stefan Wahren 2015-11-17 10:01 ` Stefan Wahren [not found] ` <1526033037.5264.1447754499675.JavaMail.open-xchange-h4m1HHXQYNFdfASV6gReHsgmgJlYmuWJ@public.gmane.org> 2015-11-17 19:53 ` Ariel D'Alessandro 2015-11-17 19:53 ` Ariel D'Alessandro 2015-10-19 17:32 ` [PATCH v2 3/4] ARM: dts: lpc18xx: add EEPROM memory node Ariel D'Alessandro 2015-10-19 17:32 ` Ariel D'Alessandro [not found] ` <1445275946-32653-4-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-24 21:42 ` Joachim Eastwood 2015-10-24 21:42 ` Joachim Eastwood 2015-10-19 17:32 ` [PATCH v2 4/4] ARM: configs: lpc18xx: enable EEPROM NVMEM driver Ariel D'Alessandro 2015-10-19 17:32 ` Ariel D'Alessandro [not found] ` <1445275946-32653-5-git-send-email-ariel-30ULvvUtt6G51wMPkGsGjgyUoB5FGQPZ@public.gmane.org> 2015-10-24 21:41 ` Joachim Eastwood 2015-10-24 21:41 ` Joachim Eastwood
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.