* Re: [PATCH v3 2/5] mtd: aspeed: add memory controllers for the Aspeed AST2400 SoC
From: Marek Vasut @ 2016-12-10 4:03 UTC (permalink / raw)
To: Cédric Le Goater, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <1481302167-28044-3-git-send-email-clg-Bxea+6Xhats@public.gmane.org>
On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
> This driver adds mtd support for the Aspeed AST2400 SoC static memory
> controllers:
>
> * New Static Memory Controller (referred as FMC)
> . BMC firmware
> . AST2500 compatible register set
> . 5 chip select pins (CE0 ∼ CE4)
> . supports NOR flash, NAND flash and SPI flash memory.
>
> * SPI Flash Controller (SPI)
> . host Firmware
> . slightly different register set, between AST2500 and the legacy
> controller
> . supports SPI flash memory
> . 1 chip select pin (CE0)
>
> The legacy static memory controller (referred as SMC) is not
> supported, as well as types other than SPI.
>
> Signed-off-by: Cédric Le Goater <clg-Bxea+6Xhats@public.gmane.org>
Well this is a nice split :-)
> ---
> drivers/mtd/spi-nor/Kconfig | 2 +-
> drivers/mtd/spi-nor/aspeed-smc.c | 33 +++++++++++++++++++++++++++++++++
> 2 files changed, 34 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
> index 5c0efbd9dd89..22bea563f9bc 100644
> --- a/drivers/mtd/spi-nor/Kconfig
> +++ b/drivers/mtd/spi-nor/Kconfig
> @@ -35,7 +35,7 @@ config SPI_ASPEED
> depends on HAS_IOMEM && OF
> help
> This enables support for the Firmware Memory controller (FMC)
> - in the Aspeed AST2500 SoC when attached to SPI NOR chips,
> + in the Aspeed AST2500/AST2400 SoCs when attached to SPI NOR chips,
> and support for the SPI flash memory controller (SPI) for
> the host firmware. The implementation only supports SPI NOR.
>
> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
> index 6f9244f07aef..99302b0d7786 100644
> --- a/drivers/mtd/spi-nor/aspeed-smc.c
> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
> @@ -119,8 +119,27 @@ struct aspeed_smc_info {
> void (*set_4b)(struct aspeed_smc_chip *chip);
> };
>
> +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip);
> static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
>
> +static const struct aspeed_smc_info fmc_2400_info = {
> + .maxsize = 64 * 1024 * 1024,
> + .nce = 5,
> + .hastype = true,
> + .we0 = 16,
> + .ctl0 = 0x10,
> + .set_4b = aspeed_smc_chip_set_4b,
> +};
> +
> +static const struct aspeed_smc_info spi_2400_info = {
> + .maxsize = 64 * 1024 * 1024,
> + .nce = 1,
> + .hastype = false,
> + .we0 = 0,
> + .ctl0 = 0x04,
> + .set_4b = aspeed_smc_chip_set_4b_spi_2400,
> +};
> +
> static const struct aspeed_smc_info fmc_2500_info = {
> .maxsize = 256 * 1024 * 1024,
> .nce = 3,
> @@ -210,6 +229,7 @@ struct aspeed_smc_controller {
> #define CONTROL_IO_DUMMY_HI BIT(14)
> #define CONTROL_IO_DUMMY_HI_SHIFT 14
> #define CONTROL_CLK_DIV4 BIT(13) /* others */
> +#define CONTROL_IO_ADDRESS_4B BIT(13) /* AST2400 SPI */
> #define CONTROL_RW_MERGE BIT(12)
> #define CONTROL_IO_DUMMY_LO_SHIFT 6
> #define CONTROL_IO_DUMMY_LO GENMASK(7, \
> @@ -406,6 +426,8 @@ static int aspeed_smc_remove(struct platform_device *dev)
> }
>
> static const struct of_device_id aspeed_smc_matches[] = {
> + { .compatible = "aspeed,ast2400-fmc", .data = &fmc_2400_info },
> + { .compatible = "aspeed,ast2400-spi", .data = &spi_2400_info },
> { .compatible = "aspeed,ast2500-fmc", .data = &fmc_2500_info },
> { .compatible = "aspeed,ast2500-spi", .data = &spi_2500_info },
> { }
> @@ -479,6 +501,17 @@ static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip)
> }
> }
>
> +/*
> + * The AST2400 SPI flash controller does not have a CE Control
> + * register. It uses the CE0 control register to set 4Byte mode at the
> + * controller level.
> + */
> +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip)
> +{
> + chip->ctl_val[smc_base] |= CONTROL_IO_ADDRESS_4B;
> + chip->ctl_val[smc_read] |= CONTROL_IO_ADDRESS_4B;
How do you know the SPI NOR is in 4B mode ?
> +}
> +
> static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
> struct resource *res)
> {
>
--
Best regards,
Marek Vasut
--
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
* Re: [PATCH v3 3/5] mtd: aspeed: used a label property
From: Marek Vasut @ 2016-12-10 4:03 UTC (permalink / raw)
To: Cédric Le Goater, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <1481302167-28044-4-git-send-email-clg-Bxea+6Xhats@public.gmane.org>
On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
> This can be used to easily identify a chip on a system with multiple
> chips.
I don't think I understand what this patch does.
It seems to me like this one should be wrapped into 1/5.
> Signed-off-by: Cédric Le Goater <clg-Bxea+6Xhats@public.gmane.org>
> ---
> drivers/mtd/spi-nor/aspeed-smc.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
> index 99302b0d7786..9119c0ca86b6 100644
> --- a/drivers/mtd/spi-nor/aspeed-smc.c
> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
> @@ -676,6 +676,8 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
> nor->prepare = aspeed_smc_prep;
> nor->unprepare = aspeed_smc_unprep;
>
> + mtd->name = of_get_property(child, "label", NULL);
> +
> ret = aspeed_smc_chip_setup_init(chip, r);
> if (ret)
> break;
>
--
Best regards,
Marek Vasut
--
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
* Re: [PATCH 1/1] of: of_reserved_mem: Ensure cma reserved region not cross the low/high memory
From: Jason Liu @ 2016-12-10 4:29 UTC (permalink / raw)
To: Jason Liu
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA, LKML,
labbott-H+wXaHxf7aLQT0dZR+AlfA,
frowand.list-Re5JQEeQqe8AvxtiuMwx3w,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <1479901021-25064-1-git-send-email-jason.hui.liu-3arQi8VN3Tc@public.gmane.org>
2016-11-23 19:37 GMT+08:00 Jason Liu <jason.hui.liu-3arQi8VN3Tc@public.gmane.org>:
> Need ensure the cma reserved region not cross the low/high memory boundary
> when using the dynamic allocation methond through device-tree, otherwise,
> kernel will fail to boot up when cma reserved region cross how/high mem.
>
> Signed-off-by: Jason Liu <jason.hui.liu-3arQi8VN3Tc@public.gmane.org>
> Cc: Laura Abbott <labbott-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
> Cc: Frank Rowand <frowand.list-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: stable-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> ---
> drivers/of/of_reserved_mem.c | 42 +++++++++++++++++++++++++++++++----------
> include/linux/of_reserved_mem.h | 3 ++-
> 2 files changed, 34 insertions(+), 11 deletions(-)
Rob, any comments about this patch?
Jason Liu
>
> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> index 366d8c3..852345a 100644
> --- a/drivers/of/of_reserved_mem.c
> +++ b/drivers/of/of_reserved_mem.c
> @@ -31,11 +31,15 @@
>
> #if defined(CONFIG_HAVE_MEMBLOCK)
> #include <linux/memblock.h>
> -int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
> - phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
> - phys_addr_t *res_base)
> +int __init __weak early_init_dt_alloc_reserved_memory_arch(unsigned long node,
> + phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end,
> + bool nomap, phys_addr_t *res_base)
> {
> phys_addr_t base;
> + phys_addr_t highmem_start;
> +
> + highmem_start = __pa(high_memory - 1) + 1;
> +
> /*
> * We use __memblock_alloc_base() because memblock_alloc_base()
> * panic()s on allocation failure.
> @@ -53,15 +57,33 @@ int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
> return -ENOMEM;
> }
>
> + /*
> + * Sanity check for the cma reserved region:If the reserved region
> + * crosses the low/high memory boundary, try to fix it up and then
> + * fall back to allocate the cma region from the low mememory space.
> + */
> +
> + if (IS_ENABLED(CONFIG_CMA)
> + && of_flat_dt_is_compatible(node, "shared-dma-pool")
> + && of_get_flat_dt_prop(node, "reusable", NULL) && !nomap) {
> + if (base < highmem_start && (base + size) > highmem_start) {
> + memblock_free(base, size);
> + base = memblock_alloc_range(size, align, start,
> + highmem_start, MEMBLOCK_NONE);
> + if (!base)
> + return -ENOMEM;
> + }
> + }
> +
> *res_base = base;
> if (nomap)
> return memblock_remove(base, size);
> return 0;
> }
> #else
> -int __init __weak early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
> - phys_addr_t align, phys_addr_t start, phys_addr_t end, bool nomap,
> - phys_addr_t *res_base)
> +int __init __weak early_init_dt_alloc_reserved_memory_arch(unsigned long node,
> + phys_addr_t size, phys_addr_t align, phys_addr_t start, phys_addr_t end,
> + bool nomap, phys_addr_t *res_base)
> {
> pr_err("Reserved memory not supported, ignoring region 0x%llx%s\n",
> size, nomap ? " (nomap)" : "");
> @@ -155,8 +177,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
> end = start + dt_mem_next_cell(dt_root_size_cells,
> &prop);
>
> - ret = early_init_dt_alloc_reserved_memory_arch(size,
> - align, start, end, nomap, &base);
> + ret = early_init_dt_alloc_reserved_memory_arch(node,
> + size, align, start, end, nomap, &base);
> if (ret == 0) {
> pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
> uname, &base,
> @@ -167,8 +189,8 @@ static int __init __reserved_mem_alloc_size(unsigned long node,
> }
>
> } else {
> - ret = early_init_dt_alloc_reserved_memory_arch(size, align,
> - 0, 0, nomap, &base);
> + ret = early_init_dt_alloc_reserved_memory_arch(node,
> + size, align, 0, 0, nomap, &base);
> if (ret == 0)
> pr_debug("allocated memory for '%s' node: base %pa, size %ld MiB\n",
> uname, &base, (unsigned long)size / SZ_1M);
> diff --git a/include/linux/of_reserved_mem.h b/include/linux/of_reserved_mem.h
> index f8e1992..a6ee451 100644
> --- a/include/linux/of_reserved_mem.h
> +++ b/include/linux/of_reserved_mem.h
> @@ -34,7 +34,8 @@ int of_reserved_mem_device_init_by_idx(struct device *dev,
> struct device_node *np, int idx);
> void of_reserved_mem_device_release(struct device *dev);
>
> -int early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
> +int early_init_dt_alloc_reserved_memory_arch(unsigned long node,
> + phys_addr_t size,
> phys_addr_t align,
> phys_addr_t start,
> phys_addr_t end,
> --
> 1.8.3.2
>
--
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
* Re: [PATCH 4/4] mmc: pwrseq-simple: add disable-post-power-on option
From: Matt Ranostay @ 2016-12-10 5:47 UTC (permalink / raw)
To: Rob Herring
Cc: Ulf Hansson, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-mmc-u79uwXL29TY76Z2rM5mHXA, Tony Lindgren, Liam Breck
In-Reply-To: <20161209180930.nsy2ys66q2thbxpx@rob-hp-laptop>
On Fri, Dec 9, 2016 at 10:09 AM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> On Fri, Dec 02, 2016 at 01:06:47AM -0800, Matt Ranostay wrote:
>> On Fri, Dec 2, 2016 at 12:28 AM, Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>> > On 2 December 2016 at 08:22, Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org> wrote:
>> >>
>> >>
>> >>> On Dec 1, 2016, at 23:13, Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> wrote:
>> >>>
>> >>>> On 2 December 2016 at 07:17, Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org> wrote:
>> >>>> Add optional device-post-power-on parameters to disable post_power_on
>> >>>> function from being called since this breaks some device.
>> >>>>
>> >>>> Cc: Tony Lindgren <tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org>
>> >>>> Cc: Ulf Hansson <ulf.hansson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
>> >>>> Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
>> >>>> ---
>> >>>> Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt | 2 ++
>> >>>> drivers/mmc/core/pwrseq_simple.c | 7 +++++++
>> >>>> 2 files changed, 9 insertions(+)
>> >>>>
>> >>>> diff --git a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>> >>>> index bea306d772d1..09fa153f743e 100644
>> >>>> --- a/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>> >>>> +++ b/Documentation/devicetree/bindings/mmc/mmc-pwrseq-simple.txt
>> >>>> @@ -24,6 +24,8 @@ Optional properties:
>> >>>> de-asserting the reset-gpios (if any)
>> >>>> - invert-off-state: Invert the power down state for the reset-gpios (if any)
>> >>>> and pwrdn-gpios (if any)
>> >>>> +- disable-post-power-on : Avoid post_power_on function from being called since
>> >>>> + this breaks some devices
>> >>>
>> >>> This is a bit weird. I would like to avoid this, if possible.
>> >>>
>> >>> Perhaps if you simply describe the sequence in detail for your device
>> >>> we can figure out the best option together.
>> >>
>> >> Yeah I know it is a bit weird but we need to keep that reset pin high for at least some time after pre power on. So any case it would be another property
>> >
>> > This went offlist, please resend.
>> >
>> > Moreover, please try to describe the sequence you need in detail
>> > according to your HW spec.
>> >
>>
>> Yeah oops....
>>
>> So basically we need to drive the reset and powerdown lines high with
>> a 300 milliseconds delay between both...
>> can't have the reset line low with post power on (pretty sure but
>> would need a delay anyway), and we need both reset + powerdown line
>> set low on powerdown.
>>
>> So the power down sequence would need to be reversed for this
>> application in pwrseq-simple.
>
> This sounds like you need a device specific sequence to me. Otherwise,
> write a language to describe any power control waveforms rather than
> trying to bolt on more and more properties. (Don't really go write a
> language.)
>
Yeah I no interest in that as well :).
So I'll resubmit with the patchset comments so far.
> Rob
--
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
* [PATCH 1/2] devicetree: add Garmin vendor prefix
From: Matt Ranostay @ 2016-12-10 6:35 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA; +Cc: Matt Ranostay, Rob Herring
Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Matt Ranostay <matt-sk+viVC6FLCDq+mSdOJa79kegs52MxvZ@public.gmane.org>
---
Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 64fdc8c1503b..aedd9979d1e9 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -106,6 +106,7 @@ firefly Firefly
focaltech FocalTech Systems Co.,Ltd
friendlyarm Guangzhou FriendlyARM Computer Tech Co., Ltd
fsl Freescale Semiconductor
+garmin Garmin Limited
ge General Electric Company
geekbuying GeekBuying
gef GE Fanuc Intelligent Platforms Embedded Systems, Inc.
--
2.7.4
--
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
* Re: [RFC PATCH] ARM: dts: Add support for Turris Omnia
From: Pavel Machek @ 2016-12-10 8:16 UTC (permalink / raw)
To: Tomas Hlavacek
Cc: Andrew Lunn, Uwe Kleine-König, Rob Herring, Mark Rutland,
Russell King, Jason Cooper, Gregory Clement,
Sebastian Hesselbarth, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1480078151.381.4-TAvD023jEQEN+BqQ9rBEUg@public.gmane.org>
Hi!
> >Yes. That is fine. It is just unusual. Most boards have gpio-led and
> >gpio-keys, which are easy to add. That is why i asked. Adding an LED
> >driver which talks to this M0 can be added later.
>
> Actually the WiP driver for MCU LED interface, that we use in our
> kernel is here: https://github.com/tmshlvck/omnia-linux/commit/2121afd8fbd2e4c720edcdd472b11b5303bc0dfb
>
> It definitely needs some cleanup and it adds non-standard features
> (main PWM for all LEDs, autonomous blink mode, colors) via custom
> /sys files, which I suspect that is not going to be acceptable for
> upstream. Let's keep it for the next iteration.
Actually, LEDs that can do PWM intensity on their own are common and
supported.
LEDs that can do PWM pretty advanced patterns are common in the cellphones,
as is the color. Unfortunately, good support in kernel is missing. It
would be good to change that.
In n900, I have a LED that can compute prime numbers then blink them,
autonomously. We probably don't need to support _that_, but common
support for patterns would be good.
Best regards,
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
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
* [PATCH v3 0/2] add support to STM LSM6DS3-LSM6DSM 6-axis Mems sensor
From: Lorenzo Bianconi @ 2016-12-10 9:02 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.bianconi-qxv4g6HH51o
Changes since v2:
- improve code documentation
- improve code readability
- use spi_write() instead of spi_sync_transfer() in st_lsm6dsx_spi_write()
- use SMBus commands instead of I2C protocol
- use fifo_lock mutex to prevent concurrent access to hw FIFO instead of
disabling/enabling irq line in st_lsm6dsx_flush_fifo()
- rename ring occurrences in buffer ones
Changes since v1:
- add sw fifo support
- drop trigger dependency
- use iio_claim_direct_mode() routine instead of grabbing the mutex directly
- use more unique prefix for all defines
- use info_mask_shared_by_all element for sampling_frequency
- use devm_iio_* routines
- use of_match_ptr instead of access directly to of_match_table
- fix device tree binding
- rename st_lsm6dsx_dev in st_lsm6dsx_hw
- cosmetics
Lorenzo Bianconi (2):
iio: imu: add support to lsm6dsx driver
Documentation: dt: iio: add st_lsm6dsx sensor device binding
.../devicetree/bindings/iio/imu/st_lsm6dsx.txt | 24 +
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 2 +
drivers/iio/imu/st_lsm6dsx/Kconfig | 23 +
drivers/iio/imu/st_lsm6dsx/Makefile | 5 +
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 133 +++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 437 ++++++++++++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 655 +++++++++++++++++++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 88 +++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 126 ++++
10 files changed, 1494 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
create mode 100644 drivers/iio/imu/st_lsm6dsx/Kconfig
create mode 100644 drivers/iio/imu/st_lsm6dsx/Makefile
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
--
2.9.3
--
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
* [PATCH v3 1/2] iio: imu: add support to lsm6dsx driver
From: Lorenzo Bianconi @ 2016-12-10 9:02 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.bianconi-qxv4g6HH51o
In-Reply-To: <20161210090218.4609-1-lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
Add support to STM LSM6DS3-LSM6DSM 6-axis (acc + gyro) Mems sensor
http://www.st.com/resource/en/datasheet/lsm6ds3.pdf
http://www.st.com/resource/en/datasheet/lsm6dsm.pdf
- continuous mode support
- i2c support
- spi support
- sw fifo mode support
- supported devices: lsm6ds3, lsm6dsm
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
---
drivers/iio/imu/Kconfig | 1 +
drivers/iio/imu/Makefile | 2 +
drivers/iio/imu/st_lsm6dsx/Kconfig | 23 +
drivers/iio/imu/st_lsm6dsx/Makefile | 5 +
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h | 133 +++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c | 437 +++++++++++++++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c | 655 +++++++++++++++++++++++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c | 88 ++++
drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c | 126 +++++
9 files changed, 1470 insertions(+)
create mode 100644 drivers/iio/imu/st_lsm6dsx/Kconfig
create mode 100644 drivers/iio/imu/st_lsm6dsx/Makefile
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
create mode 100644 drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 1f1ad41..156630a 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -39,6 +39,7 @@ config KMX61
be called kmx61.
source "drivers/iio/imu/inv_mpu6050/Kconfig"
+source "drivers/iio/imu/st_lsm6dsx/Kconfig"
endmenu
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index c71bcd3..8b563c3 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -17,3 +17,5 @@ obj-y += bmi160/
obj-y += inv_mpu6050/
obj-$(CONFIG_KMX61) += kmx61.o
+
+obj-y += st_lsm6dsx/
diff --git a/drivers/iio/imu/st_lsm6dsx/Kconfig b/drivers/iio/imu/st_lsm6dsx/Kconfig
new file mode 100644
index 0000000..2ebcb74
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/Kconfig
@@ -0,0 +1,23 @@
+
+config IIO_ST_LSM6DSX
+ tristate "ST_LSM6DSx driver for STM 6-axis IMU MEMS sensors"
+ depends on (I2C || SPI)
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ select IIO_ST_LSM6DSX_I2C if (I2C)
+ select IIO_ST_LSM6DSX_SPI if (SPI_MASTER)
+ help
+ Say yes here to build support for STMicroelectronics LSM6DSx imu
+ sensor. Supported devices: lsm6ds3, lsm6dsm
+
+ To compile this driver as a module, choose M here: the module
+ will be called st_lsm6dsx.
+
+config IIO_ST_LSM6DSX_I2C
+ tristate
+ depends on IIO_ST_LSM6DSX
+
+config IIO_ST_LSM6DSX_SPI
+ tristate
+ depends on IIO_ST_LSM6DSX
+
diff --git a/drivers/iio/imu/st_lsm6dsx/Makefile b/drivers/iio/imu/st_lsm6dsx/Makefile
new file mode 100644
index 0000000..35919fe
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/Makefile
@@ -0,0 +1,5 @@
+st_lsm6dsx-y := st_lsm6dsx_core.o st_lsm6dsx_buffer.o
+
+obj-$(CONFIG_IIO_ST_LSM6DSX) += st_lsm6dsx.o
+obj-$(CONFIG_IIO_ST_LSM6DSX_I2C) += st_lsm6dsx_i2c.o
+obj-$(CONFIG_IIO_ST_LSM6DSX_SPI) += st_lsm6dsx_spi.o
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
new file mode 100644
index 0000000..5831f63
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx.h
@@ -0,0 +1,133 @@
+/*
+ * STMicroelectronics st_lsm6dsx sensor driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
+ * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#ifndef ST_LSM6DSX_H
+#define ST_LSM6DSX_H
+
+#include <linux/device.h>
+
+#define ST_LSM6DS3_DEV_NAME "lsm6ds3"
+#define ST_LSM6DSM_DEV_NAME "lsm6dsm"
+
+#define ST_LSM6DSX_CHAN_SIZE 2
+#define ST_LSM6DSX_SAMPLE_SIZE 6
+#define ST_LSM6DSX_SAMPLE_DEPTH (ST_LSM6DSX_SAMPLE_SIZE / \
+ ST_LSM6DSX_CHAN_SIZE)
+
+#define ST_LSM6DSX_RX_MAX_LENGTH 8
+#define ST_LSM6DSX_TX_MAX_LENGTH 8
+
+struct st_lsm6dsx_transfer_buffer {
+ u8 rx_buf[ST_LSM6DSX_RX_MAX_LENGTH];
+ u8 tx_buf[ST_LSM6DSX_TX_MAX_LENGTH] ____cacheline_aligned;
+};
+
+struct st_lsm6dsx_transfer_function {
+ int (*read)(struct device *dev, u8 addr, int len, u8 *data);
+ int (*write)(struct device *dev, u8 addr, int len, u8 *data);
+};
+
+struct st_lsm6dsx_reg {
+ u8 addr;
+ u8 mask;
+};
+
+struct st_lsm6dsx_settings {
+ u8 wai;
+ u16 max_fifo_size;
+};
+
+enum st_lsm6dsx_sensor_id {
+ ST_LSM6DSX_ID_ACC,
+ ST_LSM6DSX_ID_GYRO,
+ ST_LSM6DSX_ID_MAX,
+};
+
+enum st_lsm6dsx_fifo_mode {
+ ST_LSM6DSX_FIFO_BYPASS = 0x0,
+ ST_LSM6DSX_FIFO_CONT = 0x6,
+};
+
+/**
+ * struct st_lsm6dsx_sensor - ST IMU sensor instance
+ * @id: Sensor identifier.
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ * @gain: Configured sensor sensitivity.
+ * @odr: Output data rate of the sensor [Hz].
+ * @watermark: Sensor watermark level.
+ * @sip: Number of samples in a given pattern.
+ * @decimator: FIFO decimation factor.
+ * @decimator_mask: Sensor mask for decimation register.
+ * @delta_ts: Delta time between two consecutive interrupts.
+ * @ts: Latest timestamp from the interrupt handler.
+ */
+struct st_lsm6dsx_sensor {
+ enum st_lsm6dsx_sensor_id id;
+ struct st_lsm6dsx_hw *hw;
+
+ u32 gain;
+ u16 odr;
+
+ u16 watermark;
+ u8 sip;
+ u8 decimator;
+ u8 decimator_mask;
+
+ s64 delta_ts;
+ s64 ts;
+};
+
+/**
+ * struct st_lsm6dsx_hw - ST IMU MEMS hw instance
+ * @name: Pointer to the device name (I2C name or SPI modalias).
+ * @dev: Pointer to instance of struct device (I2C or SPI).
+ * @irq: Device interrupt line (I2C or SPI).
+ * @lock: Mutex to protect read and write operations.
+ * @fifo_lock: Mutex to prevent concurrent access to the hw FIFO.
+ * @fifo_mode: FIFO operating mode supported by the device.
+ * @enable_mask: Enabled sensor bitmask.
+ * @sip: Total number of samples (acc/gyro) in a given pattern.
+ * @iio_devs: Pointers to acc/gyro iio_dev instances.
+ * @settings: Pointer to the specific sensor settings in use.
+ * @tf: Transfer function structure used by I/O operations.
+ * @tb: Transfer buffers used by SPI I/O operations.
+ */
+struct st_lsm6dsx_hw {
+ const char *name;
+ struct device *dev;
+ int irq;
+
+ struct mutex lock;
+ struct mutex fifo_lock;
+
+ enum st_lsm6dsx_fifo_mode fifo_mode;
+ u8 enable_mask;
+ u8 sip;
+
+ struct iio_dev *iio_devs[ST_LSM6DSX_ID_MAX];
+
+ const struct st_lsm6dsx_settings *settings;
+
+ const struct st_lsm6dsx_transfer_function *tf;
+ struct st_lsm6dsx_transfer_buffer tb;
+};
+
+int st_lsm6dsx_probe(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor);
+int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor);
+int st_lsm6dsx_allocate_buffers(struct st_lsm6dsx_hw *hw);
+int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
+ u8 val);
+int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor,
+ u16 watermark);
+
+#endif /* ST_LSM6DSX_H */
+
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
new file mode 100644
index 0000000..7f4032d
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_buffer.c
@@ -0,0 +1,437 @@
+/*
+ * STMicroelectronics st_lsm6dsx FIFO buffer library driver
+ *
+ * LSM6DS3/LSM6DSM: The FIFO buffer can be configured to store data
+ * from gyroscope and accelerometer. Samples are queued without any tag
+ * according to a specific pattern based on 'FIFO data sets' (6 bytes each):
+ * - 1st data set is reserved for gyroscope data
+ * - 2nd data set is reserved for accelerometer data
+ * The FIFO pattern changes depending on the ODRs and decimation factors
+ * assigned to the FIFO data sets. The first sequence of data stored in FIFO
+ * buffer contains the data of all the enabled FIFO data sets
+ * (e.g. Gx, Gy, Gz, Ax, Ay, Az), then data are repeated depending on the
+ * value of the decimation factor and ODR set for each FIFO data set.
+ * FIFO supported modes:
+ * - BYPASS: FIFO disabled
+ * - CONTINUOUS: FIFO enabled. When the buffer is full, the FIFO index
+ * restarts from the beginning and the oldest sample is overwritten
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
+ * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
+ *
+ * Licensed under the GPL-2.
+ */
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/iio/kfifo_buf.h>
+
+#include "st_lsm6dsx.h"
+
+#define ST_LSM6DSX_REG_FIFO_THL_ADDR 0x06
+#define ST_LSM6DSX_REG_FIFO_THH_ADDR 0x07
+#define ST_LSM6DSX_FIFO_TH_MASK GENMASK(11, 0)
+#define ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR 0x08
+#define ST_LSM6DSX_REG_FIFO_MODE_ADDR 0x0a
+#define ST_LSM6DSX_FIFO_MODE_MASK GENMASK(2, 0)
+#define ST_LSM6DSX_FIFO_ODR_MASK GENMASK(6, 3)
+#define ST_LSM6DSX_REG_FIFO_DIFFL_ADDR 0x3a
+#define ST_LSM6DSX_FIFO_DIFF_MASK GENMASK(11, 0)
+#define ST_LSM6DSX_FIFO_EMPTY_MASK BIT(12)
+#define ST_LSM6DSX_REG_FIFO_OUTL_ADDR 0x3e
+
+#define ST_LSM6DSX_MAX_FIFO_ODR_VAL 0x08
+
+struct st_lsm6dsx_decimator_entry {
+ u8 decimator;
+ u8 val;
+};
+
+static const
+struct st_lsm6dsx_decimator_entry st_lsm6dsx_decimator_table[] = {
+ { 0, 0x0 },
+ { 1, 0x1 },
+ { 2, 0x2 },
+ { 3, 0x3 },
+ { 4, 0x4 },
+ { 8, 0x5 },
+ { 16, 0x6 },
+ { 32, 0x7 },
+};
+
+static int st_lsm6dsx_get_decimator_val(u8 val)
+{
+ const int max_size = ARRAY_SIZE(st_lsm6dsx_decimator_table);
+ int i;
+
+ for (i = 0; i < max_size; i++)
+ if (st_lsm6dsx_decimator_table[i].decimator == val)
+ break;
+
+ return i == max_size ? 0 : st_lsm6dsx_decimator_table[i].val;
+}
+
+static void st_lsm6dsx_get_max_min_odr(struct st_lsm6dsx_hw *hw,
+ u16 *max_odr, u16 *min_odr)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ int i;
+
+ *max_odr = 0, *min_odr = ~0;
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ if (!(hw->enable_mask & BIT(sensor->id)))
+ continue;
+
+ *max_odr = max_t(u16, *max_odr, sensor->odr);
+ *min_odr = min_t(u16, *min_odr, sensor->odr);
+ }
+}
+
+static int st_lsm6dsx_update_decimators(struct st_lsm6dsx_hw *hw)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ u16 max_odr, min_odr, sip = 0;
+ int err, i;
+ u8 data;
+
+ st_lsm6dsx_get_max_min_odr(hw, &max_odr, &min_odr);
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ /* update fifo decimators and sample in pattern */
+ if (hw->enable_mask & BIT(sensor->id)) {
+ sensor->sip = sensor->odr / min_odr;
+ sensor->decimator = max_odr / sensor->odr;
+ data = st_lsm6dsx_get_decimator_val(sensor->decimator);
+ } else {
+ sensor->sip = 0;
+ sensor->decimator = 0;
+ data = 0;
+ }
+
+ err = st_lsm6dsx_write_with_mask(hw,
+ ST_LSM6DSX_REG_FIFO_DEC_GXL_ADDR,
+ sensor->decimator_mask, data);
+ if (err < 0)
+ return err;
+
+ sip += sensor->sip;
+ }
+ hw->sip = sip;
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_fifo_mode(struct st_lsm6dsx_hw *hw,
+ enum st_lsm6dsx_fifo_mode fifo_mode)
+{
+ u8 data;
+ int err;
+
+ switch (fifo_mode) {
+ case ST_LSM6DSX_FIFO_BYPASS:
+ data = fifo_mode;
+ break;
+ case ST_LSM6DSX_FIFO_CONT:
+ data = (ST_LSM6DSX_MAX_FIFO_ODR_VAL <<
+ __ffs(ST_LSM6DSX_FIFO_ODR_MASK)) | fifo_mode;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_MODE_ADDR,
+ sizeof(data), &data);
+ if (err < 0)
+ return err;
+
+ hw->fifo_mode = fifo_mode;
+
+ return 0;
+}
+
+int st_lsm6dsx_update_watermark(struct st_lsm6dsx_sensor *sensor, u16 watermark)
+{
+ u16 fifo_watermark = ~0, cur_watermark, sip = 0;
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ struct st_lsm6dsx_sensor *cur_sensor;
+ __le16 wdata;
+ int i, err;
+ u8 data;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ cur_sensor = iio_priv(hw->iio_devs[i]);
+
+ if (!(hw->enable_mask & BIT(cur_sensor->id)))
+ continue;
+
+ cur_watermark = (cur_sensor == sensor) ? watermark
+ : cur_sensor->watermark;
+
+ fifo_watermark = min_t(u16, fifo_watermark, cur_watermark);
+ sip += cur_sensor->sip;
+ }
+
+ if (!sip)
+ return 0;
+
+ fifo_watermark = max_t(u16, fifo_watermark, sip);
+ fifo_watermark = (fifo_watermark / sip) * sip;
+ fifo_watermark = fifo_watermark * ST_LSM6DSX_SAMPLE_DEPTH;
+
+ mutex_lock(&hw->lock);
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_THH_ADDR,
+ sizeof(data), &data);
+ if (err < 0)
+ goto out;
+
+ fifo_watermark = ((data & ~ST_LSM6DSX_FIFO_TH_MASK) << 8) |
+ (fifo_watermark & ST_LSM6DSX_FIFO_TH_MASK);
+
+ wdata = cpu_to_le16(fifo_watermark);
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_FIFO_THL_ADDR,
+ sizeof(wdata), (u8 *)&wdata);
+out:
+ mutex_unlock(&hw->lock);
+
+ return err < 0 ? err : 0;
+}
+
+/**
+ * st_lsm6dsx_read_fifo() - LSM6DS3-LSM6DSM read FIFO routine
+ * @hw: Pointer to instance of struct st_lsm6dsx_hw.
+ *
+ * Read samples from the hw FIFO and push them to IIO buffers.
+ *
+ * Return: Number of bytes read from the FIFO
+ */
+static int st_lsm6dsx_read_fifo(struct st_lsm6dsx_hw *hw)
+{
+ u8 buff[ALIGN(ST_LSM6DSX_SAMPLE_SIZE, sizeof(s64)) + sizeof(s64)];
+ u16 fifo_len, pattern_len = hw->sip * ST_LSM6DSX_SAMPLE_SIZE;
+ struct st_lsm6dsx_sensor *acc_sensor, *gyro_sensor;
+ s64 acc_ts, acc_delta_ts, gyro_ts, gyro_delta_ts;
+ int err, acc_sip, gyro_sip, read_len, samples;
+ __le16 fifo_status;
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_FIFO_DIFFL_ADDR,
+ sizeof(fifo_status), (u8 *)&fifo_status);
+ if (err < 0)
+ return err;
+
+ if (fifo_status & cpu_to_le16(ST_LSM6DSX_FIFO_EMPTY_MASK))
+ return 0;
+
+ fifo_len = (le16_to_cpu(fifo_status) & ST_LSM6DSX_FIFO_DIFF_MASK) *
+ ST_LSM6DSX_CHAN_SIZE;
+ samples = fifo_len / ST_LSM6DSX_SAMPLE_SIZE;
+ fifo_len = (fifo_len / pattern_len) * pattern_len;
+
+ /*
+ * compute delta timestamp between two consecutive samples
+ * in order to estimate queueing time of data generated
+ * by the sensor
+ */
+ acc_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_ACC]);
+ acc_ts = acc_sensor->ts - acc_sensor->delta_ts;
+ acc_delta_ts = div_s64(acc_sensor->delta_ts * acc_sensor->decimator,
+ samples);
+
+ gyro_sensor = iio_priv(hw->iio_devs[ST_LSM6DSX_ID_GYRO]);
+ gyro_ts = gyro_sensor->ts - gyro_sensor->delta_ts;
+ gyro_delta_ts = div_s64(gyro_sensor->delta_ts * gyro_sensor->decimator,
+ samples);
+
+ for (read_len = 0; read_len < fifo_len; read_len += pattern_len) {
+ gyro_sip = gyro_sensor->sip;
+ acc_sip = acc_sensor->sip;
+
+ while (acc_sip > 0 || gyro_sip > 0) {
+ if (gyro_sip-- > 0) {
+ err = hw->tf->read(hw->dev,
+ ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
+ ST_LSM6DSX_SAMPLE_SIZE, buff);
+ if (err < 0)
+ return err;
+
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_GYRO],
+ buff, gyro_ts);
+ gyro_ts += gyro_delta_ts;
+ }
+
+ if (acc_sip-- > 0) {
+ err = hw->tf->read(hw->dev,
+ ST_LSM6DSX_REG_FIFO_OUTL_ADDR,
+ ST_LSM6DSX_SAMPLE_SIZE, buff);
+ if (err < 0)
+ return err;
+
+ iio_push_to_buffers_with_timestamp(
+ hw->iio_devs[ST_LSM6DSX_ID_ACC],
+ buff, acc_ts);
+ acc_ts += acc_delta_ts;
+ }
+ }
+ }
+
+ return read_len;
+}
+
+static int st_lsm6dsx_flush_fifo(struct st_lsm6dsx_hw *hw)
+{
+ int err;
+
+ mutex_lock(&hw->fifo_lock);
+
+ st_lsm6dsx_read_fifo(hw);
+ err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_BYPASS);
+
+ mutex_unlock(&hw->fifo_lock);
+
+ return err;
+}
+
+static int st_lsm6dsx_update_fifo(struct iio_dev *iio_dev, bool enable)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err;
+
+ if (hw->fifo_mode != ST_LSM6DSX_FIFO_BYPASS) {
+ err = st_lsm6dsx_flush_fifo(hw);
+ if (err < 0)
+ return err;
+ }
+
+ if (enable) {
+ err = st_lsm6dsx_sensor_enable(sensor);
+ if (err < 0)
+ return err;
+ } else {
+ err = st_lsm6dsx_sensor_disable(sensor);
+ if (err < 0)
+ return err;
+ }
+
+ err = st_lsm6dsx_update_decimators(hw);
+ if (err < 0)
+ return err;
+
+ err = st_lsm6dsx_update_watermark(sensor, sensor->watermark);
+ if (err < 0)
+ return err;
+
+ if (hw->enable_mask) {
+ err = st_lsm6dsx_set_fifo_mode(hw, ST_LSM6DSX_FIFO_CONT);
+ if (err < 0)
+ return err;
+
+ /*
+ * store enable buffer timestamp as reference to compute
+ * first delta timestamp
+ */
+ sensor->ts = iio_get_time_ns(iio_dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t st_lsm6dsx_handler_irq(int irq, void *private)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
+ struct st_lsm6dsx_sensor *sensor;
+ int i;
+
+ if (!hw->sip)
+ return IRQ_NONE;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ sensor = iio_priv(hw->iio_devs[i]);
+
+ if (sensor->sip > 0) {
+ s64 timestamp;
+
+ timestamp = iio_get_time_ns(hw->iio_devs[i]);
+ sensor->delta_ts = timestamp - sensor->ts;
+ sensor->ts = timestamp;
+ }
+ }
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t st_lsm6dsx_handler_thread(int irq, void *private)
+{
+ struct st_lsm6dsx_hw *hw = (struct st_lsm6dsx_hw *)private;
+ int count;
+
+ mutex_lock(&hw->fifo_lock);
+ count = st_lsm6dsx_read_fifo(hw);
+ mutex_unlock(&hw->fifo_lock);
+
+ return !count ? IRQ_NONE : IRQ_HANDLED;
+}
+
+static int st_lsm6dsx_buffer_preenable(struct iio_dev *iio_dev)
+{
+ return st_lsm6dsx_update_fifo(iio_dev, true);
+}
+
+static int st_lsm6dsx_buffer_postdisable(struct iio_dev *iio_dev)
+{
+ return st_lsm6dsx_update_fifo(iio_dev, false);
+}
+
+static const struct iio_buffer_setup_ops st_lsm6dsx_buffer_ops = {
+ .preenable = st_lsm6dsx_buffer_preenable,
+ .postdisable = st_lsm6dsx_buffer_postdisable,
+};
+
+int st_lsm6dsx_allocate_buffers(struct st_lsm6dsx_hw *hw)
+{
+ struct iio_buffer *buffer;
+ unsigned long irq_type;
+ int i, err;
+
+ irq_type = irqd_get_trigger_type(irq_get_irq_data(hw->irq));
+
+ switch (irq_type) {
+ case IRQF_TRIGGER_HIGH:
+ case IRQF_TRIGGER_RISING:
+ break;
+ default:
+ dev_info(hw->dev, "mode %lx unsupported\n", irq_type);
+ return -EINVAL;
+ }
+
+ err = devm_request_threaded_irq(hw->dev, hw->irq,
+ st_lsm6dsx_handler_irq,
+ st_lsm6dsx_handler_thread,
+ irq_type | IRQF_ONESHOT,
+ hw->name, hw);
+ if (err) {
+ dev_err(hw->dev, "failed to request trigger irq %d\n",
+ hw->irq);
+ return err;
+ }
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ buffer = devm_iio_kfifo_allocate(hw->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(hw->iio_devs[i], buffer);
+ hw->iio_devs[i]->modes |= INDIO_BUFFER_SOFTWARE;
+ hw->iio_devs[i]->setup_ops = &st_lsm6dsx_buffer_ops;
+ }
+
+ return 0;
+}
+
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
new file mode 100644
index 0000000..473315a
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_core.c
@@ -0,0 +1,655 @@
+/*
+ * STMicroelectronics st_lsm6dsx sensor driver
+ *
+ * The ST LSM6DSx IMU MEMS series consists of 3D digital accelerometer
+ * and 3D digital gyroscope system-in-package with a digital I2C/SPI serial
+ * interface standard output.
+ * LSM6DSx IMU MEMS series has a dynamic user-selectable full-scale
+ * acceleration range of +-2/+-4/+-8/+-16 g and an angular rate range of
+ * +-125/+-245/+-500/+-1000/+-2000 dps
+ * LSM6DSx series has an integrated First-In-First-Out (FIFO) buffer
+ * allowing dynamic batching of sensor data.
+ *
+ * Supported sensors:
+ * - LSM6DS3:
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
+ * - FIFO size: 8KB
+ *
+ * - LSM6DSM:
+ * - Accelerometer/Gyroscope supported ODR [Hz]: 13, 26, 52, 104, 208, 416
+ * - Accelerometer supported full-scale [g]: +-2/+-4/+-8/+-16
+ * - Gyroscope supported full-scale [dps]: +-125/+-245/+-500/+-1000/+-2000
+ * - FIFO size: 4KB
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
+ * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#include "st_lsm6dsx.h"
+
+#define ST_LSM6DSX_REG_ACC_DEC_MASK GENMASK(2, 0)
+#define ST_LSM6DSX_REG_GYRO_DEC_MASK GENMASK(5, 3)
+#define ST_LSM6DSX_REG_INT1_ADDR 0x0d
+#define ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK BIT(3)
+#define ST_LSM6DSX_REG_WHOAMI_ADDR 0x0f
+#define ST_LSM6DSX_REG_RESET_ADDR 0x12
+#define ST_LSM6DSX_REG_RESET_MASK BIT(0)
+#define ST_LSM6DSX_REG_BDU_ADDR 0x12
+#define ST_LSM6DSX_REG_BDU_MASK BIT(6)
+#define ST_LSM6DSX_REG_INT2_ON_INT1_ADDR 0x13
+#define ST_LSM6DSX_REG_INT2_ON_INT1_MASK BIT(5)
+#define ST_LSM6DSX_REG_ROUNDING_ADDR 0x16
+#define ST_LSM6DSX_REG_ROUNDING_MASK BIT(2)
+#define ST_LSM6DSX_REG_LIR_ADDR 0x58
+#define ST_LSM6DSX_REG_LIR_MASK BIT(0)
+
+#define ST_LSM6DSX_REG_ACC_ODR_ADDR 0x10
+#define ST_LSM6DSX_REG_ACC_ODR_MASK GENMASK(7, 4)
+#define ST_LSM6DSX_REG_ACC_FS_ADDR 0x10
+#define ST_LSM6DSX_REG_ACC_FS_MASK GENMASK(3, 2)
+#define ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR 0x28
+#define ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR 0x2a
+#define ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR 0x2c
+
+#define ST_LSM6DSX_REG_GYRO_ODR_ADDR 0x11
+#define ST_LSM6DSX_REG_GYRO_ODR_MASK GENMASK(7, 4)
+#define ST_LSM6DSX_REG_GYRO_FS_ADDR 0x11
+#define ST_LSM6DSX_REG_GYRO_FS_MASK GENMASK(3, 2)
+#define ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR 0x22
+#define ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR 0x24
+#define ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR 0x26
+
+#define ST_LSM6DS3_WHOAMI 0x69
+#define ST_LSM6DSM_WHOAMI 0x6a
+
+#define ST_LSM6DS3_MAX_FIFO_SIZE 8192
+#define ST_LSM6DSM_MAX_FIFO_SIZE 4096
+
+#define ST_LSM6DSX_ACC_FS_2G_GAIN IIO_G_TO_M_S_2(61)
+#define ST_LSM6DSX_ACC_FS_4G_GAIN IIO_G_TO_M_S_2(122)
+#define ST_LSM6DSX_ACC_FS_8G_GAIN IIO_G_TO_M_S_2(244)
+#define ST_LSM6DSX_ACC_FS_16G_GAIN IIO_G_TO_M_S_2(488)
+
+#define ST_LSM6DSX_GYRO_FS_245_GAIN IIO_DEGREE_TO_RAD(4375)
+#define ST_LSM6DSX_GYRO_FS_500_GAIN IIO_DEGREE_TO_RAD(8750)
+#define ST_LSM6DSX_GYRO_FS_1000_GAIN IIO_DEGREE_TO_RAD(17500)
+#define ST_LSM6DSX_GYRO_FS_2000_GAIN IIO_DEGREE_TO_RAD(70000)
+
+struct st_lsm6dsx_odr {
+ u16 hz;
+ u8 val;
+};
+
+#define ST_LSM6DSX_ODR_LIST_SIZE 6
+struct st_lsm6dsx_odr_table_entry {
+ struct st_lsm6dsx_reg reg;
+ struct st_lsm6dsx_odr odr_avl[ST_LSM6DSX_ODR_LIST_SIZE];
+};
+
+static const struct st_lsm6dsx_odr_table_entry st_lsm6dsx_odr_table[] = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_ACC_ODR_ADDR,
+ .mask = ST_LSM6DSX_REG_ACC_ODR_MASK,
+ },
+ .odr_avl[0] = { 13, 0x01 },
+ .odr_avl[1] = { 26, 0x02 },
+ .odr_avl[2] = { 52, 0x03 },
+ .odr_avl[3] = { 104, 0x04 },
+ .odr_avl[4] = { 208, 0x05 },
+ .odr_avl[5] = { 416, 0x06 },
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_GYRO_ODR_ADDR,
+ .mask = ST_LSM6DSX_REG_GYRO_ODR_MASK,
+ },
+ .odr_avl[0] = { 13, 0x01 },
+ .odr_avl[1] = { 26, 0x02 },
+ .odr_avl[2] = { 52, 0x03 },
+ .odr_avl[3] = { 104, 0x04 },
+ .odr_avl[4] = { 208, 0x05 },
+ .odr_avl[5] = { 416, 0x06 },
+ }
+};
+
+struct st_lsm6dsx_fs {
+ u32 gain;
+ u8 val;
+};
+
+#define ST_LSM6DSX_FS_LIST_SIZE 4
+struct st_lsm6dsx_fs_table_entry {
+ struct st_lsm6dsx_reg reg;
+ struct st_lsm6dsx_fs fs_avl[ST_LSM6DSX_FS_LIST_SIZE];
+};
+
+static const struct st_lsm6dsx_fs_table_entry st_lsm6dsx_fs_table[] = {
+ [ST_LSM6DSX_ID_ACC] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_ACC_FS_ADDR,
+ .mask = ST_LSM6DSX_REG_ACC_FS_MASK,
+ },
+ .fs_avl[0] = { ST_LSM6DSX_ACC_FS_2G_GAIN, 0x0 },
+ .fs_avl[1] = { ST_LSM6DSX_ACC_FS_4G_GAIN, 0x2 },
+ .fs_avl[2] = { ST_LSM6DSX_ACC_FS_8G_GAIN, 0x3 },
+ .fs_avl[3] = { ST_LSM6DSX_ACC_FS_16G_GAIN, 0x1 },
+ },
+ [ST_LSM6DSX_ID_GYRO] = {
+ .reg = {
+ .addr = ST_LSM6DSX_REG_GYRO_FS_ADDR,
+ .mask = ST_LSM6DSX_REG_GYRO_FS_MASK,
+ },
+ .fs_avl[0] = { ST_LSM6DSX_GYRO_FS_245_GAIN, 0x0 },
+ .fs_avl[1] = { ST_LSM6DSX_GYRO_FS_500_GAIN, 0x1 },
+ .fs_avl[2] = { ST_LSM6DSX_GYRO_FS_1000_GAIN, 0x2 },
+ .fs_avl[3] = { ST_LSM6DSX_GYRO_FS_2000_GAIN, 0x3 },
+ }
+};
+
+static const struct st_lsm6dsx_settings st_lsm6dsx_sensor_settings[] = {
+ {
+ .wai = ST_LSM6DS3_WHOAMI,
+ .max_fifo_size = ST_LSM6DS3_MAX_FIFO_SIZE,
+ },
+ {
+ .wai = ST_LSM6DSM_WHOAMI,
+ .max_fifo_size = ST_LSM6DSM_MAX_FIFO_SIZE,
+ },
+};
+
+#define ST_LSM6DSX_CHANNEL(chan_type, addr, mod, scan_idx) \
+{ \
+ .type = chan_type, \
+ .address = addr, \
+ .modified = 1, \
+ .channel2 = mod, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
+ BIT(IIO_CHAN_INFO_SCALE), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = scan_idx, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec st_lsm6dsx_acc_channels[] = {
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_X_L_ADDR,
+ IIO_MOD_X, 0),
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Y_L_ADDR,
+ IIO_MOD_Y, 1),
+ ST_LSM6DSX_CHANNEL(IIO_ACCEL, ST_LSM6DSX_REG_ACC_OUT_Z_L_ADDR,
+ IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+static const struct iio_chan_spec st_lsm6dsx_gyro_channels[] = {
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_X_L_ADDR,
+ IIO_MOD_X, 0),
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Y_L_ADDR,
+ IIO_MOD_Y, 1),
+ ST_LSM6DSX_CHANNEL(IIO_ANGL_VEL, ST_LSM6DSX_REG_GYRO_OUT_Z_L_ADDR,
+ IIO_MOD_Z, 2),
+ IIO_CHAN_SOFT_TIMESTAMP(3),
+};
+
+int st_lsm6dsx_write_with_mask(struct st_lsm6dsx_hw *hw, u8 addr, u8 mask,
+ u8 val)
+{
+ u8 data;
+ int err;
+
+ mutex_lock(&hw->lock);
+
+ err = hw->tf->read(hw->dev, addr, sizeof(data), &data);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to read %02x register\n", addr);
+ goto out;
+ }
+
+ data = (data & ~mask) | ((val << __ffs(mask)) & mask);
+
+ err = hw->tf->write(hw->dev, addr, sizeof(data), &data);
+ if (err < 0)
+ dev_err(hw->dev, "failed to write %02x register\n", addr);
+
+out:
+ mutex_unlock(&hw->lock);
+
+ return err;
+}
+
+static int st_lsm6dsx_check_whoami(struct st_lsm6dsx_hw *hw)
+{
+ int err, i;
+ u8 data;
+
+ err = hw->tf->read(hw->dev, ST_LSM6DSX_REG_WHOAMI_ADDR, sizeof(data),
+ &data);
+ if (err < 0) {
+ dev_err(hw->dev, "failed to read whoami register\n");
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(st_lsm6dsx_sensor_settings); i++) {
+ if (data == st_lsm6dsx_sensor_settings[i].wai) {
+ hw->settings = &st_lsm6dsx_sensor_settings[i];
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(st_lsm6dsx_sensor_settings)) {
+ dev_err(hw->dev, "unsupported whoami [%02x]\n", data);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_full_scale(struct st_lsm6dsx_sensor *sensor,
+ u32 gain)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, err;
+ u8 val;
+
+ for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
+ if (st_lsm6dsx_fs_table[id].fs_avl[i].gain == gain)
+ break;
+
+ if (i == ST_LSM6DSX_FS_LIST_SIZE)
+ return -EINVAL;
+
+ val = st_lsm6dsx_fs_table[id].fs_avl[i].val;
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_fs_table[id].reg.addr,
+ st_lsm6dsx_fs_table[id].reg.mask,
+ val);
+ if (err < 0)
+ return err;
+
+ sensor->gain = gain;
+
+ return 0;
+}
+
+static int st_lsm6dsx_set_odr(struct st_lsm6dsx_sensor *sensor, u16 odr)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, err;
+ u8 val;
+
+ for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
+ if (st_lsm6dsx_odr_table[id].odr_avl[i].hz == odr)
+ break;
+
+ if (i == ST_LSM6DSX_ODR_LIST_SIZE)
+ return -EINVAL;
+
+ val = st_lsm6dsx_odr_table[id].odr_avl[i].val;
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_odr_table[id].reg.addr,
+ st_lsm6dsx_odr_table[id].reg.mask,
+ val);
+ if (err < 0)
+ return err;
+
+ sensor->odr = odr;
+
+ return 0;
+}
+
+int st_lsm6dsx_sensor_enable(struct st_lsm6dsx_sensor *sensor)
+{
+ int err;
+
+ err = st_lsm6dsx_set_odr(sensor, sensor->odr);
+ if (err < 0)
+ return err;
+
+ sensor->hw->enable_mask |= BIT(sensor->id);
+
+ return 0;
+}
+
+int st_lsm6dsx_sensor_disable(struct st_lsm6dsx_sensor *sensor)
+{
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int err;
+
+ err = st_lsm6dsx_write_with_mask(sensor->hw,
+ st_lsm6dsx_odr_table[id].reg.addr,
+ st_lsm6dsx_odr_table[id].reg.mask, 0);
+ if (err < 0)
+ return err;
+
+ sensor->hw->enable_mask &= ~BIT(id);
+
+ return 0;
+}
+
+static int st_lsm6dsx_read_oneshot(struct st_lsm6dsx_sensor *sensor,
+ u8 addr, int *val)
+{
+ int err, delay;
+ __le16 data;
+
+ err = st_lsm6dsx_sensor_enable(sensor);
+ if (err < 0)
+ return err;
+
+ delay = 1000000 / sensor->odr;
+ usleep_range(delay, 2 * delay);
+
+ err = sensor->hw->tf->read(sensor->hw->dev, addr, sizeof(data),
+ (u8 *)&data);
+ if (err < 0)
+ return err;
+
+ st_lsm6dsx_sensor_disable(sensor);
+
+ *val = (s16)data;
+
+ return IIO_VAL_INT;
+}
+
+static int st_lsm6dsx_read_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *ch,
+ int *val, int *val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ int ret;
+
+ ret = iio_device_claim_direct_mode(iio_dev);
+ if (ret)
+ return ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ ret = st_lsm6dsx_read_oneshot(sensor, ch->address, val);
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ *val = sensor->odr;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = sensor->gain;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ iio_device_release_direct_mode(iio_dev);
+
+ return ret;
+}
+
+static int st_lsm6dsx_write_raw(struct iio_dev *iio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ int err;
+
+ err = iio_device_claim_direct_mode(iio_dev);
+ if (err)
+ return err;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SCALE:
+ err = st_lsm6dsx_set_full_scale(sensor, val2);
+ break;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ err = st_lsm6dsx_set_odr(sensor, val);
+ break;
+ default:
+ err = -EINVAL;
+ break;
+ }
+
+ iio_device_release_direct_mode(iio_dev);
+
+ return err;
+}
+
+static int st_lsm6dsx_set_watermark(struct iio_dev *iio_dev, unsigned int val)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(iio_dev);
+ struct st_lsm6dsx_hw *hw = sensor->hw;
+ int err, max_fifo_len;
+
+ max_fifo_len = hw->settings->max_fifo_size / ST_LSM6DSX_SAMPLE_SIZE;
+ if (val < 1 || val > max_fifo_len)
+ return -EINVAL;
+
+ err = st_lsm6dsx_update_watermark(sensor, val);
+ if (err < 0)
+ return err;
+
+ sensor->watermark = val;
+
+ return 0;
+}
+
+static ssize_t
+st_lsm6dsx_sysfs_sampling_frequency_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, len = 0;
+
+ for (i = 0; i < ST_LSM6DSX_ODR_LIST_SIZE; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%d ",
+ st_lsm6dsx_odr_table[id].odr_avl[i].hz);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static ssize_t st_lsm6dsx_sysfs_scale_avail(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct st_lsm6dsx_sensor *sensor = iio_priv(dev_get_drvdata(dev));
+ enum st_lsm6dsx_sensor_id id = sensor->id;
+ int i, len = 0;
+
+ for (i = 0; i < ST_LSM6DSX_FS_LIST_SIZE; i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "0.%06u ",
+ st_lsm6dsx_fs_table[id].fs_avl[i].gain);
+ buf[len - 1] = '\n';
+
+ return len;
+}
+
+static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(st_lsm6dsx_sysfs_sampling_frequency_avail);
+static IIO_DEVICE_ATTR(in_accel_scale_available, 0444,
+ st_lsm6dsx_sysfs_scale_avail, NULL, 0);
+static IIO_DEVICE_ATTR(in_anglvel_scale_available, 0444,
+ st_lsm6dsx_sysfs_scale_avail, NULL, 0);
+
+static struct attribute *st_lsm6dsx_acc_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_accel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_lsm6dsx_acc_attribute_group = {
+ .attrs = st_lsm6dsx_acc_attributes,
+};
+
+static const struct iio_info st_lsm6dsx_acc_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_lsm6dsx_acc_attribute_group,
+ .read_raw = st_lsm6dsx_read_raw,
+ .write_raw = st_lsm6dsx_write_raw,
+ .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+static struct attribute *st_lsm6dsx_gyro_attributes[] = {
+ &iio_dev_attr_sampling_frequency_available.dev_attr.attr,
+ &iio_dev_attr_in_anglvel_scale_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group st_lsm6dsx_gyro_attribute_group = {
+ .attrs = st_lsm6dsx_gyro_attributes,
+};
+
+static const struct iio_info st_lsm6dsx_gyro_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &st_lsm6dsx_gyro_attribute_group,
+ .read_raw = st_lsm6dsx_read_raw,
+ .write_raw = st_lsm6dsx_write_raw,
+ .hwfifo_set_watermark = st_lsm6dsx_set_watermark,
+};
+
+static const unsigned long st_lsm6dsx_available_scan_masks[] = {0x7, 0x0};
+
+static int st_lsm6dsx_init_device(struct st_lsm6dsx_hw *hw)
+{
+ int err;
+ u8 data;
+
+ data = ST_LSM6DSX_REG_RESET_MASK;
+ err = hw->tf->write(hw->dev, ST_LSM6DSX_REG_RESET_ADDR, sizeof(data),
+ &data);
+ if (err < 0)
+ return err;
+
+ msleep(200);
+
+ /* latch interrupts */
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_LIR_ADDR,
+ ST_LSM6DSX_REG_LIR_MASK, 1);
+ if (err < 0)
+ return err;
+
+ /* enable Block Data Update */
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_BDU_ADDR,
+ ST_LSM6DSX_REG_BDU_MASK, 1);
+ if (err < 0)
+ return err;
+
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_ROUNDING_ADDR,
+ ST_LSM6DSX_REG_ROUNDING_MASK, 1);
+ if (err < 0)
+ return err;
+
+ /* enable FIFO watermak interrupt */
+ err = st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_INT1_ADDR,
+ ST_LSM6DSX_REG_FIFO_FTH_IRQ_MASK, 1);
+ if (err < 0)
+ return err;
+
+ /* redirect INT2 on INT1 */
+ return st_lsm6dsx_write_with_mask(hw, ST_LSM6DSX_REG_INT2_ON_INT1_ADDR,
+ ST_LSM6DSX_REG_INT2_ON_INT1_MASK, 1);
+}
+
+static struct iio_dev *st_lsm6dsx_alloc_iiodev(struct st_lsm6dsx_hw *hw,
+ enum st_lsm6dsx_sensor_id id)
+{
+ struct st_lsm6dsx_sensor *sensor;
+ struct iio_dev *iio_dev;
+
+ iio_dev = devm_iio_device_alloc(hw->dev, sizeof(*sensor));
+ if (!iio_dev)
+ return NULL;
+
+ iio_dev->modes = INDIO_DIRECT_MODE;
+ iio_dev->dev.parent = hw->dev;
+ iio_dev->available_scan_masks = st_lsm6dsx_available_scan_masks;
+
+ sensor = iio_priv(iio_dev);
+ sensor->id = id;
+ sensor->hw = hw;
+ sensor->odr = st_lsm6dsx_odr_table[id].odr_avl[0].hz;
+ sensor->gain = st_lsm6dsx_fs_table[id].fs_avl[0].gain;
+ sensor->watermark = 1;
+
+ switch (id) {
+ case ST_LSM6DSX_ID_ACC:
+ iio_dev->channels = st_lsm6dsx_acc_channels;
+ iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_acc_channels);
+ iio_dev->name = "lsm6dsx_accel";
+ iio_dev->info = &st_lsm6dsx_acc_info;
+
+ sensor->decimator_mask = ST_LSM6DSX_REG_ACC_DEC_MASK;
+ break;
+ case ST_LSM6DSX_ID_GYRO:
+ iio_dev->channels = st_lsm6dsx_gyro_channels;
+ iio_dev->num_channels = ARRAY_SIZE(st_lsm6dsx_gyro_channels);
+ iio_dev->name = "lsm6dsx_gyro";
+ iio_dev->info = &st_lsm6dsx_gyro_info;
+
+ sensor->decimator_mask = ST_LSM6DSX_REG_GYRO_DEC_MASK;
+ break;
+ default:
+ return NULL;
+ }
+
+ return iio_dev;
+}
+
+int st_lsm6dsx_probe(struct st_lsm6dsx_hw *hw)
+{
+ int i, err;
+
+ mutex_init(&hw->lock);
+ mutex_init(&hw->fifo_lock);
+
+ err = st_lsm6dsx_check_whoami(hw);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ hw->iio_devs[i] = st_lsm6dsx_alloc_iiodev(hw, i);
+ if (!hw->iio_devs[i])
+ return -ENOMEM;
+ }
+
+ err = st_lsm6dsx_init_device(hw);
+ if (err < 0)
+ return err;
+
+ if (hw->irq > 0) {
+ err = st_lsm6dsx_allocate_buffers(hw);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ST_LSM6DSX_ID_MAX; i++) {
+ err = devm_iio_device_register(hw->dev, hw->iio_devs[i]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(st_lsm6dsx_probe);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
new file mode 100644
index 0000000..cb9a158
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_i2c.c
@@ -0,0 +1,88 @@
+/*
+ * STMicroelectronics st_lsm6dsx i2c driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
+ * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_lsm6dsx.h"
+
+static int st_lsm6dsx_i2c_read(struct device *dev, u8 addr, int len, u8 *data)
+{
+ return i2c_smbus_read_i2c_block_data_or_emulated(to_i2c_client(dev),
+ addr, len, data);
+}
+
+static int st_lsm6dsx_i2c_write(struct device *dev, u8 addr, int len, u8 *data)
+{
+ return i2c_smbus_write_i2c_block_data(to_i2c_client(dev), addr,
+ len, data);
+}
+
+static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
+ .read = st_lsm6dsx_i2c_read,
+ .write = st_lsm6dsx_i2c_write,
+};
+
+static int st_lsm6dsx_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct st_lsm6dsx_hw *hw;
+
+ hw = devm_kzalloc(&client->dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, hw);
+ hw->name = client->name;
+ hw->dev = &client->dev;
+ hw->irq = client->irq;
+ hw->tf = &st_lsm6dsx_transfer_fn;
+
+ return st_lsm6dsx_probe(hw);
+}
+
+static const struct of_device_id st_lsm6dsx_i2c_of_match[] = {
+ {
+ .compatible = "st,lsm6ds3",
+ .data = ST_LSM6DS3_DEV_NAME,
+ },
+ {
+ .compatible = "st,lsm6dsm",
+ .data = ST_LSM6DSM_DEV_NAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_lsm6dsx_i2c_of_match);
+
+static const struct i2c_device_id st_lsm6dsx_i2c_id_table[] = {
+ { ST_LSM6DS3_DEV_NAME },
+ { ST_LSM6DSM_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, st_lsm6dsx_i2c_id_table);
+
+static struct i2c_driver st_lsm6dsx_driver = {
+ .driver = {
+ .name = "st_lsm6dsx_i2c",
+ .of_match_table = of_match_ptr(st_lsm6dsx_i2c_of_match),
+ },
+ .probe = st_lsm6dsx_i2c_probe,
+ .id_table = st_lsm6dsx_i2c_id_table,
+};
+module_i2c_driver(st_lsm6dsx_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx i2c driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
new file mode 100644
index 0000000..f16eab5
--- /dev/null
+++ b/drivers/iio/imu/st_lsm6dsx/st_lsm6dsx_spi.c
@@ -0,0 +1,126 @@
+/*
+ * STMicroelectronics st_lsm6dsx spi driver
+ *
+ * Copyright 2016 STMicroelectronics Inc.
+ *
+ * Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
+ * Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>
+ *
+ * Licensed under the GPL-2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/spi/spi.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+
+#include "st_lsm6dsx.h"
+
+#define SENSORS_SPI_READ BIT(7)
+
+static int st_lsm6dsx_spi_read(struct device *dev, u8 addr, int len,
+ u8 *data)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ struct st_lsm6dsx_hw *hw = spi_get_drvdata(spi);
+ int err;
+
+ struct spi_transfer xfers[] = {
+ {
+ .tx_buf = hw->tb.tx_buf,
+ .bits_per_word = 8,
+ .len = 1,
+ },
+ {
+ .rx_buf = hw->tb.rx_buf,
+ .bits_per_word = 8,
+ .len = len,
+ }
+ };
+
+ hw->tb.tx_buf[0] = addr | SENSORS_SPI_READ;
+
+ err = spi_sync_transfer(spi, xfers, ARRAY_SIZE(xfers));
+ if (err < 0)
+ return err;
+
+ memcpy(data, hw->tb.rx_buf, len * sizeof(u8));
+
+ return len;
+}
+
+static int st_lsm6dsx_spi_write(struct device *dev, u8 addr, int len,
+ u8 *data)
+{
+ struct st_lsm6dsx_hw *hw;
+ struct spi_device *spi;
+
+ if (len >= ST_LSM6DSX_TX_MAX_LENGTH)
+ return -ENOMEM;
+
+ spi = to_spi_device(dev);
+ hw = spi_get_drvdata(spi);
+
+ hw->tb.tx_buf[0] = addr;
+ memcpy(&hw->tb.tx_buf[1], data, len);
+
+ return spi_write(spi, hw->tb.tx_buf, len + 1);
+}
+
+static const struct st_lsm6dsx_transfer_function st_lsm6dsx_transfer_fn = {
+ .read = st_lsm6dsx_spi_read,
+ .write = st_lsm6dsx_spi_write,
+};
+
+static int st_lsm6dsx_spi_probe(struct spi_device *spi)
+{
+ struct st_lsm6dsx_hw *hw;
+
+ hw = devm_kzalloc(&spi->dev, sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+
+ spi_set_drvdata(spi, hw);
+ hw->name = spi->modalias;
+ hw->dev = &spi->dev;
+ hw->irq = spi->irq;
+ hw->tf = &st_lsm6dsx_transfer_fn;
+
+ return st_lsm6dsx_probe(hw);
+}
+
+static const struct of_device_id st_lsm6dsx_spi_of_match[] = {
+ {
+ .compatible = "st,lsm6ds3",
+ .data = ST_LSM6DS3_DEV_NAME,
+ },
+ {
+ .compatible = "st,lsm6dsm",
+ .data = ST_LSM6DSM_DEV_NAME,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, st_lsm6dsx_spi_of_match);
+
+static const struct spi_device_id st_lsm6dsx_spi_id_table[] = {
+ { ST_LSM6DS3_DEV_NAME },
+ { ST_LSM6DSM_DEV_NAME },
+ {},
+};
+MODULE_DEVICE_TABLE(spi, st_lsm6dsx_spi_id_table);
+
+static struct spi_driver st_lsm6dsx_driver = {
+ .driver = {
+ .name = "st_lsm6dsx_spi",
+ .of_match_table = of_match_ptr(st_lsm6dsx_spi_of_match),
+ },
+ .probe = st_lsm6dsx_spi_probe,
+ .id_table = st_lsm6dsx_spi_id_table,
+};
+module_spi_driver(st_lsm6dsx_driver);
+
+MODULE_AUTHOR("Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>");
+MODULE_AUTHOR("Denis Ciocca <denis.ciocca-qxv4g6HH51o@public.gmane.org>");
+MODULE_DESCRIPTION("STMicroelectronics st_lsm6dsx spi driver");
+MODULE_LICENSE("GPL v2");
--
2.9.3
^ permalink raw reply related
* [PATCH v3 2/2] Documentation: dt: iio: add st_lsm6dsx sensor device binding
From: Lorenzo Bianconi @ 2016-12-10 9:02 UTC (permalink / raw)
To: jic23-DgEjT+Ai2ygdnm+yROfE0A
Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.bianconi-qxv4g6HH51o
In-Reply-To: <20161210090218.4609-1-lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi-qxv4g6HH51o@public.gmane.org>
---
.../devicetree/bindings/iio/imu/st_lsm6dsx.txt | 24 ++++++++++++++++++++++
1 file changed, 24 insertions(+)
create mode 100644 Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
diff --git a/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
new file mode 100644
index 0000000..ed3cdac
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/imu/st_lsm6dsx.txt
@@ -0,0 +1,24 @@
+* ST_LSM6DSx driver for STM 6-axis (acc + gyro) imu Mems sensors
+
+Required properties:
+- compatible: must be one of:
+ "st,lsm6ds3"
+ "st,lsm6dsm"
+- reg: i2c address of the sensor / spi cs line
+
+Optional properties:
+- interrupt-parent: should be the phandle for the interrupt controller
+- interrupts: interrupt mapping for IRQ. It should be configured with
+ flags IRQ_TYPE_LEVEL_HIGH or IRQ_TYPE_EDGE_RISING.
+
+ Refer to interrupt-controller/interrupts.txt for generic interrupt
+ client node bindings.
+
+Example:
+
+lsm6dsm@6b {
+ compatible = "st,lsm6dsm";
+ reg = <0x6b>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <0 IRQ_TYPE_EDGE_RISING>;
+};
--
2.9.3
^ permalink raw reply related
* Re: [PATCH v3 3/5] mtd: aspeed: used a label property
From: Cédric Le Goater @ 2016-12-10 17:16 UTC (permalink / raw)
To: Marek Vasut, linux-mtd
Cc: Mark Rutland, Boris Brezillon, devicetree, Richard Weinberger,
Rob Herring, Joel Stanley, Cyrille Pitchen, Brian Norris,
David Woodhouse
In-Reply-To: <6bc350c3-b162-dc10-4cd3-c32f9a3d4eaf@gmail.com>
On 12/10/2016 05:03 AM, Marek Vasut wrote:
> On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
>> This can be used to easily identify a chip on a system with multiple
>> chips.
>
> I don't think I understand what this patch does.
> It seems to me like this one should be wrapped into 1/5.
Yes, but this is to open the discussion on the change required in the
jedec,spi-nor binding.
C.
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>> drivers/mtd/spi-nor/aspeed-smc.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
>> index 99302b0d7786..9119c0ca86b6 100644
>> --- a/drivers/mtd/spi-nor/aspeed-smc.c
>> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
>> @@ -676,6 +676,8 @@ static int aspeed_smc_setup_flash(struct aspeed_smc_controller *controller,
>> nor->prepare = aspeed_smc_prep;
>> nor->unprepare = aspeed_smc_unprep;
>>
>> + mtd->name = of_get_property(child, "label", NULL);
>> +
>> ret = aspeed_smc_chip_setup_init(chip, r);
>> if (ret)
>> break;
>>
>
>
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply
* Re: [PATCH v3 2/5] mtd: aspeed: add memory controllers for the Aspeed AST2400 SoC
From: Cédric Le Goater @ 2016-12-10 17:18 UTC (permalink / raw)
To: Marek Vasut, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <076683ea-fa94-2284-f269-2fcebd793940-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On 12/10/2016 05:03 AM, Marek Vasut wrote:
>> +/*
>> + * The AST2400 SPI flash controller does not have a CE Control
>> + * register. It uses the CE0 control register to set 4Byte mode at the
>> + * controller level.
>> + */
>> +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip)
>> +{
>> + chip->ctl_val[smc_base] |= CONTROL_IO_ADDRESS_4B;
>> + chip->ctl_val[smc_read] |= CONTROL_IO_ADDRESS_4B;
> How do you know the SPI NOR is in 4B mode ?
in aspeed_smc_chip_setup_finish() :
if (chip->nor.addr_width == 4 && info->set_4b)
info->set_4b(chip);
C.
>> +}
>> +
>> static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
>> struct resource *res)
>> {
>>
--
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
* Re: [PATCH v3 2/5] mtd: aspeed: add memory controllers for the Aspeed AST2400 SoC
From: Marek Vasut @ 2016-12-10 17:30 UTC (permalink / raw)
To: Cédric Le Goater, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <30a50d6d-07c5-0ca6-2d1b-3ba46c10da49-Bxea+6Xhats@public.gmane.org>
On 12/10/2016 06:18 PM, Cédric Le Goater wrote:
> On 12/10/2016 05:03 AM, Marek Vasut wrote:
>>> +/*
>>> + * The AST2400 SPI flash controller does not have a CE Control
>>> + * register. It uses the CE0 control register to set 4Byte mode at the
>>> + * controller level.
>>> + */
>>> +static void aspeed_smc_chip_set_4b_spi_2400(struct aspeed_smc_chip *chip)
>>> +{
>>> + chip->ctl_val[smc_base] |= CONTROL_IO_ADDRESS_4B;
>>> + chip->ctl_val[smc_read] |= CONTROL_IO_ADDRESS_4B;
>> How do you know the SPI NOR is in 4B mode ?
>
> in aspeed_smc_chip_setup_finish() :
>
> if (chip->nor.addr_width == 4 && info->set_4b)
> info->set_4b(chip);
>
Ahhh, great :)
--
Best regards,
Marek Vasut
--
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
* Re: [PATCH v3 1/5] mtd: spi-nor: add memory controllers for the Aspeed AST2500 SoC
From: Cédric Le Goater @ 2016-12-10 17:34 UTC (permalink / raw)
To: Marek Vasut, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <68aa03be-8195-1824-a9e1-609a5ad74381-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Hello,
On 12/10/2016 05:01 AM, Marek Vasut wrote:
> On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
>
> [...]
>
>
>> +static int aspeed_smc_read_from_ahb(void *buf, const void __iomem *src,
>> + size_t len)
>> +{
>> + if (IS_ALIGNED((u32)src, sizeof(u32)) &&
>> + IS_ALIGNED((u32)buf, sizeof(u32)) &&
>> + IS_ALIGNED(len, sizeof(u32))) {
>
> Did you try compiling this on any 64bit system ?
I cross compile the kernel on a 64bit host and then upload on the
target. What kind of problem are you forseeing ?
>
>> + while (len > 3) {
>> + *(u32 *)buf = readl(src);
>
> ioread32_rep() to avoid open-coding the loop .
ok.
>> + buf += 4;
>> + src += 4;
>> + len -= 4;
>> + }
>> + }
>> +
>> + while (len--) {
>> + *(u8 *)buf = readb(src);
>> + buf += 1;
>> + src += 1;
>> + }
>> + return 0;
>> +}
>> +
>> +static int aspeed_smc_write_to_ahb(void __iomem *dst, const void *buf,
>> + size_t len)
>> +{
>> + if (IS_ALIGNED((u32)dst, sizeof(u32)) &&
>> + IS_ALIGNED((u32)buf, sizeof(u32)) &&
>> + IS_ALIGNED(len, sizeof(u32))) {
>> + while (len > 3) {
>> + u32 val = *(u32 *)buf;
>> +
>> + writel(val, dst);
>
> iowrite32_rep()
>
>> + buf += 4;
>> + dst += 4;
>> + len -= 4;
>> + }
>> + }
>> +
>> + while (len--) {
>> + u8 val = *(u8 *)buf;
>> +
>> + writeb(val, dst);
>> + buf += 1;
>> + dst += 1;
>> + }
>> + return 0;
>> +}
>> +
>> +/*
>> + * The driver only support SPI flash
>> + */
>> +enum aspeed_smc_flash_type {
>> + smc_type_nor = 0,
>> + smc_type_nand = 1,
>> + smc_type_spi = 2,
>> +};
>> +
>> +struct aspeed_smc_chip;
>> +
>> +struct aspeed_smc_info {
>> + u32 maxsize; /* maximum size of chip window */
>> + u8 nce; /* number of chip enables */
>> + bool hastype; /* flash type field exists in config reg */
>> + u8 we0; /* shift for write enable bit for CE0 */
>> + u8 ctl0; /* offset in regs of ctl for CE0 */
>> +
>> + void (*set_4b)(struct aspeed_smc_chip *chip);
>> +};
>
> Move all the structs to the beginning of the driver please.
ok.
>
>> +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
>> +
>> +static const struct aspeed_smc_info fmc_2500_info = {
>> + .maxsize = 256 * 1024 * 1024,
>> + .nce = 3,
>> + .hastype = true,
>> + .we0 = 16,
>> + .ctl0 = 0x10,
>> + .set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +static const struct aspeed_smc_info spi_2500_info = {
>> + .maxsize = 128 * 1024 * 1024,
>> + .nce = 2,
>> + .hastype = false,
>> + .we0 = 16,
>> + .ctl0 = 0x10,
>> + .set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +enum aspeed_smc_ctl_reg_value {
>> + smc_base, /* base value without mode for other commands */
>> + smc_read, /* command reg for (maybe fast) reads */
>> + smc_write, /* command reg for writes */
>> + smc_max,
>> +};
>
> [...]
>
>> +#define CONTROL_CE_STOP_ACTIVE_CONTROL BIT(2)
>> +#define CONTROL_COMMAND_MODE_MASK GENMASK(1, 0)
>> +#define CONTROL_COMMAND_MODE_NORMAL (0)
>> +#define CONTROL_COMMAND_MODE_FREAD (1)
>> +#define CONTROL_COMMAND_MODE_WRITE (2)
>> +#define CONTROL_COMMAND_MODE_USER (3)
>
> Drop the parenthesis around constants :)
yeah
>> +#define CONTROL_KEEP_MASK \
>> + (CONTROL_AAF_MODE | CONTROL_CE_INACTIVE_MASK | CONTROL_CLK_DIV4 | \
>> + CONTROL_IO_DUMMY_MASK | CONTROL_CLOCK_FREQ_SEL_MASK | \
>> + CONTROL_LSB_FIRST | CONTROL_CLOCK_MODE_3)
>> +
>> +/*
>> + * Segment Address Registers. Start and end addresses are encoded
>> + * using 8MB units
>> + */
>> +#define SEGMENT_ADDR_REG0 0x30
>> +#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
>
> is that ((r) & 0xff0000) << 7 ?
>
>> +#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23)
>
> ((r) & 0xff000000) >> 1 ?
yes.
I rather keep the initial macros though, which I found easier to
understand.
The Segment Register uses a 8MB unit to encode the start address
and the end address of the mapping window of a flash SPI slave :
| byte 1 | byte 2 | byte 3 | byte 4 |
+--------+--------+--------+--------+
| end | start | 0 | 0 |
>> +static inline u32 aspeed_smc_chip_write_bit(struct aspeed_smc_chip *chip)
>> +{
>> + return BIT(chip->controller->info->we0 + chip->cs);
>> +}
>
> [...]
>
>> +static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
>> + struct resource *res)
>> +{
>> + struct aspeed_smc_controller *controller = chip->controller;
>> + const struct aspeed_smc_info *info = controller->info;
>> + u32 reg, base_reg;
>> +
>> + /*
>> + * Always turn on the write enable bit to allow opcodes to be
>> + * sent in user mode.
>> + */
>> + aspeed_smc_chip_enable_write(chip);
>> +
>> + /* The driver only supports SPI type flash */
>> + if (info->hastype)
>> + aspeed_smc_chip_set_type(chip, smc_type_spi);
>> +
>> + /*
>> + * Configure chip base address in memory
>> + */
>> + chip->ahb_base = aspeed_smc_chip_base(chip, res);
>> + if (!chip->ahb_base) {
>> + dev_warn(chip->nor.dev, "CE segment window closed.\n");
>> + return -1;
>
> return -EINVAL ? Check whether you always use errno.h macros in returns.
ah yes. I missed that one.
>
>> + }
>> +
>> + /*
>> + * Get value of the inherited control register. U-Boot usually
>> + * does some timing calibration on the FMC chip, so it's good
>> + * to keep them. In the future, we should handle calibration
>> + * from Linux.
>> + */
>> + reg = readl(chip->ctl);
>> + dev_dbg(controller->dev, "control register: %08x\n", reg);
>> +
>> + base_reg = reg & CONTROL_KEEP_MASK;
>> + if (base_reg != reg) {
>> + dev_info(controller->dev,
>> + "control register changed to: %08x\n",
>> + base_reg);
>> + }
>> + chip->ctl_val[smc_base] = base_reg;
>
> [...]
>
> Mostly minor nits, looks nice otherwise, thanks :)
Thanks for the review,
C.
--
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
* Re: [PATCH] iio: misc: add a generic regulator driver
From: Jonathan Cameron @ 2016-12-10 18:17 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Lars-Peter Clausen, Hartmut Knaack, Peter Meerwald-Stadler,
Rob Herring, Mark Rutland, linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-devicetree, LKML, Kevin Hilman, Patrick Titiano,
Neil Armstrong, Liam Girdwood, Mark Brown
In-Reply-To: <CAMpxmJVJ+y9tRbRBsVg+i0EJO_6EFuvrypwC=ETnBWbMnxRFyg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 06/12/16 11:12, Bartosz Golaszewski wrote:
> 2016-12-03 10:11 GMT+01:00 Jonathan Cameron <jic23-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>:
>> On 30/11/16 10:10, Lars-Peter Clausen wrote:
>>> On 11/29/2016 04:35 PM, Bartosz Golaszewski wrote:
>>>> 2016-11-29 16:30 GMT+01:00 Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>:
>>>>> On 11/29/2016 04:22 PM, Bartosz Golaszewski wrote:
>>>>> [...]
>>>>>> diff --git a/Documentation/devicetree/bindings/iio/misc/iio-regulator.txt b/Documentation/devicetree/bindings/iio/misc/iio-regulator.txt
>>>>>> new file mode 100644
>>>>>> index 0000000..147458f
>>>>>> --- /dev/null
>>>>>> +++ b/Documentation/devicetree/bindings/iio/misc/iio-regulator.txt
>>>>>> @@ -0,0 +1,18 @@
>>>>>> +Industrial IO regulator device driver
>>>>>> +-------------------------------------
>>>>>> +
>>>>>> +This document describes the bindings for the iio-regulator - a dummy device
>>>>>> +driver representing a physical regulator within the iio framework.
>>>>>
>>>>> No bindings for drivers, only for hardware. So this wont work.
>>>>>
>>>>
>>>> What about exporting regulator attributes analogous to the one in this
>>>> patch from the iio-core when a *-supply property is specified for a
>>>> node?
>>>
>>> The problem with exposing direct control to the regulator is that it allows
>>> to modify the hardware state without the drivers knowledge. If you
>>> power-cycle a device all previous configuration that has been written to the
>>> device is reset. The device driver needs to be aware of this otherwise its
>>> assumed state and the actual device state can divert which will result in
>>> undefined behavior. Also access to the device will fail unexpectedly when
>>> the regulator is turned off. So I think generally the driver should
>>> explicitly control the regulator, power-up when needed, power-down when not.
>> I agree with what Lars has said.
>>
>> There 'may' be some argument to ultimately have a bridge driver from
>> regulators to IIO. That would be for cases where the divide between a regulator
>> and a DAC is blurred. However it would still have to play nicely with the
>> regulator framework and any other devices registered on that regulator.
>> Ultimately the ideal in that case would then be to describe what the DAC is
>> actually being used to do but that's a more complex issue!
>>
>> That doesn't seem to be what you are targeting here.
>>
>> What it sounds like you need is to have the hardware well enough described that
>> the standard runtime power management can disable the regulator just fine when
>> it is not in use. This may mean improving the power management in the relevant
>> drivers.
>>
>> Jonathan
>>
>> p.s. If ever proposing to do something 'unusual' with a regulator you should
>> bring in the regulator framework maintainers in the cc list.
>>>
>>> - Lars
>>>
>>
>
> I wrote the initial patch quickly and didn't give it much of a
> thought. Now I realized I completely missed the point and managed to
> confuse everybody - myself included.
>
> So the problem we have is not power-cycling the adc - it's
> power-cycling the device connected to a probe on which there's an adc.
> What I was trying to do was adding support for the power-switch on
> baylibre-acme[1] probes.
>
> For example: we have a USB probe on which the VBUS signal goes through
> a power load switch and than through the adc. The adc (in this case
> ina226) is always powered on, while the fixed regulator I wanted to
> enable/disable actually drives the power switch to cut/restore power
> to the connected USB device i.e. there's no real regulator - just a
> GPIO driving the power switch.
>
> A typical use case is measuring the power consumption of development
> boards[2]. Rebooting them remotely using acme probes is already done,
> but we're using the obsolete /sys/class/gpio interface.
>
> We're already using libiio to read the measured data from the power
> monitor, that's why we'd like to use the iio framework for
> power-cycling the devices as well. My question is: would bridging the
> regulator framework be the right solution? Should we look for
> something else? Bridge the GPIO framework instead?
Definitely doesn't fit inside standard scope of IIO - though I can see
why you were thinking along these lines.
Mark Brown, any thoughts?
Effectively we are are looking at something that (in general form) might
be the equivalent of controlling a lab bench supply... So regulators
at the edge of the known world, with no visibility of what lies beyond.
>
> Best regards,
> Bartosz Golaszewski
>
> [1] http://baylibre.com/acme/
> [2] https://github.com/BayLibre/POWERCI
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
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
* Re: [PATCH v6 4/9] dt-bindings: iio: iio-mux: document iio-mux bindings
From: Jonathan Cameron @ 2016-12-10 18:21 UTC (permalink / raw)
To: Peter Rosin, Rob Herring
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, Wolfram Sang, Mark Rutland,
Hartmut Knaack, Lars-Peter Clausen, Peter Meerwald-Stadler,
Jonathan Corbet, Arnd Bergmann, Greg Kroah-Hartman,
linux-i2c-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-iio-u79uwXL29TY76Z2rM5mHXA,
linux-doc-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <ea58cfe1-88ed-f215-59df-e9ffba485eaa-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
On 06/12/16 09:18, Peter Rosin wrote:
> On 2016-12-06 00:26, Rob Herring wrote:
>> On Wed, Nov 30, 2016 at 09:16:58AM +0100, Peter Rosin wrote:
>>> Signed-off-by: Peter Rosin <peda-koto5C5qi+TLoDKTGw+V6w@public.gmane.org>
>>> ---
>>> .../bindings/iio/multiplexer/iio-mux.txt | 40 ++++++++++++++++++++++
>>> MAINTAINERS | 6 ++++
>>> 2 files changed, 46 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>
>> I'm still not convinced about this binding, but don't really have more
>> comments ATM. Sending 6 versions in 2 weeks or so doesn't really help
>> either.
>
> Sorry about the noise, I'll try to be more careful going forward. On
> the flip side, I haven't touched the code since v6.
>
> I don't see how bindings that are as flexible as the current (and
> original) phandle link between the mux consumer and the mux controller
> would look, and at the same time be simpler to understand. You need
> to be able to refer to a mux controller from several mux consumers, and
> you need to support several mux controllers in one node (the ADG792A
> case). And, AFAICT, the complex case wasn't really the problem, it was
> that it is overly complex to describe the simple case of one mux
> consumer and one mux controller. But in your comment for v2 [1] you
> said that I was working around limitations with shared GPIO pins. But
> solving that in the GPIO subsystem would not solve all that the
> phandle approach is solving, since you would not have support for
> ADG792A (or other non-GPIO controlled muxes). So, I think listing
> the gpio pins inside the mux consumer node is a non-starter, the mux
> controller has to live in its own node with its own compatible.
>
> Would you be happier if I managed to marry the phandle approach with
> the option of having the mux controller as a child node of the mux
> consumer for the simple case?
>
> I added an example at the end of this message (the same as the first
> example in v4 [2], at least in principle) for easy comparison between
> the phandle and the controller-in-child-node approaches. I can't say
> that I personally find the difference all that significant, and do not
> think it is worth it. As I see it, the "simple option" would just muddy
> the waters...
>
> [1] http://marc.info/?l=linux-kernel&m=147948334204795&w=2
> [2] http://marc.info/?l=linux-kernel&m=148001364904240&w=2
>
>>> diff --git a/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> new file mode 100644
>>> index 000000000000..8080cf790d82
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/iio/multiplexer/iio-mux.txt
>>> @@ -0,0 +1,40 @@
>>> +IIO multiplexer bindings
>>> +
>>> +If a multiplexer is used to select which hardware signal is fed to
>>> +e.g. an ADC channel, these bindings describe that situation.
>>> +
>>> +Required properties:
>>> +- compatible : "iio-mux"
>>
>> This is a Linuxism. perhaps "adc-mux".
>
> No, that's not general enough, it could just as well be used to mux a
> temperature sensor. Or whatever. Hmmm, given that "iio-mux" is bad, perhaps
> "io-channel-mux" is better? That matches the io-channels property used to
> refer to the parent channel.
analog-mux maybe? Makes more sense out of context (though with io-channels defined on
the next line you have plenty of context here ;)
>
>>> +- io-channels : Channel node of the parent channel that has multiplexed
>>> + input.
>>> +- io-channel-names : Should be "parent".
>>> +- #address-cells = <1>;
>>> +- #size-cells = <0>;
>>> +- mux-controls : Mux controller node to use for operating the mux
>>> +- channels : List of strings, labeling the mux controller states.
>>> +
>>> +The multiplexer state as described in ../misc/mux-controller.txt
>>> +
>>> +For each non-empty string in the channels property, an iio channel will
>>> +be created. The number of this iio channel is the same as the index into
>>> +the list of strings in the channels property, and also matches the mux
>>> +controller state.
>>> +
>>> +Example:
>>> + mux: mux-controller {
>>> + compatible = "mux-gpio";
>>> + #mux-control-cells = <0>;
>>> +
>>> + mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
>>> + <&pioA 1 GPIO_ACTIVE_HIGH>;
>>> + };
>>> +
>>> + adc-mux {
>>> + compatible = "iio-mux";
>>> + io-channels = <&adc 0>;
>>> + io-channel-names = "parent";
>>> +
>>> + mux-controls = <&mux>;
>>> +
>>> + channels = "sync", "in", system-regulator";
>>> + };
>
> Describing the same as above, but with the mux controller as a child
> node.
>
> adc-mux {
> compatible = "iio-mux";
> io-channels = <&adc 0>;
> io-channel-names = "parent";
>
> channels = "sync", "in", system-regulator";
>
> mux-controller {
> compatible = "mux-gpio";
>
> mux-gpios = <&pioA 0 GPIO_ACTIVE_HIGH>,
> <&pioA 1 GPIO_ACTIVE_HIGH>;
> };
> };
>
> Cheers,
> Peter
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
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
* Re: [PATCH v3 1/5] mtd: spi-nor: add memory controllers for the Aspeed AST2500 SoC
From: Marek Vasut @ 2016-12-10 19:08 UTC (permalink / raw)
To: Cédric Le Goater, linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Cyrille Pitchen,
devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Mark Rutland,
Joel Stanley
In-Reply-To: <f0ad683a-0989-e1ae-b33b-9746260ffa0e-Bxea+6Xhats@public.gmane.org>
On 12/10/2016 06:34 PM, Cédric Le Goater wrote:
> Hello,
Hi!
> On 12/10/2016 05:01 AM, Marek Vasut wrote:
>> On 12/09/2016 05:49 PM, Cédric Le Goater wrote:
>>
>> [...]
>>
>>
>>> +static int aspeed_smc_read_from_ahb(void *buf, const void __iomem *src,
>>> + size_t len)
>>> +{
>>> + if (IS_ALIGNED((u32)src, sizeof(u32)) &&
>>> + IS_ALIGNED((u32)buf, sizeof(u32)) &&
>>> + IS_ALIGNED(len, sizeof(u32))) {
>>
>> Did you try compiling this on any 64bit system ?
>
> I cross compile the kernel on a 64bit host and then upload on the
> target. What kind of problem are you forseeing ?
Something about the pointer being clipped to 4 bytes, I'd rather use
uintptr_t cast instead of u32 . I don't think it matters for this check,
but just to be extra precise ...
>>
>>> + while (len > 3) {
>>> + *(u32 *)buf = readl(src);
[...]
>>> +/*
>>> + * Segment Address Registers. Start and end addresses are encoded
>>> + * using 8MB units
>>> + */
>>> +#define SEGMENT_ADDR_REG0 0x30
>>> +#define SEGMENT_ADDR_START(_r) ((((_r) >> 16) & 0xFF) << 23)
>>
>> is that ((r) & 0xff0000) << 7 ?
>>
>>> +#define SEGMENT_ADDR_END(_r) ((((_r) >> 24) & 0xFF) << 23)
>>
>> ((r) & 0xff000000) >> 1 ?
>
> yes.
>
> I rather keep the initial macros though, which I found easier to
> understand.
>
> The Segment Register uses a 8MB unit to encode the start address
> and the end address of the mapping window of a flash SPI slave :
>
> | byte 1 | byte 2 | byte 3 | byte 4 |
> +--------+--------+--------+--------+
> | end | start | 0 | 0 |
Then the above should be in the comment , it's a good explanation :)
Thanks!
--
Best regards,
Marek Vasut
--
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
* Re: [RFC PATCH 1/2] watchdog: imx2: fix hang-up on boot for i.MX21, i.MX27 and i.MX31 SoCs
From: Magnus Lilja @ 2016-12-10 19:28 UTC (permalink / raw)
To: Guenter Roeck
Cc: Vladimir Zapolskiy, Shawn Guo, Wim Van Sebroeck, Rob Herring,
Fabio Estevam, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <ebece25b-7a3b-3fdf-d117-dd0a3a2975b7-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org>
Hi,
On 26 September 2016 at 15:02, Guenter Roeck <linux-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org> wrote:
> On 09/25/2016 05:39 PM, Vladimir Zapolskiy wrote:
>>
>> Power down counter enable/disable bit switch is located in WMCR
>> register, but watchdog controllers found on legacy i.MX21, i.MX27 and
>> i.MX31 SoCs don't have this register. As a result of writing data to
>> the non-existing register on driver probe the SoC hangs up, to fix the
>> problem add more OF compatible strings and on this basis get
>> information about availability of the WMCR register.
>>
>> Fixes: 5fe65ce7ccbb ("watchdog: imx2_wdt: Disable power down counter on
>> boot")
>> Signed-off-by: Vladimir Zapolskiy <vz-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org>
>> ---
>> drivers/watchdog/imx2_wdt.c | 47
>> +++++++++++++++++++++++++++++++++++++++++++--
>> 1 file changed, 45 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
>> index 62f346b..b6763e0 100644
>> --- a/drivers/watchdog/imx2_wdt.c
>> +++ b/drivers/watchdog/imx2_wdt.c
>> @@ -29,6 +29,7 @@
>> #include <linux/module.h>
>> #include <linux/moduleparam.h>
>> #include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> #include <linux/platform_device.h>
>> #include <linux/regmap.h>
>> #include <linux/watchdog.h>
>> @@ -57,6 +58,10 @@
>>
>> #define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
>>
>> +struct imx2_wdt_data {
>> + bool has_pdc;
>> +};
>> +
>> struct imx2_wdt_device {
>> struct clk *clk;
>> struct regmap *regmap;
>> @@ -64,6 +69,8 @@ struct imx2_wdt_device {
>> bool ext_reset;
>> };
>>
>> +static const struct of_device_id imx2_wdt_dt_ids[];
>> +
>> static bool nowayout = WATCHDOG_NOWAYOUT;
>> module_param(nowayout, bool, 0);
>> MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started
>> (default="
>> @@ -200,10 +207,13 @@ static const struct regmap_config
>> imx2_wdt_regmap_config = {
>>
>> static int __init imx2_wdt_probe(struct platform_device *pdev)
>> {
>> + const struct of_device_id *of_id;
>> + const struct imx2_wdt_data *data;
>> struct imx2_wdt_device *wdev;
>> struct watchdog_device *wdog;
>> struct resource *res;
>> void __iomem *base;
>> + bool has_pdc;
>> int ret;
>> u32 val;
>>
>> @@ -261,12 +271,24 @@ static int __init imx2_wdt_probe(struct
>> platform_device *pdev)
>> set_bit(WDOG_HW_RUNNING, &wdog->status);
>> }
>>
>> + if (pdev->dev.of_node) {
>> + of_id = of_match_device(imx2_wdt_dt_ids, &pdev->dev);
>> + if (!of_id)
>> + return -ENODEV;
>> +
>> + data = of_id->data;
>> + has_pdc = data->has_pdc;
>> + } else {
>> + has_pdc = false;
>> + }
>> +
>> /*
>> * Disable the watchdog power down counter at boot. Otherwise the
>> power
>> * down counter will pull down the #WDOG interrupt line for one
>> clock
>> * cycle.
>> */
>> - regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
>> + if (has_pdc)
>> + regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
>>
>> ret = watchdog_register_device(wdog);
>> if (ret) {
>> @@ -363,8 +385,29 @@ static int imx2_wdt_resume(struct device *dev)
>> static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
>> imx2_wdt_resume);
>>
>> +static const struct imx2_wdt_data imx21_wdt_data = {
>> + .has_pdc = false,
>> +};
>> +
>> +static const struct imx2_wdt_data imx25_wdt_data = {
>> + .has_pdc = true,
>> +};
>> +
>> static const struct of_device_id imx2_wdt_dt_ids[] = {
>> - { .compatible = "fsl,imx21-wdt", },
>> + { .compatible = "fsl,imx21-wdt", .data = &imx21_wdt_data },
>
>
> Please just specify the flag directly, as in
> .data = (void *) true
> or, if you prefer, use defines.
> .data = (void *) IMX_SUPPORTS_PDC
>
> Then, in above code:
> has_pdc = (bool) of_id->data;
>
> Guenter
Has this patch (or an updated one) been merged in any tree? I've
tested it on a i.MX31 board with positive result.
Regards, Magnus
--
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
* Re: [RFC PATCH 1/2] watchdog: imx2: fix hang-up on boot for i.MX21, i.MX27 and i.MX31 SoCs
From: Guenter Roeck @ 2016-12-10 20:14 UTC (permalink / raw)
To: Magnus Lilja
Cc: Vladimir Zapolskiy, Shawn Guo, Wim Van Sebroeck, Rob Herring,
Fabio Estevam, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <CAM=E1R6hzob5ZzyTLmrLL5s-6=vbZQbCig1sLHMSLChJEz9YgA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On 12/10/2016 11:28 AM, Magnus Lilja wrote:
> Hi,
>
> On 26 September 2016 at 15:02, Guenter Roeck <linux-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org> wrote:
>> On 09/25/2016 05:39 PM, Vladimir Zapolskiy wrote:
>>>
>>> Power down counter enable/disable bit switch is located in WMCR
>>> register, but watchdog controllers found on legacy i.MX21, i.MX27 and
>>> i.MX31 SoCs don't have this register. As a result of writing data to
>>> the non-existing register on driver probe the SoC hangs up, to fix the
>>> problem add more OF compatible strings and on this basis get
>>> information about availability of the WMCR register.
>>>
>>> Fixes: 5fe65ce7ccbb ("watchdog: imx2_wdt: Disable power down counter on
>>> boot")
>>> Signed-off-by: Vladimir Zapolskiy <vz-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org>
>>> ---
>>> drivers/watchdog/imx2_wdt.c | 47
>>> +++++++++++++++++++++++++++++++++++++++++++--
>>> 1 file changed, 45 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
>>> index 62f346b..b6763e0 100644
>>> --- a/drivers/watchdog/imx2_wdt.c
>>> +++ b/drivers/watchdog/imx2_wdt.c
>>> @@ -29,6 +29,7 @@
>>> #include <linux/module.h>
>>> #include <linux/moduleparam.h>
>>> #include <linux/of_address.h>
>>> +#include <linux/of_device.h>
>>> #include <linux/platform_device.h>
>>> #include <linux/regmap.h>
>>> #include <linux/watchdog.h>
>>> @@ -57,6 +58,10 @@
>>>
>>> #define WDOG_SEC_TO_COUNT(s) ((s * 2 - 1) << 8)
>>>
>>> +struct imx2_wdt_data {
>>> + bool has_pdc;
>>> +};
>>> +
>>> struct imx2_wdt_device {
>>> struct clk *clk;
>>> struct regmap *regmap;
>>> @@ -64,6 +69,8 @@ struct imx2_wdt_device {
>>> bool ext_reset;
>>> };
>>>
>>> +static const struct of_device_id imx2_wdt_dt_ids[];
>>> +
>>> static bool nowayout = WATCHDOG_NOWAYOUT;
>>> module_param(nowayout, bool, 0);
>>> MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started
>>> (default="
>>> @@ -200,10 +207,13 @@ static const struct regmap_config
>>> imx2_wdt_regmap_config = {
>>>
>>> static int __init imx2_wdt_probe(struct platform_device *pdev)
>>> {
>>> + const struct of_device_id *of_id;
>>> + const struct imx2_wdt_data *data;
>>> struct imx2_wdt_device *wdev;
>>> struct watchdog_device *wdog;
>>> struct resource *res;
>>> void __iomem *base;
>>> + bool has_pdc;
>>> int ret;
>>> u32 val;
>>>
>>> @@ -261,12 +271,24 @@ static int __init imx2_wdt_probe(struct
>>> platform_device *pdev)
>>> set_bit(WDOG_HW_RUNNING, &wdog->status);
>>> }
>>>
>>> + if (pdev->dev.of_node) {
>>> + of_id = of_match_device(imx2_wdt_dt_ids, &pdev->dev);
>>> + if (!of_id)
>>> + return -ENODEV;
>>> +
>>> + data = of_id->data;
>>> + has_pdc = data->has_pdc;
>>> + } else {
>>> + has_pdc = false;
>>> + }
>>> +
>>> /*
>>> * Disable the watchdog power down counter at boot. Otherwise the
>>> power
>>> * down counter will pull down the #WDOG interrupt line for one
>>> clock
>>> * cycle.
>>> */
>>> - regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
>>> + if (has_pdc)
>>> + regmap_write(wdev->regmap, IMX2_WDT_WMCR, 0);
>>>
>>> ret = watchdog_register_device(wdog);
>>> if (ret) {
>>> @@ -363,8 +385,29 @@ static int imx2_wdt_resume(struct device *dev)
>>> static SIMPLE_DEV_PM_OPS(imx2_wdt_pm_ops, imx2_wdt_suspend,
>>> imx2_wdt_resume);
>>>
>>> +static const struct imx2_wdt_data imx21_wdt_data = {
>>> + .has_pdc = false,
>>> +};
>>> +
>>> +static const struct imx2_wdt_data imx25_wdt_data = {
>>> + .has_pdc = true,
>>> +};
>>> +
>>> static const struct of_device_id imx2_wdt_dt_ids[] = {
>>> - { .compatible = "fsl,imx21-wdt", },
>>> + { .compatible = "fsl,imx21-wdt", .data = &imx21_wdt_data },
>>
>>
>> Please just specify the flag directly, as in
>> .data = (void *) true
>> or, if you prefer, use defines.
>> .data = (void *) IMX_SUPPORTS_PDC
>>
>> Then, in above code:
>> has_pdc = (bool) of_id->data;
>>
>> Guenter
>
> Has this patch (or an updated one) been merged in any tree? I've
> tested it on a i.MX31 board with positive result.
>
I had asked for a change, and I don't recall seeing v2. So, at least as far
as I know, the answer is no.
Guenter
--
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
* Re: [RFC PATCH 1/2] watchdog: imx2: fix hang-up on boot for i.MX21, i.MX27 and i.MX31 SoCs
From: Vladimir Zapolskiy @ 2016-12-10 22:37 UTC (permalink / raw)
To: Magnus Lilja, Guenter Roeck
Cc: Shawn Guo, Wim Van Sebroeck, Rob Herring, Fabio Estevam,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA, Sascha Hauer,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <CAM=E1R6hzob5ZzyTLmrLL5s-6=vbZQbCig1sLHMSLChJEz9YgA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
Hi Magnus,
On 12/10/2016 09:28 PM, Magnus Lilja wrote:
> Hi,
>
> On 26 September 2016 at 15:02, Guenter Roeck <linux-0h96xk9xTtrk1uMJSBkQmQ@public.gmane.org> wrote:
>> On 09/25/2016 05:39 PM, Vladimir Zapolskiy wrote:
>>>
>>> Power down counter enable/disable bit switch is located in WMCR
>>> register, but watchdog controllers found on legacy i.MX21, i.MX27 and
>>> i.MX31 SoCs don't have this register. As a result of writing data to
>>> the non-existing register on driver probe the SoC hangs up, to fix the
>>> problem add more OF compatible strings and on this basis get
>>> information about availability of the WMCR register.
>>>
>>> Fixes: 5fe65ce7ccbb ("watchdog: imx2_wdt: Disable power down counter on
>>> boot")
>>> Signed-off-by: Vladimir Zapolskiy <vz-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org>
>>> ---
[snip]
>
> Has this patch (or an updated one) been merged in any tree? I've
> tested it on a i.MX31 board with positive result.
>
no, it's not in the linux-watchdog repository at the moment, I'm going
to fix Guenter's review comments and send the change today or tomorrow
in hope that it enters v4.10.
Thank you for testing, for your information I'm on the way to send more
i.MX31 changes to get better i.MX31 device tree support.
--
With best wishes,
Vladimir
--
To unsubscribe from this list: send the line "unsubscribe linux-watchdog" 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
* Re: [PATCH v4 4/5] i2c: designware: Add slave mode as separated driver
From: kbuild test robot @ 2016-12-10 23:44 UTC (permalink / raw)
Cc: kbuild-all, wsa, robh+dt, mark.rutland, jarkko.nikula,
andriy.shevchenko, mika.westerberg, linux-i2c, devicetree,
linux-kernel, Luis.Oliveira, Ramiro.Oliveira, Joao.Pinto,
CARLOS.PALMINHA
In-Reply-To: <a7ca5014ad1c3f4905349a02ebe5294fe64c318e.1481131072.git.lolivei@synopsys.com>
[-- Attachment #1: Type: text/plain, Size: 6820 bytes --]
Hi Luis,
[auto build test ERROR on wsa/i2c/for-next]
[also build test ERROR on next-20161209]
[cannot apply to v4.9-rc8]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Luis-Oliveira/i2c-designware-Refactoring-of-the-i2c-designware/20161208-044045
base: https://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git i2c/for-next
config: i386-randconfig-c0-12110449 (attached as .config)
compiler: gcc-4.9 (Debian 4.9.4-2) 4.9.4
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
All errors (new ones prefixed by >>):
drivers/i2c/busses/i2c-designware-slave.c: In function 'i2c_dw_irq_handler_slave':
>> drivers/i2c/busses/i2c-designware-slave.c:294:3: error: implicit declaration of function 'i2c_slave_event' [-Werror=implicit-function-declaration]
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^
>> drivers/i2c/busses/i2c-designware-slave.c:294:31: error: 'I2C_SLAVE_WRITE_REQUESTED' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
^
drivers/i2c/busses/i2c-designware-slave.c:294:31: note: each undeclared identifier is reported only once for each function it appears in
In file included from include/linux/err.h:4:0,
from drivers/i2c/busses/i2c-designware-slave.c:26:
>> drivers/i2c/busses/i2c-designware-slave.c:301:6: error: 'I2C_SLAVE_WRITE_RECEIVED' undeclared (first use in this function)
I2C_SLAVE_WRITE_RECEIVED, &val)) {
^
include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^
drivers/i2c/busses/i2c-designware-slave.c:300:5: note: in expansion of macro 'if'
if (!i2c_slave_event(dev->slave,
^
>> drivers/i2c/busses/i2c-designware-slave.c:313:7: error: 'I2C_SLAVE_READ_REQUESTED' undeclared (first use in this function)
I2C_SLAVE_READ_REQUESTED, &val))
^
include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^
drivers/i2c/busses/i2c-designware-slave.c:312:4: note: in expansion of macro 'if'
if (!i2c_slave_event(dev->slave,
^
>> drivers/i2c/busses/i2c-designware-slave.c:319:36: error: 'I2C_SLAVE_READ_PROCESSED' undeclared (first use in this function)
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
^
include/linux/compiler.h:149:30: note: in definition of macro '__trace_if'
if (__builtin_constant_p(!!(cond)) ? !!(cond) : \
^
drivers/i2c/busses/i2c-designware-slave.c:319:3: note: in expansion of macro 'if'
if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
^
>> drivers/i2c/busses/i2c-designware-slave.c:323:31: error: 'I2C_SLAVE_STOP' undeclared (first use in this function)
i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
^
drivers/i2c/busses/i2c-designware-slave.c: At top level:
>> drivers/i2c/busses/i2c-designware-slave.c:358:2: error: unknown field 'reg_slave' specified in initializer
.reg_slave = i2c_dw_reg_slave,
^
drivers/i2c/busses/i2c-designware-slave.c:358:2: warning: excess elements in struct initializer
drivers/i2c/busses/i2c-designware-slave.c:358:2: warning: (near initialization for 'i2c_dw_algo')
>> drivers/i2c/busses/i2c-designware-slave.c:359:2: error: unknown field 'unreg_slave' specified in initializer
.unreg_slave = i2c_dw_unreg_slave,
^
drivers/i2c/busses/i2c-designware-slave.c:359:2: warning: excess elements in struct initializer
drivers/i2c/busses/i2c-designware-slave.c:359:2: warning: (near initialization for 'i2c_dw_algo')
cc1: some warnings being treated as errors
vim +/i2c_slave_event +294 drivers/i2c/busses/i2c-designware-slave.c
288 dw_readl(dev, DW_IC_CLR_START_DET);
289 if (stat & DW_IC_INTR_ACTIVITY)
290 dw_readl(dev, DW_IC_CLR_ACTIVITY);
291 if (stat & DW_IC_INTR_RX_OVER)
292 dw_readl(dev, DW_IC_CLR_RX_OVER);
293 if ((stat & DW_IC_INTR_RX_FULL) && (stat & DW_IC_INTR_STOP_DET))
> 294 i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val);
295
296 if (slave_activity) {
297 if (stat & DW_IC_INTR_RD_REQ) {
298 if (stat & DW_IC_INTR_RX_FULL) {
299 val = dw_readl(dev, DW_IC_DATA_CMD);
300 if (!i2c_slave_event(dev->slave,
> 301 I2C_SLAVE_WRITE_RECEIVED, &val)) {
302 dev_dbg(dev->dev, "Byte %X acked!",
303 val);
304 }
305 dw_readl(dev, DW_IC_CLR_RD_REQ);
306 stat = i2c_dw_read_clear_intrbits_slave(dev);
307 } else {
308 dw_readl(dev, DW_IC_CLR_RD_REQ);
309 dw_readl(dev, DW_IC_CLR_RX_UNDER);
310 stat = i2c_dw_read_clear_intrbits_slave(dev);
311 }
312 if (!i2c_slave_event(dev->slave,
> 313 I2C_SLAVE_READ_REQUESTED, &val))
314 dw_writel(dev, val, DW_IC_DATA_CMD);
315 }
316 }
317
318 if (stat & DW_IC_INTR_RX_DONE) {
> 319 if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED,
320 &val))
321 dw_readl(dev, DW_IC_CLR_RX_DONE);
322
> 323 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
324 stat = i2c_dw_read_clear_intrbits_slave(dev);
325 return true;
326 }
327
328 if (stat & DW_IC_INTR_RX_FULL) {
329 val = dw_readl(dev, DW_IC_DATA_CMD);
330 if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED,
331 &val))
332 dev_dbg(dev->dev, "Byte %X acked!", val);
333 } else {
334 i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val);
335 stat = i2c_dw_read_clear_intrbits_slave(dev);
336 }
337
338 if (stat & DW_IC_INTR_TX_OVER)
339 dw_readl(dev, DW_IC_CLR_TX_OVER);
340
341 return true;
342 }
343
344 static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id)
345 {
346 struct dw_i2c_dev *dev = dev_id;
347
348 i2c_dw_read_clear_intrbits_slave(dev);
349 if (!i2c_dw_irq_handler_slave(dev))
350 return IRQ_NONE;
351
352 complete(&dev->cmd_complete);
353 return IRQ_HANDLED;
354 }
355
356 static struct i2c_algorithm i2c_dw_algo = {
357 .functionality = i2c_dw_func,
> 358 .reg_slave = i2c_dw_reg_slave,
> 359 .unreg_slave = i2c_dw_unreg_slave,
360 };
361
362 void i2c_dw_disable_slave(struct dw_i2c_dev *dev)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 31719 bytes --]
^ permalink raw reply
* Re: [PATCH 3/3] crypto: brcm: Add Broadcom SPU driver DT entry.
From: kbuild test robot @ 2016-12-11 0:14 UTC (permalink / raw)
Cc: kbuild-all-JC7UmRfGjtg, Herbert Xu, David S. Miller, Rob Herring,
Mark Rutland, linux-crypto-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ray Jui, Scott Branden,
Jon Mason, bcm-kernel-feedback-list-dY08KVG/lbpWk0Htik3J/w,
Catalin Marinas, Will Deacon,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Steve Lin,
Rob Rice
In-Reply-To: <1480536453-24781-4-git-send-email-rob.rice-dY08KVG/lbpWk0Htik3J/w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1065 bytes --]
Hi Rob,
[auto build test ERROR on cryptodev/master]
[also build test ERROR on v4.9-rc8]
[cannot apply to next-20161209]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Rob-Rice/crypto-brcm-DT-documentation-for-Broadcom-SPU-driver/20161202-010038
base: https://git.kernel.org/pub/scm/linux/kernel/git/herbert/cryptodev-2.6.git master
config: arm64-defconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
All errors (new ones prefixed by >>):
>> ERROR: Input tree has errors, aborting (use -f to force output)
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 31957 bytes --]
^ permalink raw reply
* Courier was not able to deliver your parcel (ID000422883, FedEx)
From: FedEx Priority Delivery @ 2016-12-11 4:59 UTC (permalink / raw)
To: devicetree-u79uwXL29TY76Z2rM5mHXA
[-- Attachment #1: Type: text/plain, Size: 176 bytes --]
Dear Devi,
We can not deliver your parcel arrived at December 09.
Please check the attachment for complete details!
With many thanks,
Joel Price,
Parcels Delivery Manager.
[-- Attachment #2: Undelivered-Package-000422883.zip --]
[-- Type: application/zip, Size: 3000 bytes --]
^ permalink raw reply
* Re: [PATCH v5 3/3] fpga manager: Add cyclone-ps-spi driver for Altera FPGAs
From: kbuild test robot @ 2016-12-11 6:13 UTC (permalink / raw)
Cc: kbuild-all-JC7UmRfGjtg, Alan Tull, Moritz Fischer, Mark Rutland,
Russell King, Rob Herring, Anatolij Gustschin, Joshua Clayton,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1778a82d1989d13919b24e47fa09eeb56b2cb8e5.1481139171.git.stillcompiling-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 3086 bytes --]
Hi Joshua,
[auto build test ERROR on linus/master]
[also build test ERROR on v4.9-rc8]
[cannot apply to next-20161209]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Joshua-Clayton/lib-add-bitrev8x4/20161208-070638
config: arm64-allmodconfig (attached as .config)
compiler: aarch64-linux-gnu-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm64
All errors (new ones prefixed by >>):
In file included from drivers/fpga/cyclone-ps-spi.c:13:0:
drivers/fpga/cyclone-ps-spi.c: In function 'rev_buf':
>> include/linux/bitrev.h:12:21: error: implicit declaration of function '__arch_bitrev8x4' [-Werror=implicit-function-declaration]
#define __bitrev8x4 __arch_bitrev8x4
^
include/linux/bitrev.h:101:2: note: in expansion of macro '__bitrev8x4'
__bitrev8x4(__x); \
^~~~~~~~~~~
drivers/fpga/cyclone-ps-spi.c:84:11: note: in expansion of macro 'bitrev8x4'
*fw32 = bitrev8x4(*fw32);
^~~~~~~~~
In file included from include/linux/delay.h:10:0,
from drivers/fpga/cyclone-ps-spi.c:14:
drivers/fpga/cyclone-ps-spi.c: In function 'cyclonespi_write':
include/linux/kernel.h:739:16: warning: comparison of distinct pointer types lacks a cast
(void) (&min1 == &min2); \
^
include/linux/kernel.h:742:2: note: in expansion of macro '__min'
__min(typeof(x), typeof(y), \
^~~~~
drivers/fpga/cyclone-ps-spi.c:98:19: note: in expansion of macro 'min'
size_t stride = min(fw_data_end - fw_data, SZ_4K);
^~~
cc1: some warnings being treated as errors
vim +/__arch_bitrev8x4 +12 include/linux/bitrev.h
556d2f05 Yalin Wang 2014-11-03 6 #ifdef CONFIG_HAVE_ARCH_BITREVERSE
556d2f05 Yalin Wang 2014-11-03 7 #include <asm/bitrev.h>
556d2f05 Yalin Wang 2014-11-03 8
556d2f05 Yalin Wang 2014-11-03 9 #define __bitrev32 __arch_bitrev32
556d2f05 Yalin Wang 2014-11-03 10 #define __bitrev16 __arch_bitrev16
556d2f05 Yalin Wang 2014-11-03 11 #define __bitrev8 __arch_bitrev8
533d0eab Joshua Clayton 2016-12-07 @12 #define __bitrev8x4 __arch_bitrev8x4
a5cfc1ec Akinobu Mita 2006-12-08 13
556d2f05 Yalin Wang 2014-11-03 14 #else
556d2f05 Yalin Wang 2014-11-03 15 extern u8 const byte_rev_table[256];
:::::: The code at line 12 was first introduced by commit
:::::: 533d0eabff8f37edfdec7fdf6e705fdecb297daa lib: add bitrev8x4()
:::::: TO: Joshua Clayton <stillcompiling-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
:::::: CC: 0day robot <fengguang.wu-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 52456 bytes --]
^ permalink raw reply
* [PATCH] Input: imx6ul_tsc - generalize the averaging property
From: Guy Shapiro @ 2016-12-11 7:06 UTC (permalink / raw)
To: dmitry.torokhov, robh
Cc: fabio.estevam, mark.rutland, Guy Shapiro, devicetree, haibo.chen,
linux-input, linux-arm-kernel
Make the avarage-samples property a general touchscreen property
rather than imx6ul device specific.
Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
---
.../bindings/input/touchscreen/imx6ul_tsc.txt | 11 ++----
.../bindings/input/touchscreen/touchscreen.txt | 3 ++
drivers/input/touchscreen/imx6ul_tsc.c | 46 ++++++++++++++++------
3 files changed, 41 insertions(+), 19 deletions(-)
diff --git a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
index a66069f..d4927c2 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
@@ -17,13 +17,8 @@ Optional properties:
This value depends on the touch screen.
- pre-charge-time: the touch screen need some time to precharge.
This value depends on the touch screen.
-- average-samples: Number of data samples which are averaged for each read.
- Valid values 0-4
- 0 = 1 sample
- 1 = 4 samples
- 2 = 8 samples
- 3 = 16 samples
- 4 = 32 samples
+- touchscreen-average-samples: Number of data samples which are averaged for
+ each read. Valid values are 1, 4, 8, 16 and 32.
Example:
tsc: tsc@02040000 {
@@ -39,6 +34,6 @@ Example:
xnur-gpio = <&gpio1 3 GPIO_ACTIVE_LOW>;
measure-delay-time = <0xfff>;
pre-charge-time = <0xffff>;
- average-samples = <4>;
+ touchscreen-average-samples = <32>;
status = "okay";
};
diff --git a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
index bccaa4e..537643e 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/touchscreen.txt
@@ -14,6 +14,9 @@ Optional properties for Touchscreens:
- touchscreen-fuzz-pressure : pressure noise value of the absolute input
device (arbitrary range dependent on the
controller)
+ - touchscreen-average-samples : Number of data samples which are averaged
+ for each read (valid values dependent on the
+ controller)
- touchscreen-inverted-x : X axis is inverted (boolean)
- touchscreen-inverted-y : Y axis is inverted (boolean)
- touchscreen-swapped-x-y : X and Y axis are swapped (boolean)
diff --git a/drivers/input/touchscreen/imx6ul_tsc.c b/drivers/input/touchscreen/imx6ul_tsc.c
index d2a3912..58d1aa5 100644
--- a/drivers/input/touchscreen/imx6ul_tsc.c
+++ b/drivers/input/touchscreen/imx6ul_tsc.c
@@ -93,7 +93,8 @@ struct imx6ul_tsc {
u32 measure_delay_time;
u32 pre_charge_time;
- u32 average_samples;
+ bool average_enable;
+ u32 average_select;
struct completion completion;
};
@@ -117,9 +118,9 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
adc_cfg |= ADC_12BIT_MODE | ADC_IPG_CLK;
adc_cfg &= ~(ADC_CLK_DIV_MASK | ADC_SAMPLE_MODE_MASK);
adc_cfg |= ADC_CLK_DIV_8 | ADC_SHORT_SAMPLE_MODE;
- if (tsc->average_samples) {
+ if (tsc->average_enable) {
adc_cfg &= ~ADC_AVGS_MASK;
- adc_cfg |= (tsc->average_samples - 1) << ADC_AVGS_SHIFT;
+ adc_cfg |= (tsc->average_select) << ADC_AVGS_SHIFT;
}
adc_cfg &= ~ADC_HARDWARE_TRIGGER;
writel(adc_cfg, tsc->adc_regs + REG_ADC_CFG);
@@ -132,7 +133,7 @@ static int imx6ul_adc_init(struct imx6ul_tsc *tsc)
/* start ADC calibration */
adc_gc = readl(tsc->adc_regs + REG_ADC_GC);
adc_gc |= ADC_CAL;
- if (tsc->average_samples)
+ if (tsc->average_enable)
adc_gc |= ADC_AVGE;
writel(adc_gc, tsc->adc_regs + REG_ADC_GC);
@@ -362,6 +363,7 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
int err;
int tsc_irq;
int adc_irq;
+ u32 average_samples;
tsc = devm_kzalloc(&pdev->dev, sizeof(*tsc), GFP_KERNEL);
if (!tsc)
@@ -466,14 +468,36 @@ static int imx6ul_tsc_probe(struct platform_device *pdev)
if (err)
tsc->pre_charge_time = 0xfff;
- err = of_property_read_u32(np, "average-samples",
- &tsc->average_samples);
+ err = of_property_read_u32(np, "touchscreen-average-samples",
+ &average_samples);
if (err)
- tsc->average_samples = 0;
-
- if (tsc->average_samples > 4) {
- dev_err(&pdev->dev, "average-samples (%u) must be [0-4]\n",
- tsc->average_samples);
+ average_samples = 1;
+
+ switch (average_samples) {
+ case 1:
+ tsc->average_enable = false;
+ tsc->average_select = 0; /* value unused; initialize anyway */
+ break;
+ case 4:
+ tsc->average_enable = true;
+ tsc->average_select = 0;
+ break;
+ case 8:
+ tsc->average_enable = true;
+ tsc->average_select = 1;
+ break;
+ case 16:
+ tsc->average_enable = true;
+ tsc->average_select = 2;
+ break;
+ case 32:
+ tsc->average_enable = true;
+ tsc->average_select = 3;
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "touchscreen-average-samples (%u) must be 1, 4, 8, 16 or 32\n",
+ average_samples);
return -EINVAL;
}
--
2.1.4
^ permalink raw reply related
* Re: [RFC PATCH 2/2] ARM: i.MX: dts: add fsl, imx25-wdt compatible to all relevant watchdog nodes
From: Uwe Kleine-König @ 2016-12-11 9:40 UTC (permalink / raw)
To: Vladimir Zapolskiy
Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-watchdog-u79uwXL29TY76Z2rM5mHXA, Wim Van Sebroeck,
Rob Herring, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Sascha Hauer, Fabio Estevam, Shawn Guo, Guenter Roeck
In-Reply-To: <20160926062759.3eoezyezog6clz6x-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org>
Hello,
On Mon, Sep 26, 2016 at 08:27:59AM +0200, Uwe Kleine-König wrote:
> On Mon, Sep 26, 2016 at 03:39:21AM +0300, Vladimir Zapolskiy wrote:
> > Watchdog device controller found on all modern SoCs from i.MX series
> > and firstly introduced in i.MX25 is not one in one compatible with the
> > watchdog controllers on i.MX21, i.MX27 and i.MX31, the latter
> > controlles don't have WICR (and pretimeout notification support) and
> > WMCR registers. To get benefit from the more advanced watchdog device
> > and to avoid operations over non-existing registers on legacy SoCs add
> > fsl,imx25-wdt compatible to descriptions of all i.MX25 compatible
> > watchdog controllers.
> >
> > Signed-off-by: Vladimir Zapolskiy <vz-ChpfBGZJDbMAvxtiuMwx3w@public.gmane.org>
> > ---
> > arch/arm/boot/dts/imx35.dtsi | 3 ++-
> > arch/arm/boot/dts/imx50.dtsi | 3 ++-
> > arch/arm/boot/dts/imx51.dtsi | 6 ++++--
> > arch/arm/boot/dts/imx53.dtsi | 6 ++++--
> > arch/arm/boot/dts/imx6qdl.dtsi | 6 ++++--
> > arch/arm/boot/dts/imx6sl.dtsi | 6 ++++--
> > arch/arm/boot/dts/imx6sx.dtsi | 9 ++++++---
> > arch/arm/boot/dts/imx6ul.dtsi | 6 ++++--
> > arch/arm/boot/dts/imx7s.dtsi | 12 ++++++++----
> > arch/arm/boot/dts/ls1021a.dtsi | 2 +-
> > arch/arm/boot/dts/vfxxx.dtsi | 3 ++-
> > 11 files changed, 41 insertions(+), 21 deletions(-)
> >
> > diff --git a/arch/arm/boot/dts/imx35.dtsi b/arch/arm/boot/dts/imx35.dtsi
> > index 490b7b4..8fd4482 100644
> > --- a/arch/arm/boot/dts/imx35.dtsi
> > +++ b/arch/arm/boot/dts/imx35.dtsi
> > @@ -284,7 +284,8 @@
> > };
> >
> > wdog: wdog@53fdc000 {
> > - compatible = "fsl,imx35-wdt", "fsl,imx21-wdt";
> > + compatible = "fsl,imx35-wdt", "fsl,imx25-wdt",
> > + "fsl,imx21-wdt";
>
> When this is used on an old kernel that doesn't know about fsl,imx25-wdt
> this picks up the imx21 driver logic. As this is wrong I think you
> should drop imx21-wdt here. Can one of the dt-people comfirm?
I forgot in the mail at the other end of this thread that the dti were
already addressed. I (implicitly) wrote there that fsl,imx35-wdt should
be the new compatible describing the wdt with misc register. Picking
imx25 (as you did) works, too, but e.g. the CSPI device has
compatible = "fsl,imx25-cspi", "fsl,imx35-cspi";
on the i.MX25 and
compatible = "fsl,imx35-cspi";
on the i.MX35. So I think we should pick i.MX35 here, too, as the one
giving its name.
Best regards
Uwe
--
Pengutronix e.K. | Uwe Kleine-König |
Industrial Linux Solutions | http://www.pengutronix.de/ |
--
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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox