* Re: [PATCH V3 0/5] iommu/arm-smmu: Add runtime pm/sleep support
From: Will Deacon @ 2017-03-31 17:54 UTC (permalink / raw)
To: Sricharan R
Cc: robin.murphy-5wv7dgnIgG8, joro-zLv9SwRftAIdnm+yROfE0A,
iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
m.szyprowski-Sze3O3UU22JBDgjK7y7TUQ,
linux-clk-u79uwXL29TY76Z2rM5mHXA, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
devicetree-u79uwXL29TY76Z2rM5mHXA, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
mathieu.poirier-QSEj5FYQhm4dnm+yROfE0A, mark.rutland-5wv7dgnIgG8
In-Reply-To: <1489073748-3659-1-git-send-email-sricharan-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
On Thu, Mar 09, 2017 at 09:05:43PM +0530, Sricharan R wrote:
> This series provides the support for turning on the arm-smmu's
> clocks/power domains using runtime pm. This is done using the
> recently introduced device links patches, which lets the symmu's
> runtime to follow the master's runtime pm, so the smmu remains
> powered only when the masters use it.
Do you have any numbers for the power savings you achieve with this?
How often do we actually manage to stop the SMMU clocks on an SoC with
a handful of masters?
In other words, is this too coarse-grained to be useful, or is it common
that all the devices upstream of the SMMU are suspended?
Thanks,
Will
>
> Took some reference from the exynos runtime patches [2].
> Tested this with MDP, GPU, VENUS devices on apq8096-db820c board.
>
> Previous version of the patchset [1].
>
> [V3]
> * Reworked the patches to keep the clocks init/enabling function
> seperately for each compatible.
>
> * Added clocks bindings for MMU40x/500.
>
> * Added a new compatible for qcom,smmu-v2 implementation and
> the clock bindings for the same.
>
> * Rebased on top of 4.11-rc1
>
> [V2]
> * Split the patches little differently.
>
> * Addressed comments.
>
> * Removed the patch #4 [3] from previous post
> for arm-smmu context save restore. Planning to
> post this separately after reworking/addressing Robin's
> feedback.
>
> * Reversed the sequence to disable clocks than enabling.
> This was required for those cases where the
> clocks are populated in a dependent order from DT.
>
> [1] https://www.spinics.net/lists/linux-arm-msm/msg23870.html
> [2] https://lkml.org/lkml/2016/10/20/70
> [3] https://patchwork.kernel.org/patch/9389717/
>
> Sricharan R (5):
> iommu/arm-smmu: Add pm_runtime/sleep ops
> iommu/arm-smmu: Add support for MMU40x/500 clocks
> drivers: arm-smmu: Add clock support for QCOM_SMMUV2
> iommu/arm-smmu: Invoke pm_runtime during probe, add/remove device
> iommu/arm-smmu: Add the device_link between masters and smmu
>
> .../devicetree/bindings/iommu/arm,smmu.txt | 35 +++
> drivers/iommu/arm-smmu.c | 349 ++++++++++++++++++++-
> 2 files changed, 373 insertions(+), 11 deletions(-)
>
> --
> QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
>
--
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] ARM: dts: armada-38x: label USB and SATA nodes
From: Ralph Sennhauser @ 2017-03-31 17:39 UTC (permalink / raw)
To: Andrew Lunn
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jason Cooper,
Gregory Clement, Sebastian Hesselbarth, Rob Herring, Mark Rutland,
Russell King, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170331165015.GJ12814-g2DYL2Zd6BY@public.gmane.org>
On Fri, 31 Mar 2017 18:50:15 +0200
Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org> wrote:
> > - sata@a8000 {
> > + satac0: sata@a8000 {
>
> Hi Ralph
>
> Why the c in satac0?
For controller and to not conflict with a use case of sata0 for a port,
similarly to pciec and pcie1. See armada-385-synology-ds116.dts.
>
> >
> > - usb3@f0000 {
> > + usb3_0: usb3@f0000 {
> > compatible =
> > "marvell,armada-380-xhci"; reg = <0xf0000 0x4000>,<0xf4000 0x4000>;
> > interrupts = <GIC_SPI 16
> > IRQ_TYPE_LEVEL_HIGH>; @@ -598,7 +598,7 @@
> > status = "disabled";
> > };
> >
> > - usb3@f8000 {
> > + usb3_1: usb3@f8000 {
> > compatible =
> > "marvell,armada-380-xhci"; reg = <0xf8000 0x4000>,<0xfc000 0x4000>;
> > interrupts = <GIC_SPI 17
> > IRQ_TYPE_LEVEL_HIGH>;
>
> I can understand what you are saying. But does anybody else care? Are
> there other .dtsi files differentiating between USB 1.1, 2 and 3?
It's handled differently where ever I looked, some do some don't. A
case for distinguishing USB 2.0 and USB 3.0 like this is
armada-388-gp.dts.
Personally I'm only interested in there being a label, making it
"natural" is a bonus though.
Thanks
Ralph
>
> Andrew
--
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 V2 2/2] thermal: broadcom: add Northstar thermal driver
From: Jon Mason @ 2017-03-31 17:29 UTC (permalink / raw)
To: Rafał Miłecki
Cc: Rafał Miłecki, Zhang Rui, Eduardo Valentin, Rob Herring,
Mark Rutland, Stephen Warren, Lee Jones, Eric Anholt,
Florian Fainelli, Ray Jui, Scott Branden, BCM Kernel Feedback,
linux-pm,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-rpi-kernel, linux-arm-kernel
In-Reply-To: <cfbb429d-5dd9-88b4-eeae-a288def7b56f@milecki.pl>
On Fri, Mar 31, 2017 at 10:49 AM, Rafał Miłecki <rafal@milecki.pl> wrote:
> On 03/31/2017 04:23 PM, Jon Mason wrote:
>>
>> On Fri, Mar 31, 2017 at 3:03 AM, Rafał Miłecki <zajec5@gmail.com> wrote:
>>>
>>> On 03/24/2017 03:35 PM, Jon Mason wrote:
>>>>
>>>>
>>>> On Thu, Mar 23, 2017 at 11:30:45PM +0100, Rafał Miłecki wrote:
>>>>>
>>>>>
>>>>> diff --git a/drivers/thermal/broadcom/ns-thermal.c
>>>>> b/drivers/thermal/broadcom/ns-thermal.c
>>>>> new file mode 100644
>>>>> index 000000000000..acf3a4de62a4
>>>>> --- /dev/null
>>>>> +++ b/drivers/thermal/broadcom/ns-thermal.c
>>>>> @@ -0,0 +1,98 @@
>>>>> +/*
>>>>> + * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
>>>>> + *
>>>>> + * This program is free software; you can redistribute it and/or
>>>>> modify
>>>>> + * it under the terms of the GNU General Public License version 2 as
>>>>> + * published by the Free Software Foundation.
>>>>> + */
>>>>> +
>>>>> +#include <linux/module.h>
>>>>> +#include <linux/of_address.h>
>>>>> +#include <linux/platform_device.h>
>>>>> +#include <linux/thermal.h>
>>>>> +
>>>>> +#define PVTMON_CONTROL0 0x00
>>>>> +#define PVTMON_CONTROL0_SEL_MASK 0x0000000e
>>>>> +#define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000
>>>>> +#define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e
>>>>> +#define PVTMON_STATUS 0x08
>>>>> +
>>>>> +struct ns_thermal {
>>>>> + void __iomem *pvtmon;
>>>>> +};
>>>>> +
>>>>> +static int ns_thermal_get_temp(void *data, int *temp)
>>>>> +{
>>>>> + struct ns_thermal *ns_thermal = data;
>>>>> + u32 val;
>>>>> +
>>>>> + val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
>>>>> + if ((val & PVTMON_CONTROL0_SEL_MASK) !=
>>>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
>>>>> + val &= ~PVTMON_CONTROL0_SEL_MASK;
>>>>> + val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
>>>>
>>>>
>>>>
>>>> I think this is slightly confusing here. If this was off, ORing in 0
>>>> will not enable it. I think we need to flip the #define to make it
>>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE (or a less crappy name).
>>>> then use this line here to toggle it. Something like
>>>>
>>>> val &= ~PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE;
>>>
>>>
>>>
>>> I don't understand this, can you help me further?
>>>
>>> OR-ing with 0 is only a cosmetic thing obviously - just to make it clear
>>> which
>>> value we expect to be set in bits 1:3. The important part is:
>>> val &= ~PVTMON_CONTROL0_SEL_MASK;
>>
>>
>> You are using a side effect of the masking to clear/enable the block.
>> I'm simply saying that we should be explicit about enabling it. My
>> concern is that using the side effect hides what is being done and
>> could result in a bug somewhere down the line. I think this is
>> improbable based on the code, but wanted to err on the side of
>> caution.
>
>
> Well, I'm clearing current mode selection and "selecting" the mode I want.
> By
> OR-ing PVTMON_CONTROL0_SEL_TEMP_MONITOR I'm clearly indicating I want temp
> monitor more.
>
> How else I could make it more obvious? Should I add some comment maybe?
I think it would be acceptable to remove the ORing of the 0, and
simply put a comment there that the masking of it is clearing the 0th
bit, thus enabling the IP block.
^ permalink raw reply
* Re: [PATCH v2,1/3] meson_uart: expose CLKID_UARTx
From: Helmut Klein @ 2017-03-31 17:03 UTC (permalink / raw)
To: Jerome Brunet, Kevin Hilman, Martin Blumenstingl
Cc: mturquette, sboyd, devicetree, linux-clk, linux-kernel,
linux-arm-kernel, linux-amlogic
In-Reply-To: <1490974657.12951.5.camel@baylibre.com>
On 31.03.2017 17:37, Jerome Brunet wrote:
> On Wed, 2017-03-29 at 13:21 -0700, Kevin Hilman wrote:
>> Martin Blumenstingl <martin.blumenstingl@googlemail.com> writes:
>>
>> [...]
>>
>>> for Helmut this would mean that instead of dropping this patch (or
>>> dropping CLKID_UART1 and CLKID_UART2 from this patch) he would rather
>>> have to *add* another patch (for meson-gxbb.dtsi and meson-gxl.dtsi)
>>> which passes the core clocks to the corresponding UART controllers
>>> (similar to the CLKID_SD_EMMC_ clocks).
>>
>> Yes, this is what I would like to see.
>>
>> If a new CLKID is exposed, I want to see the users of it at the same
>> time.
>
> Helmut,
>
> If you send another version of these patches, considering the feedback of Kevin
> and Martin, could you please change the subject of this patch to:
>
> dt-bindings: clock: gxbb: expose UART clocks
>
> Thx
> Jerome
>
i've just sent v3 of my patchset.
(i changed the subjects of most patches in the set)
Helmut
>>
>> Kevin
>
^ permalink raw reply
* [PATCH v2 2/2] mtd: spi-nor: add driver for STM32 quad spi flash controller
From: Ludovic Barre @ 2017-03-31 17:02 UTC (permalink / raw)
To: Cyrille Pitchen, Marek Vasut
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Alexandre Torgue, Rob Herring, linux-mtd,
linux-kernel, devicetree
In-Reply-To: <1490979724-10905-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
The quadspi is a specialized communication interface targeting single,
dual or quad SPI Flash memories.
It can operate in any of the following modes:
-indirect mode: all the operations are performed using the quadspi
registers
-read memory-mapped mode: the external Flash memory is mapped to the
microcontroller address space and is seen by the system as if it was
an internal memory
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
drivers/mtd/spi-nor/Kconfig | 7 +
drivers/mtd/spi-nor/Makefile | 1 +
drivers/mtd/spi-nor/stm32-quadspi.c | 690 ++++++++++++++++++++++++++++++++++++
3 files changed, 698 insertions(+)
create mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c
diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
index 7252087..bfdfb1e 100644
--- a/drivers/mtd/spi-nor/Kconfig
+++ b/drivers/mtd/spi-nor/Kconfig
@@ -106,4 +106,11 @@ config SPI_INTEL_SPI_PLATFORM
To compile this driver as a module, choose M here: the module
will be called intel-spi-platform.
+config SPI_STM32_QUADSPI
+ tristate "STM32 Quad SPI controller"
+ depends on ARCH_STM32
+ help
+ This enables support for the STM32 Quad SPI controller.
+ We only connect the NOR to this controller.
+
endif # MTD_SPI_NOR
diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
index 72238a7..285aab8 100644
--- a/drivers/mtd/spi-nor/Makefile
+++ b/drivers/mtd/spi-nor/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_MTD_MT81xx_NOR) += mtk-quadspi.o
obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
obj-$(CONFIG_SPI_INTEL_SPI) += intel-spi.o
obj-$(CONFIG_SPI_INTEL_SPI_PLATFORM) += intel-spi-platform.o
+obj-$(CONFIG_SPI_STM32_QUADSPI) += stm32-quadspi.o
\ No newline at end of file
diff --git a/drivers/mtd/spi-nor/stm32-quadspi.c b/drivers/mtd/spi-nor/stm32-quadspi.c
new file mode 100644
index 0000000..7d26e37
--- /dev/null
+++ b/drivers/mtd/spi-nor/stm32-quadspi.c
@@ -0,0 +1,690 @@
+/*
+ * stm32_quadspi.c
+ *
+ * Copyright (C) 2017, Ludovic Barre
+ *
+ * License terms: GNU General Public License (GPL), version 2
+ */
+#include <linux/clk.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#define QUADSPI_CR 0x00
+#define CR_EN BIT(0)
+#define CR_ABORT BIT(1)
+#define CR_DMAEN BIT(2)
+#define CR_TCEN BIT(3)
+#define CR_SSHIFT BIT(4)
+#define CR_DFM BIT(6)
+#define CR_FSEL BIT(7)
+#define CR_FTHRES_SHIFT 8
+#define CR_FTHRES_MASK GENMASK(12, 8)
+#define CR_FTHRES(n) (((n) << CR_FTHRES_SHIFT) & CR_FTHRES_MASK)
+#define CR_TEIE BIT(16)
+#define CR_TCIE BIT(17)
+#define CR_FTIE BIT(18)
+#define CR_SMIE BIT(19)
+#define CR_TOIE BIT(20)
+#define CR_PRESC_SHIFT 24
+#define CR_PRESC_MASK GENMASK(31, 24)
+#define CR_PRESC(n) (((n) << CR_PRESC_SHIFT) & CR_PRESC_MASK)
+
+#define QUADSPI_DCR 0x04
+#define DCR_CSHT_SHIFT 8
+#define DCR_CSHT_MASK GENMASK(10, 8)
+#define DCR_CSHT(n) (((n) << DCR_CSHT_SHIFT) & DCR_CSHT_MASK)
+#define DCR_FSIZE_SHIFT 16
+#define DCR_FSIZE_MASK GENMASK(20, 16)
+#define DCR_FSIZE(n) (((n) << DCR_FSIZE_SHIFT) & DCR_FSIZE_MASK)
+
+#define QUADSPI_SR 0x08
+#define SR_TEF BIT(0)
+#define SR_TCF BIT(1)
+#define SR_FTF BIT(2)
+#define SR_SMF BIT(3)
+#define SR_TOF BIT(4)
+#define SR_BUSY BIT(5)
+#define SR_FLEVEL_SHIFT 8
+#define SR_FLEVEL_MASK GENMASK(13, 8)
+
+#define QUADSPI_FCR 0x0c
+#define FCR_CTCF BIT(1)
+
+#define QUADSPI_DLR 0x10
+
+#define QUADSPI_CCR 0x14
+#define CCR_INST_SHIFT 0
+#define CCR_INST_MASK GENMASK(7, 0)
+#define CCR_INST(n) (((n) << CCR_INST_SHIFT) & CCR_INST_MASK)
+#define CCR_IMODE_NONE (0 << 8)
+#define CCR_IMODE_1 (1 << 8)
+#define CCR_IMODE_2 (2 << 8)
+#define CCR_IMODE_4 (3 << 8)
+#define CCR_ADMODE_NONE (0 << 10)
+#define CCR_ADMODE_1 (1 << 10)
+#define CCR_ADMODE_2 (2 << 10)
+#define CCR_ADMODE_4 (3 << 10)
+#define CCR_ADSIZE_SHIFT 12
+#define CCR_ADSIZE_MASK GENMASK(13, 12)
+#define CCR_ADSIZE(n) (((n) << CCR_ADSIZE_SHIFT) & CCR_ADSIZE_MASK)
+#define CCR_ABMODE_NONE (0 << 14)
+#define CCR_ABMODE_1 (1 << 14)
+#define CCR_ABMODE_2 (2 << 14)
+#define CCR_ABMODE_4 (3 << 14)
+#define CCR_ABSIZE_8 (0 << 16)
+#define CCR_ABSIZE_16 (1 << 16)
+#define CCR_ABSIZE_24 (2 << 16)
+#define CCR_ABSIZE_32 (3 << 16)
+#define CCR_DCYC_SHIFT 18
+#define CCR_DCYC_MASK GENMASK(22, 18)
+#define CCR_DCYC(n) (((n) << CCR_DCYC_SHIFT) & CCR_DCYC_MASK)
+#define CCR_DMODE_NONE (0 << 24)
+#define CCR_DMODE_1 (1 << 24)
+#define CCR_DMODE_2 (2 << 24)
+#define CCR_DMODE_4 (3 << 24)
+#define CCR_FMODE_INDW (0 << 26)
+#define CCR_FMODE_INDR (1 << 26)
+#define CCR_FMODE_APM (2 << 26)
+#define CCR_FMODE_MM (3 << 26)
+
+#define QUADSPI_AR 0x18
+#define QUADSPI_ABR 0x1c
+#define QUADSPI_DR 0x20
+#define QUADSPI_PSMKR 0x24
+#define QUADSPI_PSMAR 0x28
+#define QUADSPI_PIR 0x2c
+#define QUADSPI_LPTR 0x30
+#define LPTR_DFT_TIMEOUT 0x10
+
+#define STM32_MAX_MMAP_SZ SZ_256M
+#define STM32_MAX_NORCHIP 2
+
+#define STM32_QSPI_FIFO_TIMEOUT_US 30000
+#define STM32_QSPI_BUSY_TIMEOUT_US 100000
+
+struct stm32_qspi_flash {
+ struct spi_nor nor;
+ u32 cs;
+ u32 fsize;
+ u32 presc;
+ struct stm32_qspi *qspi;
+};
+
+struct stm32_qspi {
+ struct device *dev;
+ void __iomem *io_base;
+ void __iomem *mm_base;
+ u32 nor_num;
+ struct clk *clk;
+ u32 clk_rate;
+ struct stm32_qspi_flash flash[STM32_MAX_NORCHIP];
+ u32 read_mode;
+ struct completion cmd_completion;
+
+ /*
+ * to protect device configuration, could be different between
+ * 2 flash access (bk1, bk2)
+ */
+ struct mutex lock;
+};
+
+struct stm32_qspi_cmd {
+ struct {
+ u8 addr_width;
+ u8 dummy;
+ u8 data;
+ } conf;
+
+ u8 opcode;
+ u32 framemode;
+ u32 qspimode;
+ u32 addr;
+ size_t len;
+ void *buf;
+};
+
+static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi)
+{
+ u32 cr;
+ int err = 0;
+
+ if (readl_relaxed(qspi->io_base + QUADSPI_SR) & SR_TCF)
+ return 0;
+
+ reinit_completion(&qspi->cmd_completion);
+ cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
+ writel_relaxed(cr | CR_TCIE, qspi->io_base + QUADSPI_CR);
+
+ if (!wait_for_completion_interruptible_timeout(&qspi->cmd_completion,
+ msecs_to_jiffies(1000)))
+ err = -ETIMEDOUT;
+
+ writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
+ return err;
+}
+
+static int stm32_qspi_wait_nobusy(struct stm32_qspi *qspi)
+{
+ u32 sr;
+
+ return readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR, sr,
+ !(sr & SR_BUSY), 10,
+ STM32_QSPI_BUSY_TIMEOUT_US);
+}
+
+static void stm32_qspi_set_framemode(struct spi_nor *nor,
+ struct stm32_qspi_cmd *cmd, bool read)
+{
+ u32 dmode = CCR_DMODE_1;
+
+ cmd->framemode = CCR_IMODE_1;
+
+ if (read) {
+ switch (nor->flash_read) {
+ case SPI_NOR_NORMAL:
+ case SPI_NOR_FAST:
+ dmode = CCR_DMODE_1;
+ break;
+ case SPI_NOR_DUAL:
+ dmode = CCR_DMODE_2;
+ break;
+ case SPI_NOR_QUAD:
+ dmode = CCR_DMODE_4;
+ break;
+ }
+ }
+
+ cmd->framemode |= cmd->conf.data ? dmode : 0;
+ cmd->framemode |= cmd->conf.addr_width ? CCR_ADMODE_1 : 0;
+}
+
+static void stm32_qspi_read_fifo(u8 *val, void __iomem *addr)
+{
+ *val = readb_relaxed(addr);
+}
+
+static void stm32_qspi_write_fifo(u8 *val, void __iomem *addr)
+{
+ writeb_relaxed(*val, addr);
+}
+
+static int stm32_qspi_tx_poll(struct stm32_qspi *qspi,
+ const struct stm32_qspi_cmd *cmd)
+{
+ void (*tx_fifo)(u8 *, void __iomem *);
+ u32 len = cmd->len, sr;
+ u8 *buf = cmd->buf;
+ int ret;
+
+ if (cmd->qspimode == CCR_FMODE_INDW)
+ tx_fifo = stm32_qspi_write_fifo;
+ else
+ tx_fifo = stm32_qspi_read_fifo;
+
+ while (len--) {
+ ret = readl_relaxed_poll_timeout(qspi->io_base + QUADSPI_SR,
+ sr, (sr & SR_FTF),10,
+ STM32_QSPI_FIFO_TIMEOUT_US);
+ if (ret) {
+ dev_err(qspi->dev, "fifo timeout (stat:%#x)\n", sr);
+ break;
+ }
+ tx_fifo(buf++, qspi->io_base + QUADSPI_DR);
+ }
+
+ return ret;
+}
+
+static int stm32_qspi_tx_mm(struct stm32_qspi *qspi,
+ const struct stm32_qspi_cmd *cmd)
+{
+ memcpy_fromio(cmd->buf, qspi->mm_base + cmd->addr, cmd->len);
+ return 0;
+}
+
+static int stm32_qspi_tx(struct stm32_qspi *qspi,
+ const struct stm32_qspi_cmd *cmd)
+{
+ if (!cmd->conf.data)
+ return 0;
+
+ if (cmd->qspimode == CCR_FMODE_MM)
+ return stm32_qspi_tx_mm(qspi, cmd);
+
+ return stm32_qspi_tx_poll(qspi, cmd);
+}
+
+static int stm32_qspi_send(struct stm32_qspi_flash *flash,
+ const struct stm32_qspi_cmd *cmd)
+{
+ struct stm32_qspi *qspi = flash->qspi;
+ u32 ccr, dcr, cr;
+ int err;
+
+ err = stm32_qspi_wait_nobusy(qspi);
+ if (err)
+ goto abort;
+
+ dcr = readl_relaxed(qspi->io_base + QUADSPI_DCR) & ~DCR_FSIZE_MASK;
+ dcr |= DCR_FSIZE(flash->fsize);
+ writel_relaxed(dcr, qspi->io_base + QUADSPI_DCR);
+
+ cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
+ cr &= ~CR_PRESC_MASK & ~CR_FSEL;
+ cr |= CR_PRESC(flash->presc);
+ cr |= flash->cs ? CR_FSEL : 0;
+ writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
+
+ if (cmd->conf.data)
+ writel_relaxed(cmd->len - 1, qspi->io_base + QUADSPI_DLR);
+
+ ccr = cmd->framemode | cmd->qspimode;
+
+ if (cmd->conf.dummy)
+ ccr |= CCR_DCYC(cmd->conf.dummy);
+
+ if (cmd->conf.addr_width)
+ ccr |= CCR_ADSIZE(cmd->conf.addr_width - 1);
+
+ ccr |= CCR_INST(cmd->opcode);
+ writel_relaxed(ccr, qspi->io_base + QUADSPI_CCR);
+
+ if (cmd->conf.addr_width && cmd->qspimode != CCR_FMODE_MM)
+ writel_relaxed(cmd->addr, qspi->io_base + QUADSPI_AR);
+
+ err = stm32_qspi_tx(qspi, cmd);
+ if (err)
+ goto abort;
+
+ if (cmd->qspimode != CCR_FMODE_MM) {
+ err = stm32_qspi_wait_cmd(qspi);
+ if (err)
+ goto abort;
+ writel_relaxed(FCR_CTCF, qspi->io_base + QUADSPI_FCR);
+ }
+
+ return err;
+
+abort:
+ cr = readl_relaxed(qspi->io_base + QUADSPI_CR) | CR_ABORT;
+ writel_relaxed(cr, qspi->io_base + QUADSPI_CR);
+
+ dev_err(qspi->dev, "%s abort err:%d\n", __func__, err);
+ return err;
+}
+
+static int stm32_qspi_read_reg(struct spi_nor *nor,
+ u8 opcode, u8 *buf, int len)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct device *dev = flash->qspi->dev;
+ struct stm32_qspi_cmd cmd;
+
+ dev_dbg(dev, "read_reg: cmd:%.2x buf:%p len:%d\n", opcode, buf, len);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = opcode;
+ cmd.conf.data = 1;
+ cmd.len = len;
+ cmd.buf = buf;
+ cmd.qspimode = CCR_FMODE_INDR;
+
+ stm32_qspi_set_framemode(nor, &cmd, false);
+
+ return stm32_qspi_send(flash, &cmd);
+}
+
+static int stm32_qspi_write_reg(struct spi_nor *nor, u8 opcode,
+ u8 *buf, int len)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct device *dev = flash->qspi->dev;
+ struct stm32_qspi_cmd cmd;
+
+ dev_dbg(dev, "write_reg: cmd:%.2x buf:%p len:%d\n", opcode, buf, len);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = opcode;
+ cmd.conf.data = (buf && len > 0);
+ cmd.len = len;
+ cmd.buf = buf;
+ cmd.qspimode = CCR_FMODE_INDW;
+
+ stm32_qspi_set_framemode(nor, &cmd, false);
+
+ return stm32_qspi_send(flash, &cmd);
+}
+
+static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from, size_t len,
+ u_char *buf)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct stm32_qspi *qspi = flash->qspi;
+ struct stm32_qspi_cmd cmd;
+ int err;
+
+ dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
+ nor->read_opcode, buf, (u32)from, len);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = nor->read_opcode;
+ cmd.conf.addr_width = nor->addr_width;
+ cmd.addr = (u32)from;
+ cmd.conf.data = 1;
+ cmd.conf.dummy = nor->read_dummy;
+ cmd.len = len;
+ cmd.buf = buf;
+ cmd.qspimode = qspi->read_mode;
+
+ stm32_qspi_set_framemode(nor, &cmd, true);
+ err = stm32_qspi_send(flash, &cmd);
+
+ return err ? err : len;
+}
+
+static ssize_t stm32_qspi_write(struct spi_nor *nor, loff_t to, size_t len,
+ const u_char *buf)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct device *dev = flash->qspi->dev;
+ struct stm32_qspi_cmd cmd;
+ int err;
+
+ dev_dbg(dev, "write(%#.2x): buf:%p to:%#.8x len:%#x\n",
+ nor->program_opcode, buf, (u32)to, len);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = nor->program_opcode;
+ cmd.conf.addr_width = nor->addr_width;
+ cmd.addr = (u32)to;
+ cmd.conf.data = 1;
+ cmd.len = len;
+ cmd.buf = (void *)buf;
+ cmd.qspimode = CCR_FMODE_INDW;
+
+ stm32_qspi_set_framemode(nor, &cmd, false);
+ err = stm32_qspi_send(flash, &cmd);
+
+ return err ? err : len;
+}
+
+static int stm32_qspi_erase(struct spi_nor *nor, loff_t offs)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct device *dev = flash->qspi->dev;
+ struct stm32_qspi_cmd cmd;
+
+ dev_dbg(dev, "erase(%#.2x):offs:%#x\n", nor->erase_opcode, (u32)offs);
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.opcode = nor->erase_opcode;
+ cmd.conf.addr_width = nor->addr_width;
+ cmd.addr = (u32)offs;
+ cmd.qspimode = CCR_FMODE_INDW;
+
+ stm32_qspi_set_framemode(nor, &cmd, false);
+
+ return stm32_qspi_send(flash, &cmd);
+}
+
+static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
+{
+ struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
+ u32 cr, sr, fcr = 0;
+
+ cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
+ sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
+
+ if ((cr & CR_TCIE) && (sr & SR_TCF)) {
+ /* tx complete */
+ fcr |= FCR_CTCF;
+ complete(&qspi->cmd_completion);
+ } else {
+ dev_info(qspi->dev, "spurious interrupt\n");
+ }
+
+ writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
+
+ return IRQ_HANDLED;
+}
+
+static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct stm32_qspi *qspi = flash->qspi;
+
+ mutex_lock(&qspi->lock);
+ return 0;
+}
+
+static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops ops)
+{
+ struct stm32_qspi_flash *flash = nor->priv;
+ struct stm32_qspi *qspi = flash->qspi;
+
+ mutex_unlock(&qspi->lock);
+}
+
+static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
+ struct device_node *np)
+{
+ u32 width, flash_read, presc, cs_num, max_rate = 0;
+ struct stm32_qspi_flash *flash;
+ struct mtd_info *mtd;
+ int ret;
+
+ of_property_read_u32(np, "reg", &cs_num);
+ if (cs_num >= STM32_MAX_NORCHIP)
+ return -EINVAL;
+
+ of_property_read_u32(np, "spi-max-frequency", &max_rate);
+ if (!max_rate)
+ return -EINVAL;
+
+ presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
+
+ if (of_property_read_u32(np, "spi-rx-bus-width", &width))
+ width = 1;
+
+ if (width == 4)
+ flash_read = SPI_NOR_QUAD;
+ else if (width == 2)
+ flash_read = SPI_NOR_DUAL;
+ else if (width == 1)
+ flash_read = SPI_NOR_NORMAL;
+ else
+ return -EINVAL;
+
+ flash = &qspi->flash[cs_num];
+ flash->qspi = qspi;
+ flash->cs = cs_num;
+ flash->presc = presc;
+
+ flash->nor.dev = qspi->dev;
+ spi_nor_set_flash_node(&flash->nor, np);
+ flash->nor.priv = flash;
+ mtd = &flash->nor.mtd;
+ mtd->priv = &flash->nor;
+
+ flash->nor.read = stm32_qspi_read;
+ flash->nor.write = stm32_qspi_write;
+ flash->nor.erase = stm32_qspi_erase;
+ flash->nor.read_reg = stm32_qspi_read_reg;
+ flash->nor.write_reg = stm32_qspi_write_reg;
+ flash->nor.prepare = stm32_qspi_prep;
+ flash->nor.unprepare = stm32_qspi_unprep;
+
+ writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
+
+ writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
+ | CR_EN, qspi->io_base + QUADSPI_CR);
+
+ /*
+ * in stm32 qspi controller, QUADSPI_DCR register has a fsize field
+ * which define the size of nor flash.
+ * if fsize is NULL, the controller can't sent spi-nor command.
+ * set a temporary value just to discover the nor flash with
+ * "spi_nor_scan". After, the right value (mtd->size) can be set.
+ */
+ flash->fsize = 25;
+
+ ret = spi_nor_scan(&flash->nor, NULL, flash_read);
+ if (ret) {
+ dev_err(qspi->dev, "device scan failed\n");
+ return ret;
+ }
+
+ /* number of bytes in Flash memory = 2^[FSIZE+1] */
+ flash->fsize = __fls(mtd->size) - 1;
+
+ writel_relaxed(DCR_CSHT(1), qspi->io_base + QUADSPI_DCR);
+
+ ret = mtd_device_register(mtd, NULL, 0);
+ if (ret) {
+ dev_err(qspi->dev, "mtd device parse failed\n");
+ return ret;
+ }
+
+ dev_dbg(qspi->dev, "read mm:%s cs:%d bus:%d\n",
+ qspi->read_mode == CCR_FMODE_MM ? "yes" : "no", cs_num, width);
+
+ return 0;
+}
+
+static void stm32_qspi_mtd_free(struct stm32_qspi *qspi)
+{
+ int i;
+
+ for (i = 0; i < STM32_MAX_NORCHIP; i++) {
+ if (qspi->flash[i].qspi)
+ mtd_device_unregister(&qspi->flash[i].nor.mtd);
+ }
+}
+
+static int stm32_qspi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *flash_np;
+ struct reset_control *rstc;
+ struct stm32_qspi *qspi;
+ struct resource *res;
+ int ret, irq;
+
+ qspi = devm_kzalloc(dev, sizeof(*qspi), GFP_KERNEL);
+ if (!qspi)
+ return -ENOMEM;
+
+ qspi->nor_num = of_get_child_count(dev->of_node);
+ if (!qspi->nor_num || qspi->nor_num > STM32_MAX_NORCHIP)
+ return -ENODEV;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi");
+ qspi->io_base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(qspi->io_base))
+ return PTR_ERR(qspi->io_base);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qspi_mm");
+ if (res && resource_size(res) <= STM32_MAX_MMAP_SZ)
+ qspi->mm_base = devm_ioremap_resource(dev, res);
+
+ qspi->read_mode = IS_ERR_OR_NULL(qspi->mm_base) ?
+ CCR_FMODE_INDR : CCR_FMODE_MM;
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, stm32_qspi_irq, 0,
+ dev_name(dev), qspi);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ return ret;
+ }
+
+ init_completion(&qspi->cmd_completion);
+
+ qspi->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(qspi->clk))
+ return PTR_ERR(qspi->clk);
+
+ qspi->clk_rate = clk_get_rate(qspi->clk);
+ if (!qspi->clk_rate)
+ return -EINVAL;
+
+ ret = clk_prepare_enable(qspi->clk);
+ if (ret) {
+ dev_err(dev, "can not enable the clock\n");
+ return ret;
+ }
+
+ rstc = devm_reset_control_get(dev, NULL);
+ if (!IS_ERR(rstc)) {
+ reset_control_assert(rstc);
+ udelay(2);
+ reset_control_deassert(rstc);
+ }
+
+ qspi->dev = dev;
+ platform_set_drvdata(pdev, qspi);
+ mutex_init(&qspi->lock);
+
+ for_each_available_child_of_node(dev->of_node, flash_np) {
+ ret = stm32_qspi_flash_setup(qspi, flash_np);
+ if (ret) {
+ dev_err(dev, "unable to setup flash chip\n");
+ goto err_flash;
+ }
+ }
+
+ return 0;
+
+err_flash:
+ mutex_destroy(&qspi->lock);
+ stm32_qspi_mtd_free(qspi);
+
+ clk_disable_unprepare(qspi->clk);
+ return ret;
+}
+
+static int stm32_qspi_remove(struct platform_device *pdev)
+{
+ struct stm32_qspi *qspi = platform_get_drvdata(pdev);
+
+ /* disable qspi */
+ writel_relaxed(0, qspi->io_base + QUADSPI_CR);
+
+ stm32_qspi_mtd_free(qspi);
+ mutex_destroy(&qspi->lock);
+
+ clk_disable_unprepare(qspi->clk);
+ return 0;
+}
+
+static const struct of_device_id stm32_qspi_match[] = {
+ {.compatible = "st,stm32f469-qspi"},
+ {}
+};
+MODULE_DEVICE_TABLE(of, stm32_qspi_match);
+
+static struct platform_driver stm32_qspi_driver = {
+ .probe = stm32_qspi_probe,
+ .remove = stm32_qspi_remove,
+ .driver = {
+ .name = "stm32-quadspi",
+ .of_match_table = stm32_qspi_match,
+ },
+};
+module_platform_driver(stm32_qspi_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 quad spi driver");
+MODULE_LICENSE("GPL v2");
--
2.7.4
^ permalink raw reply related
* [PATCH v2 1/2] dt-bindings: Document the STM32 QSPI bindings
From: Ludovic Barre @ 2017-03-31 17:02 UTC (permalink / raw)
To: Cyrille Pitchen, Marek Vasut
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Alexandre Torgue, Rob Herring, linux-mtd,
linux-kernel, devicetree
In-Reply-To: <1490979724-10905-1-git-send-email-ludovic.Barre@st.com>
From: Ludovic Barre <ludovic.barre@st.com>
This patch adds documentation of device tree bindings for the STM32
QSPI controller.
Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
---
.../devicetree/bindings/mtd/stm32-quadspi.txt | 45 ++++++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
diff --git a/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
new file mode 100644
index 0000000..95a8ebd
--- /dev/null
+++ b/Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
@@ -0,0 +1,45 @@
+* STMicroelectronics Quad Serial Peripheral Interface(QuadSPI)
+
+Required properties:
+- compatible: should be "st,stm32f469-qspi"
+- reg: contains the register location and length.
+ (optional) the memory mapping address and length
+- reg-names: list of the names corresponding to the previous register
+ Should contain "qspi" to register location
+ (optional) "qspi_mm" if read in memory map mode (improve read throughput)
+- interrupts: should contain the interrupt for the device
+- clocks: the phandle of the clock needed by the QSPI controller
+- A pinctrl must be defined to set pins in mode of operation for QSPI transfer
+
+Optional properties:
+- resets: must contain the phandle to the reset controller.
+
+A spi flash must be a child of the nor_flash node and could have some
+properties. Also see jedec,spi-nor.txt.
+
+Required properties:
+- reg: chip-Select number (QSPI controller may connect 2 nor flashes)
+- spi-max-frequency: max frequency of spi bus
+
+Optional property:
+- spi-rx-bus-width: the bus width (number of data wires)
+
+Example:
+
+qspi: qspi@a0001000 {
+ compatible = "st,stm32f469-qspi";
+ reg = <0xa0001000 0x1000>, <0x90000000 0x10000000>;
+ reg-names = "qspi", "qspi_mm";
+ interrupts = <91>;
+ resets = <&rcc STM32F4_AHB3_RESET(QSPI)>;
+ clocks = <&rcc 0 STM32F4_AHB3_CLOCK(QSPI)>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_qspi0>;
+
+ flash@0 {
+ reg = <0>;
+ spi-rx-bus-width = <4>;
+ spi-max-frequency = <108000000>;
+ ...
+ };
+};
--
2.7.4
^ permalink raw reply related
* [PATCH v2 0/2] mtd: spi-nor: add stm32 qspi driver
From: Ludovic Barre @ 2017-03-31 17:02 UTC (permalink / raw)
To: Cyrille Pitchen, Marek Vasut
Cc: David Woodhouse, Brian Norris, Boris Brezillon,
Richard Weinberger, Alexandre Torgue, Rob Herring,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
devicetree-u79uwXL29TY76Z2rM5mHXA
From: Ludovic Barre <ludovic.barre-qxv4g6HH51o@public.gmane.org>
This patch set adds a SPI-NOR driver for stm32 QSPI controller.
It is a specialized SPI interface for serial Flash devices.
It supports 1 or 2 Flash device with single, dual and quad SPI Flash memories.
It can operate in any of the following modes:
-indirect mode: all the operations are performed using the quadspi
registers
-read memory-mapped mode: the external Flash memory is mapped to the
microcontroller address space and is seen by the system as if it was
an internal memory
Marek, Cyrille
How do you wish process?
If this patch set is OK for you, I agree for the merge
Cyrille, I working on rebase
[PATCH v5 0/6] mtd: spi-nor: parse SFDP tables to setup (Q)SPI memories
I could send a patch for stm32 as soon as possible, like this you could add my
controller into your patchset. I would be glad to be your stm32 tester :-)
Changes in v2:
-awful construct: s/u32/u8
-add define for timeout
-Use a helper variable
-add comment on "stm32 qspi controller fsize issue"
Ludovic Barre (2):
dt-bindings: Document the STM32 QSPI bindings
mtd: spi-nor: add driver for STM32 quad spi flash controller
.../devicetree/bindings/mtd/stm32-quadspi.txt | 45 ++
drivers/mtd/spi-nor/Kconfig | 7 +
drivers/mtd/spi-nor/Makefile | 1 +
drivers/mtd/spi-nor/stm32-quadspi.c | 690 +++++++++++++++++++++
4 files changed, 743 insertions(+)
create mode 100644 Documentation/devicetree/bindings/mtd/stm32-quadspi.txt
create mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c
--
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
* Re: [PATCH] OF: mark released devices as no longer populated
From: Rob Herring @ 2017-03-31 16:59 UTC (permalink / raw)
To: Horia Geantă
Cc: Russell King - ARM Linux, Fabio Estevam, Frank Rowand,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-crypto-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Dan Douglass
In-Reply-To: <VI1PR0401MB2591E5FD962023914F042C9B98370-9IDQY6o3qQhGNIhRVge97I3W/0Ik+aLCnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
On Fri, Mar 31, 2017 at 10:23 AM, Horia Geantă <horia.geanta-3arQi8VN3Tc@public.gmane.org> wrote:
> On 3/31/2017 1:40 PM, Russell King - ARM Linux wrote:
>> Ping, this issue still exists with 4.11-rc4 - and there's been no
>> reaction from the alleged CAAM maintainers.
>>
> Sorry, this somehow slipped through (Cc vs. To, no linux-crypto).
>
>> On Tue, Aug 09, 2016 at 11:48:38AM -0500, Rob Herring wrote:
>>> On Tue, Aug 9, 2016 at 4:33 AM, Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> wrote:
>>>> When a Linux device is released and cleaned up, we left the OF device
>>>> node marked as populated. This causes the Freescale CAAM driver
>>>> (drivers/crypto/caam) problems when the module is removed and re-
>>>> inserted:
>>>>
>>>> JR0 Platform device creation error
>>>> JR0 Platform device creation error
>>>> caam 2100000.caam: no queues configured, terminating
>>>> caam: probe of 2100000.caam failed with error -12
>>>>
>>>> The reason is that CAAM creates platform devices for each job ring:
>>>>
>>>> for_each_available_child_of_node(nprop, np)
>>>> if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
>>>> of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
>>>> ctrlpriv->jrpdev[ring] =
>>>> of_platform_device_create(np, NULL, dev);
>>>>
>>>> which sets OF_POPULATED on the device node, but then it cleans these
>>>> up:
>>>>
>>>> /* Remove platform devices for JobRs */
>>>> for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
>>>> if (ctrlpriv->jrpdev[ring])
>>>> of_device_unregister(ctrlpriv->jrpdev[ring]);
>>>
>>> This looks a bit asymmetrical to me with a of_platform_device_* call
>>> and a of_device_* call.
>>>
>>> I think you could use of_platform_{de}populate here instead. That
>>> would simplify things in the driver a bit too as you wouldn't need to
>>> store jrpdev. It wouldn't work if there are other child nodes with
> Indeed, this would clean-up the driver a bit. However, the driver needs
> to know how many of the devices probed successfully - to print the
> number and more importantly to exit in case total_jobrs = 0.
The only thing you are guaranteed is the OF code created some platform
devices. That's it. Whether any driver probed successfully is separate
and a lot more things can go wrong there. The only thing you are
checking is that your dtb is not crap.
> Thus, I would keep the one-by-one probing of the devices.
> What options are there in this case?
> Should a function symmetric to of_platform_device_create() be added - to
> replace of_device_unregister() - or rely on an open-coded solution?
Certainly not the latter. We don't want drivers mucking with flags
internal to the DT code.
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
* Re: [PATCH] arm64: dts: rk3399: add support for firefly-rk3399 board
From: Andreas Färber @ 2017-03-31 16:59 UTC (permalink / raw)
To: Kever Yang
Cc: Heiko Stuebner, linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA, Jianqun Xu,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Andy Yan, Rob Herring,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Will Deacon,
Mark Rutland, Catalin Marinas, Matthias Brugger
In-Reply-To: <1860080.ebfBDdk4Fv@phil>
Hi,
Am 31.03.2017 um 14:56 schrieb Heiko Stuebner:
> Hi Kever,
>
> Am Freitag, 31. März 2017, 17:59:07 CEST schrieb Kever Yang:
>> Firefly-rk3399 is a bord from T-Firefly, you can find detail about
>> it here:
>> http://en.t-firefly.com/en/firenow/Firefly_RK3399/
>>
>> This patch add basic node for the board and make it able to bring
>> up.
>
> This more a first glance, I didn't check every binding, but already found
> some dubious ones, so in general, please make sure to only include nodes
> with approved bindings.
>
>
> [...]
>
>> arch/arm64/boot/dts/rockchip/Makefile | 1 +
>> arch/arm64/boot/dts/rockchip/rk3399-firefly.dts | 772 ++++++++++++++++++++++++
>
> please provide a binding addition for the board in a separate patch as well.
>
>
>> 2 files changed, 773 insertions(+)
>> create mode 100644 arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/Makefile b/arch/arm64/boot/dts/rockchip/Makefile
>> index 3a86289..dd3d550 100644
>> --- a/arch/arm64/boot/dts/rockchip/Makefile
>> +++ b/arch/arm64/boot/dts/rockchip/Makefile
>> @@ -4,6 +4,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-orion-r68-meta.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-px5-evb.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3368-r88.dtb
>> dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-evb.dtb
>> +dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3399-firefly.dtb
>
> if possible, please rebase on top of my for-next branch, as we also
> have the first gru board in there now.
>
>>
>> always := $(dtb-y)
>> subdir-y := $(dts-dirs)
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
>> new file mode 100644
>> index 0000000..686977b
>> --- /dev/null
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399-firefly.dts
>> @@ -0,0 +1,772 @@
>> +/*
>> + * Copyright (c) 2017 Fuzhou Rockchip Electronics Co., Ltd
"Ltd."?
>> + *
>> + * This file is dual-licensed: you can use it either under the terms
>> + * of the GPL or the X11 license, at your option. Note that this dual
>> + * licensing only applies to this file, and not this project as a
>> + * whole.
>> + *
>> + * a) This file is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation; either version 2 of the
>> + * License, or (at your option) any later version.
>> + *
>> + * This file is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + *
>> + * Or, alternatively,
>> + *
>> + * b) Permission is hereby granted, free of charge, to any person
>> + * obtaining a copy of this software and associated documentation
>> + * files (the "Software"), to deal in the Software without
>> + * restriction, including without limitation the rights to use,
>> + * copy, modify, merge, publish, distribute, sublicense, and/or
>> + * sell copies of the Software, and to permit persons to whom the
>> + * Software is furnished to do so, subject to the following
>> + * conditions:
>> + *
>> + * The above copyright notice and this permission notice shall be
>> + * included in all copies or substantial portions of the Software.
>> + *
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
>> + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
>> + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
>> + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
>> + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
>> + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
>> + * OTHER DEALINGS IN THE SOFTWARE.
This should be shorter: "SPDX-License-Identifier: GPL-2.0+ OR MIT"
>> + */
>> +
>> +/dts-v1/;
>> +#include <dt-bindings/pwm/pwm.h>
>> +#include "rk3399.dtsi"
>> +
>> +/ {
>> + model = "Rockchip RK3399 Firefly Board (Linux Opensource)";
"(Linux Opensource)" is not a hardware description, please drop.
>> + compatible = "rockchip,rk3399-firefly-linux", "rockchip,rk3399";
>
> Just to make sure, is this really a Rockchip board? I would've expected
> to see something like "firefly,firefly-rk3399" here, like on the rk3288-
> variant. Not a requirement, just a question to clarify who designed the
> board please :-) .
+1, especially no -linux suffix please. The same device tree should in
theory be usable with Linux, Android, FreeBSD or any other OS with
drivers based on the official bindings.
>> +
>> + backlight: backlight {
>> + status = "okay";
>> + compatible = "pwm-backlight";
>> + enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
>> + pwms = <&pwm0 0 25000 0>;
>> + brightness-levels = <
>> + 0 1 2 3 4 5 6 7
>> + 8 9 10 11 12 13 14 15
>> + 16 17 18 19 20 21 22 23
>> + 24 25 26 27 28 29 30 31
>> + 32 33 34 35 36 37 38 39
>> + 40 41 42 43 44 45 46 47
>> + 48 49 50 51 52 53 54 55
>> + 56 57 58 59 60 61 62 63
>> + 64 65 66 67 68 69 70 71
>> + 72 73 74 75 76 77 78 79
>> + 80 81 82 83 84 85 86 87
>> + 88 89 90 91 92 93 94 95
>> + 96 97 98 99 100 101 102 103
>> + 104 105 106 107 108 109 110 111
>> + 112 113 114 115 116 117 118 119
>> + 120 121 122 123 124 125 126 127
>> + 128 129 130 131 132 133 134 135
>> + 136 137 138 139 140 141 142 143
>> + 144 145 146 147 148 149 150 151
>> + 152 153 154 155 156 157 158 159
>> + 160 161 162 163 164 165 166 167
>> + 168 169 170 171 172 173 174 175
>> + 176 177 178 179 180 181 182 183
>> + 184 185 186 187 188 189 190 191
>> + 192 193 194 195 196 197 198 199
>> + 200 201 202 203 204 205 206 207
>> + 208 209 210 211 212 213 214 215
>> + 216 217 218 219 220 221 222 223
>> + 224 225 226 227 228 229 230 231
>> + 232 233 234 235 236 237 238 239
>> + 240 241 242 243 244 245 246 247
>> + 248 249 250 251 252 253 254 255>;
>> + default-brightness-level = <200>;
>> + };
>> +
>> + clkin_gmac: external-gmac-clock {
>> + compatible = "fixed-clock";
>> + clock-frequency = <125000000>;
>> + clock-output-names = "clkin_gmac";
>> + #clock-cells = <0>;
>> + };
>> +
>> + rt5640-sound {
Drop rt5640- node prefix, or is there more than one?
>> + compatible = "simple-audio-card";
>> + simple-audio-card,format = "i2s";
>> + simple-audio-card,name = "rockchip,rt5640-codec";
>> + simple-audio-card,mclk-fs = <256>;
>> + simple-audio-card,widgets =
>> + "Microphone", "Mic Jack",
>> + "Headphone", "Headphone Jack";
>> + simple-audio-card,routing =
>> + "Mic Jack", "MICBIAS1",
>> + "IN1P", "Mic Jack",
>> + "Headphone Jack", "HPOL",
>> + "Headphone Jack", "HPOR";
>> + simple-audio-card,cpu {
>> + sound-dai = <&i2s1>;
>> + };
>> + simple-audio-card,codec {
>> + sound-dai = <&rt5640>;
>> + };
Insert while lines before these two nodes for readability?
>> + };
>> +
>> + sdio_pwrseq: sdio-pwrseq {
>> + compatible = "mmc-pwrseq-simple";
>> + clocks = <&rk808 1>;
>> + clock-names = "ext_clock";
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&wifi_enable_h>;
>> +
>> + /*
>> + * On the module itself this is one of these (depending
>> + * on the actual card populated):
>> + * - SDIO_RESET_L_WL_REG_ON
>> + * - PDN (power down when low)
>> + */
>> + reset-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>; /* GPIO0_B2 */
>
> Thanks to Andy's persistence, we have nice constants in the pinctrl-
> binding-header now, like RK_PB2 for the above. So you can drop the
> comment and use the constant instead for easier reading.
> Same for other pins.
>
>
>> + };
>> +
>> + vcc3v3_pcie: vcc3v3-pcie-regulator {
>> + compatible = "regulator-fixed";
>> + enable-active-high;
>> + regulator-always-on;
>> + regulator-boot-on;
>> + gpio = <&gpio1 17 GPIO_ACTIVE_HIGH>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&pcie_drv>;
>> + regulator-name = "vcc3v3_pcie";
>> + };
>> +
>> + vcc3v3_sys: vcc3v3-sys {
>> + compatible = "regulator-fixed";
>> + regulator-name = "vcc3v3_sys";
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3300000>;
>> + regulator-max-microvolt = <3300000>;
>> + };
>> +
>> + vcc5v0_host: vcc5v0-host-regulator {
>> + compatible = "regulator-fixed";
>> + enable-active-high;
>> + gpio = <&gpio1 0 GPIO_ACTIVE_HIGH>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&host_vbus_drv>;
>> + regulator-name = "vcc5v0_host";
>> + regulator-always-on;
>> + };
>> +
>> + vcc5v0_sys: vcc5v0-sys {
>> + compatible = "regulator-fixed";
>> + regulator-name = "vcc5v0_sys";
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <5000000>;
>> + regulator-max-microvolt = <5000000>;
>> + };
>> +
>> + vcc_phy: vcc-phy-regulator {
>> + compatible = "regulator-fixed";
>> + regulator-name = "vcc_phy";
>> + regulator-always-on;
>> + regulator-boot-on;
>> + };
>> +
>> + vdd_log: vdd-log {
>> + compatible = "pwm-regulator";
>> + pwms = <&pwm2 0 25000 1>;
>> + regulator-name = "vdd_log";
>> + regulator-min-microvolt = <800000>;
>> + regulator-max-microvolt = <1400000>;
>> + regulator-always-on;
>> + regulator-boot-on;
>> +
>> + /* for rockchip boot on */
>> + rockchip,pwm_id= <2>;
>> + rockchip,pwm_voltage = <1000000>;
>> + };
>> +
>> + vccadc_ref: vccadc-ref {
>> + compatible = "regulator-fixed";
>> + regulator-name = "vcc1v8_sys";
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + };
>> +
>> + wireless-wlan {
>> + compatible = "wlan-platdata";
>> + rockchip,grf = <&grf>;
>> + wifi_chip_type = "ap6354";
>> + sdio_vref = <1800>;
>> + WIFI,host_wake_irq = <&gpio0 3 GPIO_ACTIVE_HIGH>; /* GPIO0_a3 */
>> + status = "okay";
>
> that is not a valid binding, am I right? ;-)
> So should be dropped.
... or should be replaced by the proper binding (brcmfmac probably?).
>
>> + };
>> +
>> + wireless-bluetooth {
>> + compatible = "bluetooth-platdata";
>> + //wifi-bt-power-toggle;
>> + uart_rts_gpios = <&gpio2 19 GPIO_ACTIVE_LOW>; /* GPIO2_C3 */
>> + pinctrl-names = "default", "rts_gpio";
>> + pinctrl-0 = <&uart0_rts>;
>> + pinctrl-1 = <&uart0_gpios>;
>> + //BT,power_gpio = <&gpio3 19 GPIO_ACTIVE_HIGH>; /* GPIOx_xx */
>> + BT,reset_gpio = <&gpio0 9 GPIO_ACTIVE_HIGH>; /* GPIO0_B1 */
>> + BT,wake_gpio = <&gpio2 26 GPIO_ACTIVE_HIGH>; /* GPIO2_D2 */
>> + BT,wake_host_irq = <&gpio0 4 GPIO_ACTIVE_HIGH>; /* GPIO0_A4 */
>> + status = "okay";
>> + };
>
> same here
Move to corresponding uart node? (serdev bindings)
>> +};
>> +
>> +&cpu_l0 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l1 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l2 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_l3 {
>> + cpu-supply = <&vdd_cpu_l>;
>> +};
>> +
>> +&cpu_b0 {
>> + cpu-supply = <&vdd_cpu_b>;
>> +};
>> +
>> +&cpu_b1 {
>> + cpu-supply = <&vdd_cpu_b>;
>> +};
>> +
>> +&emmc_phy {
>> + status = "okay";
>> +};
>> +
>> +&gmac {
>> + assigned-clocks = <&cru SCLK_RMII_SRC>;
>> + assigned-clock-parents = <&clkin_gmac>;
>> + clock_in_out = "input";
>> + phy-supply = <&vcc_phy>;
>> + phy-mode = "rgmii";
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&rgmii_pins>;
>> + snps,reset-gpio = <&gpio3 15 GPIO_ACTIVE_LOW>;
>> + snps,reset-active-low;
>> + snps,reset-delays-us = <0 10000 50000>;
>> + tx_delay = <0x28>;
>> + rx_delay = <0x11>;
>> + status = "okay";
>> +};
>> +
>> +&i2c0 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <168>;
>> + i2c-scl-falling-time-ns = <4>;
>> + clock-frequency = <400000>;
>> +
>> + vdd_cpu_b: syr827@40 {
Node name should not duplicate the model. pmic@40?
>> + compatible = "silergy,syr827";
>> + reg = <0x40>;
>> + vin-supply = <&vcc5v0_sys>;
>> + regulator-compatible = "fan53555-reg";
>> + regulator-name = "vdd_cpu_b";
>> + regulator-min-microvolt = <712500>;
>> + regulator-max-microvolt = <1500000>;
>> + regulator-ramp-delay = <1000>;
>> + vsel-gpios = <&gpio1 18 GPIO_ACTIVE_HIGH>;
>> + fcs,suspend-voltage-selector = <0>;
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-initial-state = <3>;
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vdd_gpu: syr828@41 {
Ditto.
>> + compatible = "silergy,syr828";
>> + reg = <0x41>;
>> + vin-supply = <&vcc5v0_sys>;
>> + regulator-compatible = "fan53555-reg";
>> + regulator-name = "vdd_gpu";
>> + regulator-min-microvolt = <712500>;
>> + regulator-max-microvolt = <1500000>;
>> + regulator-ramp-delay = <1000>;
>> + fcs,suspend-voltage-selector = <1>;
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-initial-state = <3>;
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + rk808: pmic@1b {
Sort order: Any reason that 1b is after 40, 41?
>> + compatible = "rockchip,rk808";
>> + reg = <0x1b>;
>> + interrupt-parent = <&gpio1>;
>> + interrupts = <21 IRQ_TYPE_LEVEL_LOW>;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&pmic_int_l>;
>> + rockchip,system-power-controller;
>> + wakeup-source;
>> + #clock-cells = <1>;
>> + clock-output-names = "xin32k", "rk808-clkout2";
>> +
>> + vcc1-supply = <&vcc3v3_sys>;
>> + vcc2-supply = <&vcc3v3_sys>;
>> + vcc3-supply = <&vcc3v3_sys>;
>> + vcc4-supply = <&vcc3v3_sys>;
>> + vcc6-supply = <&vcc3v3_sys>;
>> + vcc7-supply = <&vcc3v3_sys>;
>> + vcc8-supply = <&vcc3v3_sys>;
>> + vcc9-supply = <&vcc3v3_sys>;
>> + vcc10-supply = <&vcc3v3_sys>;
>> + vcc11-supply = <&vcc3v3_sys>;
>> + vcc12-supply = <&vcc3v3_sys>;
>> + vddio-supply = <&vcc1v8_pmu>;
>> +
>> + regulators {
>> + vdd_center: DCDC_REG1 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <750000>;
>> + regulator-max-microvolt = <1350000>;
>> + regulator-ramp-delay = <6001>;
>> + regulator-name = "vdd_center";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vdd_cpu_l: DCDC_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <750000>;
>> + regulator-max-microvolt = <1350000>;
>> + regulator-ramp-delay = <6001>;
>> + regulator-name = "vdd_cpu_l";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_ddr: DCDC_REG3 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-name = "vcc_ddr";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + };
>> + };
>> +
>> + vcc_1v8: DCDC_REG4 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + regulator-name = "vcc_1v8";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <1800000>;
>> + };
>> + };
>> +
>> + vcc1v8_dvp: LDO_REG1 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + regulator-name = "vcc1v8_dvp";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc3v0_tp: LDO_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3000000>;
>> + regulator-max-microvolt = <3000000>;
>> + regulator-name = "vcc3v0_tp";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc1v8_pmu: LDO_REG3 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + regulator-name = "vcc1v8_pmu";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <1800000>;
>> + };
>> + };
>> +
>> + vcc_sd: LDO_REG4 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <3300000>;
>> + regulator-name = "vcc_sd";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <3300000>;
>> + };
>> + };
>> +
>> + vcca3v0_codec: LDO_REG5 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3000000>;
>> + regulator-max-microvolt = <3000000>;
>> + regulator-name = "vcca3v0_codec";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_1v5: LDO_REG6 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1500000>;
>> + regulator-max-microvolt = <1500000>;
>> + regulator-name = "vcc_1v5";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <1500000>;
>> + };
>> + };
>> +
>> + vcca1v8_codec: LDO_REG7 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <1800000>;
>> + regulator-max-microvolt = <1800000>;
>> + regulator-name = "vcca1v8_codec";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc_3v0: LDO_REG8 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-min-microvolt = <3000000>;
>> + regulator-max-microvolt = <3000000>;
>> + regulator-name = "vcc_3v0";
>> + regulator-state-mem {
>> + regulator-on-in-suspend;
>> + regulator-suspend-microvolt = <3000000>;
>> + };
>> + };
>> +
>> + vcc3v3_s3: SWITCH_REG1 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-name = "vcc3v3_s3";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> +
>> + vcc3v3_s0: SWITCH_REG2 {
>> + regulator-always-on;
>> + regulator-boot-on;
>> + regulator-name = "vcc3v3_s0";
>> + regulator-state-mem {
>> + regulator-off-in-suspend;
>> + };
>> + };
>> + };
>> + };
>> +};
>> +
>> +&i2c1 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <300>;
>> + i2c-scl-falling-time-ns = <15>;
>> +
>> + gsl3673: gsl3673@40 {
Node name?
>> + compatible = "GSL,GSL3673";
>> + reg = <0x40>;
>> + screen_max_x = <1536>;
>> + screen_max_y = <2048>;
>> + irq_gpio_number = <&gpio1 20 IRQ_TYPE_LEVEL_LOW>;
>> + rst_gpio_number = <&gpio4 22 GPIO_ACTIVE_HIGH>;
>
> Again doesn't look like a valid binding.
>
>
>> + };
>> +
>> + rt5640: rt5640@1c {
Node name: codec@1c?
>> + #sound-dai-cells = <0>;
>> + compatible = "realtek,rt5640";
>> + reg = <0x1c>;
>> + clocks = <&cru SCLK_I2S_8CH_OUT>;
>> + clock-names = "mclk";
>> + realtek,in1-differential;
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&rt5640_hpcon>;
>> + hp-con-gpio = <&gpio4 21 GPIO_ACTIVE_HIGH>;
>> + //hp-det-gpio = <&gpio4 28 GPIO_ACTIVE_LOW>;
>
> don't add commented lines please
>
>
>> + io-channels = <&saradc 4>;
>> + hp-det-adc-value = <500>;
>> + };
>> +};
>> +
>> +&i2c3 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <450>;
>> + i2c-scl-falling-time-ns = <15>;
>> +};
>> +
>> +&i2c4 {
>> + status = "okay";
>> + i2c-scl-rising-time-ns = <600>;
>> + i2c-scl-falling-time-ns = <20>;
>> +
>> + fusb0: fusb30x@22 {
Node name?
>> + compatible = "fairchild,fusb302";
>
> Has this made its way into the kernel yet?
Regards,
Andreas
--
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
--
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 2/4] dt-binding: meson_uart: add documentation for the UARTs of amlogic
From: Helmut Klein @ 2017-03-31 16:54 UTC (permalink / raw)
To: robh+dt, mark.rutland
Cc: Helmut Klein, devicetree, linux-amlogic, linux-arm-kernel,
linux-kernel
In-Reply-To: <20170331165437.26227-1-hgkr.klein@gmail.com>
Add the documentation for the device tree binding of meson_uart
Signed-off-by: Helmut Klein <hgkr.klein@gmail.com>
---
.../bindings/serial/amlogic,meson_uart.txt | 30 ++++++++++++++++++++++
1 file changed, 30 insertions(+)
create mode 100644 Documentation/devicetree/bindings/serial/amlogic,meson_uart.txt
diff --git a/Documentation/devicetree/bindings/serial/amlogic,meson_uart.txt b/Documentation/devicetree/bindings/serial/amlogic,meson_uart.txt
new file mode 100644
index 000000000000..8250a191c2fc
--- /dev/null
+++ b/Documentation/devicetree/bindings/serial/amlogic,meson_uart.txt
@@ -0,0 +1,30 @@
+* Amlogic Meson UART, used in multiple SoCs (e.g. S905, s905X, ...)
+
+Required properties:
+- compatible : "amlogic,meson-uart"
+- reg : offset and length of the register set for the device.
+- interrupts : device interrupt
+- clocks : a list of phandle + clock-specifier pairs, one for each
+ entry in clock names.
+- clocks-names : contains:
+ * "xtal" for the baud rate clock
+ * "core" for the core clock of none AO UARTs (optional)
+
+e.g.
+uart_A: serial@84c0 {
+ compatible = "amlogic,meson-uart";
+ reg = <0x0 0x84c0 0x0 0x14>;
+ pinctrl-0 = <&uart_a_pins &uart_a_cts_rts_pins>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&xtal>, <&clkc CLKID_UART0>;
+ clock-names = "xtal", "core";
+ status = "ok";
+};
+
+Note: Each port should have an alias correctly numbered in "aliases" node.
+
+e.g.
+aliases {
+ serial0 = &uart_AO;
+ serial1 = &uart_A;
+};
--
2.11.0
^ permalink raw reply related
* [PATCH v3 1/4] dt-bindings: clock: gxbb: expose UART clocks
From: Helmut Klein @ 2017-03-31 16:54 UTC (permalink / raw)
To: mturquette, sboyd
Cc: devicetree, linux-kernel, Helmut Klein, linux-amlogic, linux-clk,
linux-arm-kernel
In-Reply-To: <20170331165437.26227-1-hgkr.klein@gmail.com>
Expose the clock ids of the three none AO uarts to the dt-bindings
Signed-off-by: Helmut Klein <hgkr.klein@gmail.com>
---
drivers/clk/meson/gxbb.h | 6 +++---
include/dt-bindings/clock/gxbb-clkc.h | 3 +++
2 files changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/meson/gxbb.h b/drivers/clk/meson/gxbb.h
index 8ee2022ce5d5..1edfaa5fe307 100644
--- a/drivers/clk/meson/gxbb.h
+++ b/drivers/clk/meson/gxbb.h
@@ -194,7 +194,7 @@
/* #define CLKID_SAR_ADC */
#define CLKID_SMART_CARD 24
#define CLKID_RNG0 25
-#define CLKID_UART0 26
+/* CLKID_UART0 */
#define CLKID_SDHC 27
#define CLKID_STREAM 28
#define CLKID_ASYNC_FIFO 29
@@ -216,7 +216,7 @@
#define CLKID_ADC 45
#define CLKID_BLKMV 46
#define CLKID_AIU 47
-#define CLKID_UART1 48
+/* CLKID_UART1 */
#define CLKID_G2D 49
/* CLKID_USB0 */
/* CLKID_USB1 */
@@ -236,7 +236,7 @@
/* CLKID_USB0_DDR_BRIDGE */
#define CLKID_MMC_PCLK 66
#define CLKID_DVIN 67
-#define CLKID_UART2 68
+/* CLKID_UART2 */
/* #define CLKID_SANA */
#define CLKID_VPU_INTR 70
#define CLKID_SEC_AHB_AHB3_BRIDGE 71
diff --git a/include/dt-bindings/clock/gxbb-clkc.h b/include/dt-bindings/clock/gxbb-clkc.h
index 692846c7941b..7b329df47752 100644
--- a/include/dt-bindings/clock/gxbb-clkc.h
+++ b/include/dt-bindings/clock/gxbb-clkc.h
@@ -15,13 +15,16 @@
#define CLKID_SPI 34
#define CLKID_I2C 22
#define CLKID_SAR_ADC 23
+#define CLKID_UART0 26
#define CLKID_ETH 36
+#define CLKID_UART1 48
#define CLKID_USB0 50
#define CLKID_USB1 51
#define CLKID_USB 55
#define CLKID_HDMI_PCLK 63
#define CLKID_USB1_DDR_BRIDGE 64
#define CLKID_USB0_DDR_BRIDGE 65
+#define CLKID_UART2 68
#define CLKID_SANA 69
#define CLKID_GCLK_VENCI_INT0 77
#define CLKID_AO_I2C 93
--
2.11.0
^ permalink raw reply related
* [PATCH v3 0/4] tty/serial: meson_uart: add support for core clock handling
From: Helmut Klein @ 2017-03-31 16:54 UTC (permalink / raw)
Cc: Helmut Klein, linux-clk, linux-serial, linux-amlogic,
linux-arm-kernel, linux-kernel, devicetree
To be able to use the three none AO uarts of the meson gx SoCs (uart_A,
uart_B & uart_C), the core clock has to be enabled (see chapter 22.3 of
the public s905 data sheet).
At least the u-boot of my s905 based media player (netxeon minimx-g)
doesn't do this. so the driver must enable the clock.
This patch set does:
- exposes the UART clock ids to the dtb
- adds documentation for the dt-bindings of meson_uart
- adds the core clock handling to the driver
- adds the core clock handling to meson-gxbb.dtsi and meson-gxl.dtsi
The patchset is based on the branch "master" of the repository in [1]
Changes since v2
- mail subjects reworked
- add clocks/clock-names to the documentation
- add core clock handling to meson-gxbb.dtsi & meson-gxl.dtsi
Changes since v1
- use git to produce the patch set
- added the clock ids for uart_B and uart_C
[1] git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic.git
Helmut Klein (4):
clk: meson: gxbb: expose CLKID_UARTx
dt-bindings: meson_uart: add documentation for meson UARTs
tty/serial: meson_uart: add the core clock handling to the driver
ARM64: dts: meson-gx: add core clock support for uart_A, uart_B and
uart_C
.../bindings/serial/amlogic,meson_uart.txt | 30 ++++++++++++++++++++++
arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 15 +++++++++++
arch/arm64/boot/dts/amlogic/meson-gxl.dtsi | 15 +++++++++++
drivers/clk/meson/gxbb.h | 6 ++---
drivers/tty/serial/meson_uart.c | 10 ++++++++
include/dt-bindings/clock/gxbb-clkc.h | 3 +++
6 files changed, 76 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/serial/amlogic,meson_uart.txt
--
2.11.0
^ permalink raw reply
* Re: [PATCH v2 2/2] ARM: dts: sun7i: Add CAN node and can0_pins_a pinctrl settings
From: Patrick Menschel @ 2017-03-31 16:51 UTC (permalink / raw)
To: Maxime Ripard
Cc: robh+dt, mark.rutland, linux, wens, devicetree, linux-arm-kernel,
linux-kernel, linux-can
In-Reply-To: <20170327064625.we7ydn2oapwizncb@lukather>
[-- Attachment #1: Type: text/plain, Size: 901 bytes --]
Hello Maxime,
Am 27.03.2017 um 08:46 schrieb Maxime Ripard:
>> @@ -1582,6 +1587,14 @@
>> #size-cells = <0>;
>> };
>>
>> + can0: can@01c2bc00 {
>> + compatible = "allwinner,sun4i-a10-can";
>
> Sorry for not spotting this earlier, but this would need an A20
> compatible too, to deal with the case where it turns out not to be
> compatible.
>
> you can do something like this:
> compatible = "allwinner,sun7i-a20-can", "allwinner,sun4i-a10-can";
Adding "sun7i-a20-can" to the compatible list results in a checkpatch
warning, that the "driver" is not documented.
WARNING: DT compatible string "allwinner,sun7i-a20-can" appears
un-documented -- check ./Documentation/devicetree/bindings/
#27: FILE: arch/arm/boot/dts/sun7i-a20.dtsi:1586:
+ compatible = "allwinner,sun7i-a20-can",
Is it really OK to add a driver that doesn't exist yet?
Thanks,
Patrick
[-- Attachment #2: S/MIME Cryptographic Signature --]
[-- Type: application/pkcs7-signature, Size: 3709 bytes --]
^ permalink raw reply
* Re: [PATCH] ARM: dts: armada-38x: label USB and SATA nodes
From: Andrew Lunn @ 2017-03-31 16:50 UTC (permalink / raw)
To: Ralph Sennhauser
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jason Cooper,
Gregory Clement, Sebastian Hesselbarth, Rob Herring, Mark Rutland,
Russell King, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170331074115.8111-1-ralph.sennhauser-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
> - sata@a8000 {
> + satac0: sata@a8000 {
Hi Ralph
Why the c in satac0?
>
> - usb3@f0000 {
> + usb3_0: usb3@f0000 {
> compatible = "marvell,armada-380-xhci";
> reg = <0xf0000 0x4000>,<0xf4000 0x4000>;
> interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
> @@ -598,7 +598,7 @@
> status = "disabled";
> };
>
> - usb3@f8000 {
> + usb3_1: usb3@f8000 {
> compatible = "marvell,armada-380-xhci";
> reg = <0xf8000 0x4000>,<0xfc000 0x4000>;
> interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
I can understand what you are saying. But does anybody else care? Are
there other .dtsi files differentiating between USB 1.1, 2 and 3?
Andrew
--
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 v2,1/3] meson_uart: expose CLKID_UARTx
From: Jerome Brunet @ 2017-03-31 15:37 UTC (permalink / raw)
To: Kevin Hilman, Martin Blumenstingl
Cc: Helmut Klein, mturquette, sboyd, devicetree, linux-clk,
linux-kernel, linux-arm-kernel, linux-amlogic
In-Reply-To: <m2y3vn6dhk.fsf@baylibre.com>
On Wed, 2017-03-29 at 13:21 -0700, Kevin Hilman wrote:
> Martin Blumenstingl <martin.blumenstingl@googlemail.com> writes:
>
> [...]
>
> > for Helmut this would mean that instead of dropping this patch (or
> > dropping CLKID_UART1 and CLKID_UART2 from this patch) he would rather
> > have to *add* another patch (for meson-gxbb.dtsi and meson-gxl.dtsi)
> > which passes the core clocks to the corresponding UART controllers
> > (similar to the CLKID_SD_EMMC_ clocks).
>
> Yes, this is what I would like to see.
>
> If a new CLKID is exposed, I want to see the users of it at the same
> time.
Helmut,
If you send another version of these patches, considering the feedback of Kevin
and Martin, could you please change the subject of this patch to:
dt-bindings: clock: gxbb: expose UART clocks
Thx
Jerome
>
> Kevin
^ permalink raw reply
* Re: [PATCH] ARM: dts: armada-385-linksys: disk-activity trigger for all
From: Andrew Lunn @ 2017-03-31 15:35 UTC (permalink / raw)
To: Ralph Sennhauser
Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Jason Cooper,
Gregory Clement, Sebastian Hesselbarth, Rob Herring, Mark Rutland,
Russell King, devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170330165405.14540-1-ralph.sennhauser-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Thu, Mar 30, 2017 at 06:54:04PM +0200, Ralph Sennhauser wrote:
> Commit a4ee7e18d808 ("ARM: dts: armada: Add default trigger for sata
> led") adds the default trigger to individual boards, move it to
> armada-385-linksys.dtsi which effectively enables the definition for
> the WRT1900ACS (Shelby) as well as for future boards.
>
> Signed-off-by: Ralph Sennhauser <ralph.sennhauser-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Centralising this makes sense.
Reviewed-by: Andrew Lunn <andrew-g2DYL2Zd6BY@public.gmane.org>
Andrew
--
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 v2] i2c/muxes/i2c-mux-ltc4306: LTC4306 and LTC4305 I2C multiplexer/switch
From: Peter Rosin @ 2017-03-31 15:29 UTC (permalink / raw)
To: michael.hennerich, wsa, robh+dt, mark.rutland, linus.walleij
Cc: linux-i2c, devicetree, linux-gpio, linux-kernel
In-Reply-To: <1490782541-7832-1-git-send-email-michael.hennerich@analog.com>
Hi!
Sorry for my incremental reviewing...
There's a question for the gpio people below that I would like
to have some confirmation on. Thanks!
On 2017-03-29 12:15, michael.hennerich@analog.com wrote:
> From: Michael Hennerich <michael.hennerich@analog.com>
>
> This patch adds support for the Analog Devices / Linear Technology
> LTC4306 and LTC4305 4/2 Channel I2C Bus Multiplexer/Switches.
> The LTC4306 optionally provides two general purpose input/output pins
> (GPIOs) that can be configured as logic inputs, opendrain outputs or
> push-pull outputs via the generic GPIOLIB framework.
>
> Signed-off-by: Michael Hennerich <michael.hennerich@analog.com>
>
> ---
>
> Changes since v1:
>
> - Sort makefile entries
> - Sort driver includes
> - Use proper defines
> - Miscellaneous coding style fixups
> - Rename mux select callback
> - Revise i2c-mux-idle-disconnect handling
> - Add ENABLE GPIO handling on error and device removal.
> - Remove surplus of_match_device call.
> ---
> .../devicetree/bindings/i2c/i2c-mux-ltc4306.txt | 61 ++++
> MAINTAINERS | 8 +
> drivers/i2c/muxes/Kconfig | 10 +
> drivers/i2c/muxes/Makefile | 1 +
> drivers/i2c/muxes/i2c-mux-ltc4306.c | 367 +++++++++++++++++++++
> 5 files changed, 447 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
> create mode 100644 drivers/i2c/muxes/i2c-mux-ltc4306.c
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
> new file mode 100644
> index 0000000..1e98c6b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
> @@ -0,0 +1,61 @@
> +* Linear Technology / Analog Devices I2C bus switch
> +
> +Required Properties:
> +
> + - compatible: Must contain one of the following.
> + "lltc,ltc4305", "lltc,ltc4306"
> + - reg: The I2C address of the device.
> +
> + The following required properties are defined externally:
> +
> + - Standard I2C mux properties. See i2c-mux.txt in this directory.
> + - I2C child bus nodes. See i2c-mux.txt in this directory.
> +
> +Optional Properties:
> +
> + - enable-gpios: Reference to the GPIO connected to the enable input.
> + - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
> + children in idle state. This is necessary for example, if there are several
> + multiplexers on the bus and the devices behind them use same I2C addresses.
> + - gpio-controller: Marks the device node as a GPIO Controller.
> + - #gpio-cells: Should be two. The first cell is the pin number and
> + the second cell is used to specify flags.
> + See ../gpio/gpio.txt for more information.
> + - ltc,downstream-accelerators-enable: Enables the rise time accelerators
> + on the downstream port.
> + - ltc,upstream-accelerators-enable: Enables the rise time accelerators
> + on the upstream port.
> +
> +Example:
> +
> + ltc4306: i2c-mux@4a {
> + compatible = "lltc,ltc4306";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x4a>;
> +
> + gpio-controller;
> + #gpio-cells = <2>;
> +
> + i2c@0 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0>;
> +
> + eeprom@50 {
> + compatible = "at,24c02";
> + reg = <0x50>;
> + };
> + };
> +
> + i2c@1 {
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <1>;
> +
> + eeprom@50 {
> + compatible = "at,24c02";
> + reg = <0x50>;
> + };
> + };
> + };
> diff --git a/MAINTAINERS b/MAINTAINERS
> index c776906..9a27a19 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7698,6 +7698,14 @@ S: Maintained
> F: Documentation/hwmon/ltc4261
> F: drivers/hwmon/ltc4261.c
>
> +LTC4306 I2C MULTIPLEXER DRIVER
> +M: Michael Hennerich <michael.hennerich@analog.com>
> +W: http://ez.analog.com/community/linux-device-drivers
> +L: linux-i2c@vger.kernel.org
> +S: Supported
> +F: drivers/i2c/muxes/i2c-mux-ltc4306.c
> +F: Documentation/devicetree/bindings/i2c/i2c-mux-ltc4306.txt
> +
> LTP (Linux Test Project)
> M: Mike Frysinger <vapier@gentoo.org>
> M: Cyril Hrubis <chrubis@suse.cz>
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index 10b3d17..f501b3b 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -30,6 +30,16 @@ config I2C_MUX_GPIO
> This driver can also be built as a module. If so, the module
> will be called i2c-mux-gpio.
>
> +config I2C_MUX_LTC4306
> + tristate "LTC LTC4306/5 I2C multiplexer"
> + select GPIOLIB
> + help
> + If you say yes here you get support for the LTC LTC4306 or LTC4305
> + I2C mux/switch devices.
> +
> + This driver can also be built as a module. If so, the module
> + will be called i2c-mux-ltc4306.
> +
> config I2C_MUX_PCA9541
> tristate "NXP PCA9541 I2C Master Selector"
> help
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 9948fa4..ff7618c 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -6,6 +6,7 @@ obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
> obj-$(CONFIG_I2C_DEMUX_PINCTRL) += i2c-demux-pinctrl.o
>
> obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
> +obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
> obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
> obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
> obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
> diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c
> new file mode 100644
> index 0000000..c15a8a4
> --- /dev/null
> +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c
> @@ -0,0 +1,367 @@
> +/*
> + * Linear Technology LTC4306 and LTC4305 I2C multiplexer/switch
> + *
> + * Copyright (C) 2017 Analog Devices Inc.
> + *
> + * Licensed under the GPL-2.
> + *
> + * Based on: i2c-mux-pca954x.c
> + *
> + * Datasheet: http://cds.linear.com/docs/en/datasheet/4306.pdf
> + */
> +
> +#include <linux/device.h>
> +#include <linux/gpio.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/gpio/driver.h>
> +#include <linux/i2c-mux.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/slab.h>
> +
> +#define LTC4305_MAX_NCHANS 2
> +#define LTC4306_MAX_NCHANS 4
> +
> +#define LTC_REG_STATUS 0x0
> +#define LTC_REG_CONFIG 0x1
> +#define LTC_REG_MODE 0x2
> +#define LTC_REG_SWITCH 0x3
> +
> +#define LTC_DOWNSTREAM_ACCL_EN BIT(6)
> +#define LTC_UPSTREAM_ACCL_EN BIT(7)
Maybe align the BIT(x) parts with a tab, like you do above...
> +
> +#define LTC_GPIO_ALL_INPUT 0xC0
> +
> +enum ltc_type {
> + ltc_4305,
> + ltc_4306,
> +};
> +
> +struct chip_desc {
> + u8 nchans;
> + u8 num_gpios;
> +};
> +
> +struct ltc4306 {
> + struct i2c_client *client;
> + struct gpio_desc *en_gpio;
> + struct gpio_chip gpiochip;
> + const struct chip_desc *chip;
> + u8 regs[LTC_REG_SWITCH + 1];
> +};
> +
> +/* Provide specs for the PCA954x types we know about */
> +static const struct chip_desc chips[] = {
> + [ltc_4305] = {
> + .nchans = LTC4305_MAX_NCHANS,
> + },
> + [ltc_4306] = {
> + .nchans = LTC4306_MAX_NCHANS,
> + .num_gpios = 2,
> + },
> +};
> +
> +static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset)
> +{
> + struct ltc4306 *data = gpiochip_get_data(chip);
> + int ret = 0;
This assignment is not needed.
> +
> + if (gpiochip_line_is_open_drain(chip, offset) ||
> + (data->regs[LTC_REG_MODE] & BIT(7 - offset))) {
I wonder about this open-coded register cache. So, gpio people, is there
a guarantee from gpiolib that only one gpio_chip operation is in flight
concurrently? Because I don't see any evidence of that. With that in
mind, I think some locking is needed?
> + /* Open Drain or Input */
> + ret = i2c_smbus_read_byte_data(data->client, LTC_REG_CONFIG);
> + if (ret < 0)
> + return ret;
> +
> + return !!(ret & BIT(1 - offset));
> + } else {
> + return !!(data->regs[LTC_REG_CONFIG] & BIT(5 - offset));
> + }
> +}
> +
> +static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset,
> + int value)
> +{
> + struct ltc4306 *data = gpiochip_get_data(chip);
> +
> + if (value)
> + data->regs[LTC_REG_CONFIG] |= BIT(5 - offset);
> + else
> + data->regs[LTC_REG_CONFIG] &= ~BIT(5 - offset);
> +
> + i2c_smbus_write_byte_data(data->client, LTC_REG_CONFIG,
> + data->regs[LTC_REG_CONFIG]);
> +}
> +
> +static int ltc4306_gpio_direction_input(struct gpio_chip *chip,
> + unsigned int offset)
> +{
> + struct ltc4306 *data = gpiochip_get_data(chip);
> +
> + data->regs[LTC_REG_MODE] |= BIT(7 - offset);
> +
> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
> + data->regs[LTC_REG_MODE]);
> +}
> +
> +static int ltc4306_gpio_direction_output(struct gpio_chip *chip,
> + unsigned int offset, int value)
> +{
> + struct ltc4306 *data = gpiochip_get_data(chip);
> +
> + ltc4306_gpio_set(chip, offset, value);
> + data->regs[LTC_REG_MODE] &= ~BIT(7 - offset);
> +
> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
> + data->regs[LTC_REG_MODE]);
> +}
> +
> +static int ltc4306_gpio_set_config(struct gpio_chip *chip,
> + unsigned int offset, unsigned long config)
> +{
> + struct ltc4306 *data = gpiochip_get_data(chip);
> +
> + switch (pinconf_to_config_param(config)) {
> + case PIN_CONFIG_DRIVE_OPEN_DRAIN:
> + data->regs[LTC_REG_MODE] &= ~BIT(4 - offset);
> + break;
> + case PIN_CONFIG_DRIVE_PUSH_PULL:
> + data->regs[LTC_REG_MODE] |= BIT(4 - offset);
> + break;
> + default:
> + return -ENOTSUPP;
> + }
> +
> + return i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
> + data->regs[LTC_REG_MODE]);
> +}
> +
> +static int ltc4306_gpio_init(struct ltc4306 *data)
> +{
> + if (!data->chip->num_gpios)
> + return 0;
> +
> + data->gpiochip.label = dev_name(&data->client->dev);
> + data->gpiochip.base = -1;
> + data->gpiochip.ngpio = data->chip->num_gpios;
> + data->gpiochip.parent = &data->client->dev;
> + data->gpiochip.can_sleep = true;
> + data->gpiochip.direction_input = ltc4306_gpio_direction_input;
> + data->gpiochip.direction_output = ltc4306_gpio_direction_output;
> + data->gpiochip.get = ltc4306_gpio_get;
> + data->gpiochip.set = ltc4306_gpio_set;
> + data->gpiochip.set_config = ltc4306_gpio_set_config;
> + data->gpiochip.owner = THIS_MODULE;
> +
> + /* gpiolib assumes all GPIOs default input */
> + data->regs[LTC_REG_MODE] |= LTC_GPIO_ALL_INPUT;
> + i2c_smbus_write_byte_data(data->client, LTC_REG_MODE,
> + data->regs[LTC_REG_MODE]);
> +
> + return devm_gpiochip_add_data(&data->client->dev,
> + &data->gpiochip, data);
> +}
> +
> +/*
> + * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer()
> + * as they will try to lock the adapter a second time.
> + */
> +static int ltc4306_reg_write(struct i2c_adapter *adap,
> + struct i2c_client *client, u8 reg, u8 val)
> +{
> + int ret;
> +
> + if (adap->algo->master_xfer) {
> + struct i2c_msg msg;
> + char buf[2];
> +
> + msg.addr = client->addr;
> + msg.flags = 0;
> + msg.len = 2;
> + buf[0] = reg;
> + buf[1] = val;
> + msg.buf = buf;
> + ret = __i2c_transfer(adap, &msg, 1);
> + } else {
> + union i2c_smbus_data data;
> +
> + data.byte = val;
> + ret = adap->algo->smbus_xfer(adap, client->addr,
> + client->flags,
> + I2C_SMBUS_WRITE,
> + reg,
> + I2C_SMBUS_BYTE_DATA, &data);
> + }
> +
> + return ret;
> +}
> +
> +static int ltc4306_select_mux(struct i2c_mux_core *muxc, u32 chan)
> +{
> + struct ltc4306 *data = i2c_mux_priv(muxc);
> + struct i2c_client *client = data->client;
> + u8 regval;
> + int ret = 0;
> +
> + regval = BIT(7 - chan);
> +
> + /* Only select the channel if its different from the last channel */
> + if (data->regs[LTC_REG_SWITCH] != regval) {
> + ret = ltc4306_reg_write(muxc->parent, client,
> + LTC_REG_SWITCH, regval);
> + data->regs[LTC_REG_SWITCH] = ret < 0 ? 0 : regval;
> + }
> +
> + return ret;
> +}
> +
> +static int ltc4306_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
> +{
> + struct ltc4306 *data = i2c_mux_priv(muxc);
> + struct i2c_client *client = data->client;
> +
> + /* Deselect all channels */
> + data->regs[LTC_REG_SWITCH] = 0;
> +
> + return ltc4306_reg_write(muxc->parent, client,
> + LTC_REG_SWITCH, data->regs[LTC_REG_SWITCH]);
> +}
> +
> +static const struct i2c_device_id ltc4306_id[] = {
> + { "ltc4305", ltc_4305 },
> + { "ltc4306", ltc_4306 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(i2c, ltc4306_id);
> +
> +static const struct of_device_id ltc4306_of_match[] = {
> + { .compatible = "lltc,ltc4305", .data = &chips[ltc_4305] },
> + { .compatible = "lltc,ltc4306", .data = &chips[ltc_4306] },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, ltc4306_of_match);
> +
> +static int ltc4306_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
> + struct device_node *of_node = client->dev.of_node;
> + bool idle_disconnect_dt = false;
> + struct i2c_mux_core *muxc;
> + struct ltc4306 *data;
> + int num, ret;
> +
> + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA))
> + return -ENODEV;
> +
> + if (of_node) {
> + idle_disconnect_dt =
> + of_property_read_bool(of_node,
> + "i2c-mux-idle-disconnect");
If you rename the variable "disconnect" or something similar and
shorter, you can avoid the interesting indentation.
> + }
> +
> + muxc = i2c_mux_alloc(adap, &client->dev,
> + LTC4306_MAX_NCHANS, sizeof(*data), 0,
> + ltc4306_select_mux, idle_disconnect_dt ?
> + ltc4306_deselect_mux : NULL);
> + if (!muxc)
> + return -ENOMEM;
> + data = i2c_mux_priv(muxc);
> +
> + i2c_set_clientdata(client, muxc);
> + data->client = client;
> +
> + /* Enable the mux if an enable GPIO is specified. */
> + data->en_gpio = devm_gpiod_get_optional(&client->dev, "enable",
> + GPIOD_OUT_HIGH);
> + if (IS_ERR(data->en_gpio))
> + return PTR_ERR(data->en_gpio);
> +
> + /*
> + * Write the mux register at addr to verify
> + * that the mux is in fact present. This also
> + * initializes the mux to disconnected state.
> + */
> + if (i2c_smbus_write_byte_data(client, LTC_REG_SWITCH, 0) < 0) {
> + dev_warn(&client->dev, "probe failed\n");
> + ret = -ENODEV;
> + goto gpio_default;
> + }
> +
> + if (of_node) {
> + data->chip = of_device_get_match_data(&client->dev);
> +
> + if (of_property_read_bool(of_node,
> + "ltc,downstream-accelerators-enable"))
> + data->regs[LTC_REG_CONFIG] |= LTC_DOWNSTREAM_ACCL_EN;
> +
> + if (of_property_read_bool(of_node,
> + "ltc,upstream-accelerators-enable"))
> + data->regs[LTC_REG_CONFIG] |= LTC_UPSTREAM_ACCL_EN;
> +
> + if (i2c_smbus_write_byte_data(client, LTC_REG_CONFIG,
> + data->regs[LTC_REG_CONFIG]) < 0) {
> + dev_warn(&client->dev, "probe failed\n");
> + ret = -ENODEV;
> + goto gpio_default;
> + }
> + } else {
> + data->chip = &chips[id->driver_data];
> + }
> +
> + ret = ltc4306_gpio_init(data);
> + if (ret < 0)
> + goto gpio_default;
> +
> + /* Now create an adapter for each channel */
> + for (num = 0; num < data->chip->nchans; num++) {
> + ret = i2c_mux_add_adapter(muxc, 0, num, 0);
> + if (ret) {
> + dev_err(&client->dev,
> + "failed to register multiplexed adapter %d\n",
> + num);
> + goto add_adapter_failed;
> + }
> + }
> +
> + dev_info(&client->dev,
> + "registered %d multiplexed busses for I2C switch %s\n",
> + num, client->name);
> +
> + return 0;
> +
> +add_adapter_failed:
> + i2c_mux_del_adapters(muxc);
> +gpio_default:
> + gpiod_direction_input(data->en_gpio);
This was actually not what I had in mind when I asked about it in v1, and
this looks a bit strange. You have no way of knowing if the pin was
configured as input when probe was called, and I don't see code like this
all over the place. Maybe it's is ok to not disable the chip over
suspend/resume, I was just asking because it looked a bit strange to grab
a pin and then forget about it. Now that I think about it some more, it's
probably ok to do just that since it is perhaps not possible to make the
chip draw less power by deasserting enable, but what do I know?
However, it might be a good idea to toggle enable and deliberately reset
the chip in probe?
Cheers,
peda
> + return ret;
> +}
> +
> +static int ltc4306_remove(struct i2c_client *client)
> +{
> + struct i2c_mux_core *muxc = i2c_get_clientdata(client);
> + struct ltc4306 *data = i2c_mux_priv(muxc);
> +
> + i2c_mux_del_adapters(muxc);
> + gpiod_direction_input(data->en_gpio);
> +
> + return 0;
> +}
> +
> +static struct i2c_driver ltc4306_driver = {
> + .driver = {
> + .name = "ltc4306",
> + .of_match_table = of_match_ptr(ltc4306_of_match),
> + },
> + .probe = ltc4306_probe,
> + .remove = ltc4306_remove,
> + .id_table = ltc4306_id,
> +};
> +
> +module_i2c_driver(ltc4306_driver);
> +
> +MODULE_AUTHOR("Michael Hennerich <michael.hennerich@analog.com>");
> +MODULE_DESCRIPTION("Linear Technology LTC4306, LTC4305 I2C mux/switch driver");
> +MODULE_LICENSE("GPL v2");
>
^ permalink raw reply
* Re: [PATCH] OF: mark released devices as no longer populated
From: Horia Geantă @ 2017-03-31 15:23 UTC (permalink / raw)
To: Russell King - ARM Linux, Rob Herring, Fabio Estevam
Cc: Frank Rowand, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
linux-crypto-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Dan Douglass
In-Reply-To: <20170331103950.GA18376@n2100.armlinux.org.uk>
On 3/31/2017 1:40 PM, Russell King - ARM Linux wrote:
> Ping, this issue still exists with 4.11-rc4 - and there's been no
> reaction from the alleged CAAM maintainers.
>
Sorry, this somehow slipped through (Cc vs. To, no linux-crypto).
> On Tue, Aug 09, 2016 at 11:48:38AM -0500, Rob Herring wrote:
>> On Tue, Aug 9, 2016 at 4:33 AM, Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org> wrote:
>>> When a Linux device is released and cleaned up, we left the OF device
>>> node marked as populated. This causes the Freescale CAAM driver
>>> (drivers/crypto/caam) problems when the module is removed and re-
>>> inserted:
>>>
>>> JR0 Platform device creation error
>>> JR0 Platform device creation error
>>> caam 2100000.caam: no queues configured, terminating
>>> caam: probe of 2100000.caam failed with error -12
>>>
>>> The reason is that CAAM creates platform devices for each job ring:
>>>
>>> for_each_available_child_of_node(nprop, np)
>>> if (of_device_is_compatible(np, "fsl,sec-v4.0-job-ring") ||
>>> of_device_is_compatible(np, "fsl,sec4.0-job-ring")) {
>>> ctrlpriv->jrpdev[ring] =
>>> of_platform_device_create(np, NULL, dev);
>>>
>>> which sets OF_POPULATED on the device node, but then it cleans these
>>> up:
>>>
>>> /* Remove platform devices for JobRs */
>>> for (ring = 0; ring < ctrlpriv->total_jobrs; ring++) {
>>> if (ctrlpriv->jrpdev[ring])
>>> of_device_unregister(ctrlpriv->jrpdev[ring]);
>>
>> This looks a bit asymmetrical to me with a of_platform_device_* call
>> and a of_device_* call.
>>
>> I think you could use of_platform_{de}populate here instead. That
>> would simplify things in the driver a bit too as you wouldn't need to
>> store jrpdev. It wouldn't work if there are other child nodes with
Indeed, this would clean-up the driver a bit. However, the driver needs
to know how many of the devices probed successfully - to print the
number and more importantly to exit in case total_jobrs = 0.
Thus, I would keep the one-by-one probing of the devices.
What options are there in this case?
Should a function symmetric to of_platform_device_create() be added - to
replace of_device_unregister() - or rely on an open-coded solution?
Thanks,
Horia
>> compatible strings which you don't want devices created.
>>
>>> }
>>>
>>> which leaves OF_POPULATED set.
>>>
>>> Arrange for platform devices with a device node to clear the
>>> OF_POPULATED bit when they are released.
>>>
>>> Signed-off-by: Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org>
>>> ---
>>> Please check this carefully - it may have issues where an of_node
>>> pointer is copied from one platform device to another, but IMHO
>>> doing that is itself buggy behaviour.
>>
>> Agreed, that is wrong.
>>
>>>
>>> Resending due to wrong list address, sorry.
>>>
>>> include/linux/of_device.h | 1 +
>>> 1 file changed, 1 insertion(+)
>>>
>>> diff --git a/include/linux/of_device.h b/include/linux/of_device.h
>>> index cc7dd687a89d..7a8362d0c6d2 100644
>>> --- a/include/linux/of_device.h
>>> +++ b/include/linux/of_device.h
>>> @@ -43,6 +43,7 @@ extern int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env
>>>
>>> static inline void of_device_node_put(struct device *dev)
>>> {
>>> + of_node_clear_flag(dev->of_node, OF_POPULATED);
>>
>> This would result in clearing the flag twice in the
>> of_platform_populate/of_platform_depopulate case. It would do the same
>> for other bus types like i2c as well. That doesn't really hurt
>> anything that I can think of, but just not the best implementation. I
>> think adding a of_platform_device_unregister() call that wraps
>> of_platform_device_destroy would be more balanced.
>>
>> I looked thru all the callers of of_platform_device_create. The only
>> other ones affected by this are:
>>
>> drivers/macintosh/ams/ams-core.c
>> drivers/macintosh/therm_adt746x.c
>> drivers/macintosh/therm_windtunnel.c
>>
>> The others either have no remove path or a buggy remove path.
>>
>> 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 4/4] dt-bindings: input: Add Atmel PTC subsystem bindings
From: Ludovic Desroches @ 2017-03-31 15:22 UTC (permalink / raw)
To: linux-input, linux-arm-kernel, devicetree
Cc: dmitry.torokhov, nicolas.ferre, alexandre.belloni, linux-kernel,
Ludovic Desroches
In-Reply-To: <20170331152250.12758-1-ludovic.desroches@microchip.com>
Add description of the Atmel PTC subsystem bindings.
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
.../devicetree/bindings/input/atmel,ptc.txt | 67 ++++++++++++++++++++++
1 file changed, 67 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/atmel,ptc.txt
diff --git a/Documentation/devicetree/bindings/input/atmel,ptc.txt b/Documentation/devicetree/bindings/input/atmel,ptc.txt
new file mode 100644
index 0000000..a183fd5
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/atmel,ptc.txt
@@ -0,0 +1,67 @@
+Atmel PTC Subsystem
+
+The Atmel Peripheral Touch Controller subsystem offers built-in hardware
+for capacitive touch measurement on sensors that function as buttons, sliders
+and wheels.
+
+1) PTC Subsystem node
+
+Required properties:
+- compatible: Must be "atmel,sama5d2-ptc"
+- reg: Address, length of the shared memory and ppp registers location
+ and length.
+- clocks: Phandlers to the clocks.
+- clock-names: Must be "ptc_clk", "ptc_int_osc", "slow_clk".
+- #address-cells: Must be one. The cell is the button or scroller id.
+- #size-cells: Must be zero.
+
+Example:
+ ptc@fc060000 {
+ compatible = "atmel,sama5d2-ptc";
+ reg = <0x00800000 0x10000
+ 0xfc060000 0xcf>;
+ interrupts = <58 IRQ_TYPE_LEVEL_HIGH 7>;
+ clocks = <&ptc_clk>, <&main>, <&clk32k>;
+ clock-names = "ptc_clk", "ptc_int_osc", "slow_clk";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ [ child node definitions... ]
+ };
+
+2) Scroller / buttons subnodes
+
+Subnodes describe the kind of sensors the customer want to use. They have to be
+named according to their function: button, slider or wheel.
+
+2.1) Scroller subnodes
+
+Required properties:
+- reg: Id of the scroller, each id must be different.
+
+Example:
+ slider@0 {
+ reg = <0>;
+ };
+
+ wheel@1 {
+ reg = <1>;
+ };
+
+2.2) Button subnodes
+
+Required properties:
+- reg: Id of node used for the button, each id must be
+ different.
+- linux,keycode: Key code of the button.
+
+Example:
+ button@8 {
+ reg = <8>;
+ linux,keycode = <2>;
+ };
+
+ button@9 {
+ reg = <9>;
+ linux,keycode = <3>;
+ };
--
2.9.0
^ permalink raw reply related
* [PATCH 3/4] MAINTAINERS: add Atmel PTC entries
From: Ludovic Desroches @ 2017-03-31 15:22 UTC (permalink / raw)
To: linux-input, linux-arm-kernel, devicetree
Cc: dmitry.torokhov, nicolas.ferre, alexandre.belloni, linux-kernel,
Ludovic Desroches
In-Reply-To: <20170331152250.12758-1-ludovic.desroches@microchip.com>
Add entries for the Atmel PTC Subsystem.
Signed-off-by: Ludovic Desroches <ludovic.desroches@microchip.com>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 57634d0..afb2645 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2292,6 +2292,13 @@ F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt
F: drivers/input/touchscreen/atmel_mxt_ts.c
F: include/linux/platform_data/atmel_mxt_ts.h
+ATMEL PTC SUBSYSTEM DRIVER
+M: Ludovic Desroches <ludovic.desroches@microchip.com>
+L: linux-input@vger.kernel.org
+S: Supported
+F: drivers/input/misc/atmel_ptc.c
+F: include/uapi/linux/atmel_ptc.h
+
ATTO EXPRESSSAS SAS/SATA RAID SCSI DRIVER
M: Bradley Grove <linuxdrivers@attotech.com>
L: linux-scsi@vger.kernel.org
--
2.9.0
^ permalink raw reply related
* [PATCH 2/4] ARM: dts: at91: sama5d2: add PTC subsystem device
From: Ludovic Desroches @ 2017-03-31 15:22 UTC (permalink / raw)
To: linux-input, linux-arm-kernel, devicetree
Cc: dmitry.torokhov, nicolas.ferre, alexandre.belloni, linux-kernel,
Ludovic Desroches
In-Reply-To: <20170331152250.12758-1-ludovic.desroches@microchip.com>
From: Ludovic Desroches <ludovic.desroches@atmel.com>
Add the Atmel Peripheral Touch Controller subsystem.
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
arch/arm/boot/dts/sama5d2.dtsi | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/arch/arm/boot/dts/sama5d2.dtsi b/arch/arm/boot/dts/sama5d2.dtsi
index 468ef9c..a958456 100644
--- a/arch/arm/boot/dts/sama5d2.dtsi
+++ b/arch/arm/boot/dts/sama5d2.dtsi
@@ -762,6 +762,12 @@
atmel,clk-output-range = <0 83000000>;
};
+ ptc_clk: ptc_clk {
+ #clock-cells = <0>;
+ reg = <58>;
+ atmel,clk-output-range = <0 83000000>;
+ };
+
classd_clk: classd_clk {
#clock-cells = <0>;
reg = <59>;
@@ -1310,6 +1316,16 @@
reg = <0xfc05c000 0x20>;
};
+ ptc@fc060000 {
+ compatible = "atmel,sama5d2-ptc";
+ reg = <0x00800000 0x10000
+ 0xfc060000 0xcf>;
+ interrupts = <58 IRQ_TYPE_LEVEL_HIGH 7>;
+ clocks = <&ptc_clk>, <&main>, <&clk32k>;
+ clock-names = "ptc_clk", "ptc_int_osc", "slow_clk";
+ status = "disabled";
+ };
+
chipid@fc069000 {
compatible = "atmel,sama5d2-chipid";
reg = <0xfc069000 0x8>;
--
2.9.0
^ permalink raw reply related
* [PATCH 1/4] input: misc: introduce Atmel PTC driver
From: Ludovic Desroches @ 2017-03-31 15:22 UTC (permalink / raw)
To: linux-input-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
devicetree-u79uwXL29TY76Z2rM5mHXA
Cc: dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
nicolas.ferre-UWL1GkI3JZL3oGB3hsPCZA,
alexandre.belloni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Ludovic Desroches
In-Reply-To: <20170331152250.12758-1-ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
From: Ludovic Desroches <ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
Signed-off-by: Ludovic Desroches <ludovic.desroches-AIFe0yeh4nAAvxtiuMwx3w@public.gmane.org>
---
drivers/input/misc/Kconfig | 12 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/atmel_ptc.c | 651 +++++++++++++++++++++++++++++++++++++++++
include/uapi/linux/atmel_ptc.h | 355 ++++++++++++++++++++++
4 files changed, 1019 insertions(+)
create mode 100644 drivers/input/misc/atmel_ptc.c
create mode 100644 include/uapi/linux/atmel_ptc.h
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 5b6c522..aec7b8f 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -96,6 +96,18 @@ config INPUT_ATMEL_CAPTOUCH
To compile this driver as a module, choose M here: the
module will be called atmel_captouch.
+config INPUT_ATMEL_PTC
+ tristate "Atmel PTC Driver"
+ depends on OF || COMPILE_TEST
+ depends on SOC_SAMA5D2
+ help
+ Say Y to enable support for the Atmel PTC Subsystem.
+
+ To compile this driver as a module, choose M here: the
+ module will be called atmel_ptc.
+ If you compile it as a built-in driver, you have to build the
+ firmware into the kernel or to use an initrd.
+
config INPUT_BMA150
tristate "BMA150/SMB380 acceleration sensor support"
depends on I2C
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index b10523f..9470ec7 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -18,6 +18,7 @@ obj-$(CONFIG_INPUT_ARIZONA_HAPTICS) += arizona-haptics.o
obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_ATLAS_BTNS) += atlas_btns.o
obj-$(CONFIG_INPUT_ATMEL_CAPTOUCH) += atmel_captouch.o
+obj-$(CONFIG_INPUT_ATMEL_PTC) += atmel_ptc.o
obj-$(CONFIG_INPUT_BFIN_ROTARY) += bfin_rotary.o
obj-$(CONFIG_INPUT_BMA150) += bma150.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
diff --git a/drivers/input/misc/atmel_ptc.c b/drivers/input/misc/atmel_ptc.c
new file mode 100644
index 0000000..44df1bf
--- /dev/null
+++ b/drivers/input/misc/atmel_ptc.c
@@ -0,0 +1,651 @@
+/*
+ * Atmel PTC subsystem driver for SAMA5D2 devices and compatible.
+ *
+ * Copyright (C) 2017 Microchip,
+ * 2017 Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+
+#include <uapi/linux/atmel_ptc.h>
+
+#define ATMEL_QTM_MB_OFFSET 0x4000
+
+/* ----- PPP REGISTERS ----- */
+#define ATMEL_PPP_CONFIG 0x20
+#define ATMEL_PPP_CTRL 0x24
+#define ATMEL_PPP_CMD 0x28
+#define ATMEL_PPP_CMD_STOP 0x1
+#define ATMEL_PPP_CMD_RESET 0x2
+#define ATMEL_PPP_CMD_RESTART 0x3
+#define ATMEL_PPP_CMD_ABORT 0x4
+#define ATMEL_PPP_CMD_RUN 0x5
+#define ATMEL_PPP_CMD_RUN_LOCKED 0x6
+#define ATMEL_PPP_CMD_RUN_OCD 0x7
+#define ATMEL_PPP_CMD_UNLOCK 0x8
+#define ATMEL_PPP_CMD_NMI 0x9
+#define ATMEL_PPP_CMD_HOST_OCD_RESUME 0xB
+#define ATMEL_PPP_ISR 0x33
+#define ATMEL_PPP_IRQ_MASK GENMASK(7, 4)
+#define ATMEL_PPP_IRQ0 BIT(4)
+#define ATMEL_PPP_IRQ1 BIT(5)
+#define ATMEL_PPP_IRQ2 BIT(6)
+#define ATMEL_PPP_IRQ3 BIT(7)
+#define ATMEL_PPP_NOTIFY_MASK GENMASK(3, 0)
+#define ATMEL_PPP_NOTIFY0 BIT(0)
+#define ATMEL_PPP_NOTIFY1 BIT(1)
+#define ATMEL_PPP_NOTIFY2 BIT(2)
+#define ATMEL_PPP_NOTIFY3 BIT(3)
+#define ATMEL_PPP_IDR 0x34
+#define ATMEL_PPP_IER 0x35
+
+#define PPP_FIRMWARE_NAME "atmel_ptc.bin"
+#define QTM_CONF_NAME "atmel_ptc.conf"
+
+#define atmel_ppp_readb(ptc, reg) readb_relaxed(ptc->ppp_regs + reg)
+#define atmel_ppp_writeb(ptc, reg, val) writeb_relaxed(val, ptc->ppp_regs + reg)
+#define atmel_ppp_readl(ptc, reg) readl_relaxed(ptc->ppp_regs + reg)
+#define atmel_ppp_writel(ptc, reg, val) writel_relaxed(val, ptc->ppp_regs + reg)
+
+#define get_scroller_resolution(ptc, scroller_id) \
+ (1 << (ptc->qtm_mb->scroller_config[i].resol_deadband >> 4))
+
+struct atmel_ptc {
+ void __iomem *ppp_regs;
+ void __iomem *firmware;
+ int irq;
+ uint8_t imr;
+ volatile struct atmel_qtm_mailbox __iomem *qtm_mb;
+ struct clk *clk_per;
+ struct clk *clk_int_osc;
+ struct clk *clk_slow;
+ struct device *dev;
+ struct completion ppp_ack;
+ unsigned int button_keycode[ATMEL_PTC_MAX_NODES];
+ struct input_dev *buttons_input;
+ struct input_dev *scroller_input[ATMEL_PTC_MAX_SCROLLERS];
+ bool buttons_registered;
+ bool scroller_registered[ATMEL_PTC_MAX_SCROLLERS];
+ uint32_t button_event[ATMEL_PTC_MAX_NODES/32];
+ uint32_t button_state[ATMEL_PTC_MAX_NODES/32];
+ uint32_t scroller_event;
+ uint32_t scroller_state;
+};
+
+static void atmel_ppp_irq_enable(struct atmel_ptc *ptc, uint8_t mask)
+{
+ ptc->imr |= mask;
+ atmel_ppp_writeb(ptc, ATMEL_PPP_IER, mask & ATMEL_PPP_IRQ_MASK);
+}
+
+static void atmel_ppp_irq_disable(struct atmel_ptc *ptc, uint8_t mask)
+{
+ ptc->imr &= ~mask;
+ atmel_ppp_writeb(ptc, ATMEL_PPP_IDR, mask & ATMEL_PPP_IRQ_MASK);
+}
+
+static void atmel_ppp_notify(struct atmel_ptc *ptc, uint8_t mask)
+{
+ if (mask & ATMEL_PPP_NOTIFY_MASK) {
+ uint8_t notify = atmel_ppp_readb(ptc, ATMEL_PPP_ISR)
+ | (mask & ATMEL_PPP_NOTIFY_MASK);
+
+ atmel_ppp_writeb(ptc, ATMEL_PPP_ISR, notify);
+ }
+}
+
+static void atmel_ppp_irq_pending_clr(struct atmel_ptc *ptc, uint8_t mask)
+{
+ if (mask & ATMEL_PPP_IRQ_MASK) {
+ uint8_t irq = atmel_ppp_readb(ptc, ATMEL_PPP_ISR) & ~mask;
+
+ atmel_ppp_writeb(ptc, ATMEL_PPP_ISR, irq);
+ }
+}
+
+static void atmel_ppp_cmd_send(struct atmel_ptc *ptc, uint32_t cmd)
+{
+ atmel_ppp_writel(ptc, ATMEL_PPP_CMD, cmd);
+}
+
+static void atmel_ppp_irq_scroller_event(struct atmel_ptc *ptc)
+{
+ int i;
+
+ if (!ptc->scroller_event)
+ return;
+
+ for (i = 0; i < ATMEL_PTC_MAX_SCROLLERS; i++) {
+ uint32_t mask = 1 << i;
+ uint8_t status;
+ uint16_t position;
+
+ if (!(ptc->scroller_event & mask))
+ continue;
+
+ status = ptc->qtm_mb->scroller_data[i].status;
+ position = ptc->qtm_mb->scroller_data[i].position;
+
+ if (ptc->qtm_mb->scroller_config[i].type ==
+ QTM_SCROLLER_TYPE_WHEEL)
+ input_report_abs(ptc->scroller_input[i],
+ ABS_WHEEL, position);
+ else
+ input_report_abs(ptc->scroller_input[i],
+ ABS_X, position);
+
+ input_report_key(ptc->scroller_input[i], BTN_TOUCH, status & 0x1);
+ input_sync(ptc->scroller_input[i]);
+ }
+}
+
+static void atmel_ppp_irq_button_event(struct atmel_ptc *ptc)
+{
+ int i, j;
+
+ for (i = 0; i < ATMEL_PTC_MAX_NODES / 32; i++) {
+ if (!ptc->button_event[i])
+ continue;
+
+ for (j = 0; j < 32; j++) {
+ uint32_t mask = 1 << j;
+ uint32_t state = ptc->button_state[i] & mask;
+ unsigned int key_id = i * 32 + j;
+
+ if (!(ptc->button_event[i] & mask))
+ continue;
+
+ input_report_key(ptc->buttons_input,
+ ptc->button_keycode[key_id], !!state);
+ input_sync(ptc->buttons_input);
+ }
+ }
+}
+
+static void atmel_ppp_irq_touch_event(struct atmel_ptc *ptc)
+{
+ atmel_ppp_irq_scroller_event(ptc);
+ atmel_ppp_irq_button_event(ptc);
+}
+
+static irqreturn_t atmel_ppp_irq_handler(int irq, void *data)
+{
+ struct atmel_ptc *ptc = data;
+ uint32_t isr = atmel_ppp_readb(ptc, ATMEL_PPP_ISR) & ptc->imr;
+
+ /* QTM CMD acknowledgment */
+ if (isr & ATMEL_PPP_IRQ0) {
+ atmel_ppp_irq_disable(ptc, ATMEL_PPP_IRQ0);
+ atmel_ppp_irq_pending_clr(ptc, ATMEL_PPP_IRQ0);
+ complete(&ptc->ppp_ack);
+ }
+ /* QTM touch event */
+ if (isr & ATMEL_PPP_IRQ1) {
+ int i;
+
+ for (i = 0; i < ATMEL_PTC_MAX_NODES / 32; i++) {
+ ptc->button_event[i] = ptc->qtm_mb->touch_events.key_event_id[i];
+ ptc->button_state[i] = ptc->qtm_mb->touch_events.key_enable_state[i];
+ }
+ ptc->scroller_event = ptc->qtm_mb->touch_events.scroller_event_id;
+ ptc->scroller_state = ptc->qtm_mb->touch_events.scroller_event_state;
+
+ atmel_ppp_irq_pending_clr(ptc, ATMEL_PPP_IRQ1);
+
+ atmel_ppp_irq_touch_event(ptc);
+ }
+ /* Debug event */
+ if (isr & ATMEL_PPP_IRQ2) {
+ atmel_ppp_irq_pending_clr(ptc, ATMEL_PPP_IRQ2);
+ }
+
+ return IRQ_HANDLED;
+}
+
+uint32_t atmel_qtm_cmd_send(struct atmel_ptc *ptc, struct atmel_qtm_cmd *cmd)
+{
+ int i, ret;
+
+ dev_dbg(ptc->dev, "%s: cmd=0x%x, addr=0x%x, data=0x%x\n",
+ __func__, cmd->id, cmd->addr, cmd->data);
+
+ ptc->qtm_mb->cmd.id = cmd->id;
+ ptc->qtm_mb->cmd.addr = cmd->addr;
+ ptc->qtm_mb->cmd.data = cmd->data;
+
+ /* Once command performed, we'll get an IRQ. */
+ atmel_ppp_irq_enable(ptc, ATMEL_PPP_IRQ0);
+ /* Notify PPP that we have sent a command. */
+ atmel_ppp_notify(ptc, ATMEL_PPP_NOTIFY0);
+ /* Wait for IRQ from PPP. */
+ wait_for_completion(&ptc->ppp_ack);
+
+ /*
+ * Register input devices only when QTM is started since we need some
+ * information from the QTM configuration.
+ */
+ if (cmd->id == QTM_CMD_RUN) {
+ if (ptc->buttons_input && !ptc->buttons_registered) {
+ ret = input_register_device(ptc->buttons_input);
+ if (ret)
+ dev_err(ptc->dev, "can't register input button device.\n");
+ else
+ ptc->buttons_registered = true;
+ }
+
+ for (i = 0; i < ATMEL_PTC_MAX_SCROLLERS; i++) {
+ struct input_dev *scroller = ptc->scroller_input[i];
+
+ if (!scroller || ptc->scroller_registered[i])
+ continue;
+ if (ptc->qtm_mb->scroller_config[i].type ==
+ QTM_SCROLLER_TYPE_SLIDER) {
+ unsigned int max = get_scroller_resolution(ptc, i);
+
+ input_set_abs_params(scroller, 0, 0, max, 0, 0);
+ }
+ ret = input_register_device(scroller);
+ if (ret)
+ dev_err(ptc->dev, "can't register input scroller device.\n");
+ else
+ ptc->scroller_registered[i] = true;
+ }
+ }
+
+ return ptc->qtm_mb->cmd.data;
+}
+
+static inline struct atmel_ptc *kobj_to_atmel_ptc(struct kobject *kobj)
+{
+ struct device *dev = kobj_to_dev(kobj);
+
+ return dev->driver_data;
+}
+
+static ssize_t atmel_qtm_mb_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct atmel_ptc *ptc = kobj_to_atmel_ptc(kobj);
+ char *qtm_mb = (char *)ptc->qtm_mb;
+
+ dev_dbg(ptc->dev, "%s: off=0x%llx, count=%zu\n", __func__, off, count);
+
+ memcpy(buf, qtm_mb + off, count);
+
+ return count;
+}
+
+static ssize_t atmel_qtm_mb_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct atmel_ptc *ptc = kobj_to_atmel_ptc(kobj);
+ char *qtm_mb = (char *)ptc->qtm_mb;
+
+ dev_dbg(ptc->dev, "%s: off=0x%llx, count=%zu\n", __func__, off, count);
+
+ if (off == 0 && count == sizeof(struct atmel_qtm_cmd))
+ atmel_qtm_cmd_send(ptc, (struct atmel_qtm_cmd *)buf);
+ else
+ memcpy(qtm_mb + off, buf, count);
+
+ return count;
+}
+
+static struct bin_attribute atmel_ptc_qtm_mb_attr = {
+ .attr = {
+ .name = "qtm_mb",
+ .mode = 0644,
+ },
+ .size = sizeof(struct atmel_qtm_mailbox),
+ .read = atmel_qtm_mb_read,
+ .write = atmel_qtm_mb_write,
+};
+
+/*
+ * From QTM MB configuration, we can't retrieve all the information needed
+ * to setup correctly input devices: buttons key codes and slider axis are
+ * missing.
+ */
+static int atmel_ptc_of_parse(struct atmel_ptc *ptc)
+{
+ struct device_node *sensor;
+ bool first_button = true;
+
+ /* Parse sensors. */
+ for_each_child_of_node(ptc->dev->of_node, sensor) {
+ if (!strcmp(sensor->name, "button")) {
+ uint32_t key_id, keycode;
+ struct input_dev *buttons = ptc->buttons_input;
+
+ if (of_property_read_u32(sensor, "reg", &key_id)) {
+ dev_err(ptc->dev, "reg is missing (%s)\n",
+ sensor->full_name);
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(sensor, "linux,keycode", &keycode)) {
+ dev_err(ptc->dev, "linux,keycode is missing (%s)\n",
+ sensor->full_name);
+ return -EINVAL;
+ }
+ ptc->button_keycode[key_id] = keycode;
+
+ /* All buttons are put together in a keyboard device. */
+ if (first_button) {
+ buttons = devm_input_allocate_device(ptc->dev);
+ if (!buttons)
+ return -ENOMEM;
+ buttons->name = "atmel_ptc_buttons";
+ buttons->dev.parent = ptc->dev;
+ buttons->keycode = ptc->button_keycode;
+ buttons->keycodesize = sizeof(ptc->button_keycode[0]);
+ buttons->keycodemax = ATMEL_PTC_MAX_NODES;
+ ptc->buttons_input = buttons;
+ first_button = false;
+ }
+
+ input_set_capability(buttons, EV_KEY, keycode);
+ } else if (!strcmp(sensor->name, "slider") ||
+ !strcmp(sensor->name, "wheel")) {
+ uint32_t scroller_id;
+ struct input_dev *scroller;
+
+ if (of_property_read_u32(sensor, "reg", &scroller_id)) {
+ dev_err(ptc->dev, "reg is missing (%s)\n",
+ sensor->full_name);
+ return -EINVAL;
+ }
+
+ if (scroller_id > ATMEL_PTC_MAX_SCROLLERS - 1) {
+ dev_err(ptc->dev, "wrong scroller id (%s)\n",
+ sensor->full_name);
+ return -EINVAL;
+ }
+
+ scroller = devm_input_allocate_device(ptc->dev);
+ if (!scroller)
+ return -ENOMEM;
+
+ scroller->dev.parent = ptc->dev;
+ ptc->scroller_input[scroller_id] = scroller;
+
+ if (!strcmp(sensor->name, "slider")) {
+ scroller->name = "atmel_ptc_slider";
+ input_set_capability(scroller, EV_ABS, ABS_X);
+ input_set_capability(scroller, EV_KEY, BTN_TOUCH);
+ } else {
+ scroller->name = "atmel_ptc_wheel";
+ input_set_capability(scroller, EV_ABS, ABS_WHEEL);
+ input_set_capability(scroller, EV_KEY, BTN_TOUCH);
+ }
+ } else {
+ dev_err(ptc->dev, "%s is not supported\n", sensor->name);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static void atmel_qtm_conf_callback(const struct firmware *conf, void *context)
+{
+ struct atmel_ptc *ptc = context;
+ unsigned int qtm_conf_size = sizeof(struct atmel_qtm_mailbox)
+ - offsetof(struct atmel_qtm_mailbox, node_group_config);
+ struct atmel_qtm_cmd qtm_cmd;
+ char *dst;
+
+ if (!conf) {
+ dev_err(ptc->dev, "cannot load QTM configuration, "
+ "it has to be set manually.\n");
+ return;
+ }
+
+ if (!conf->size || conf->size != qtm_conf_size) {
+ dev_err(ptc->dev, "incorrect QTM configuration file (size must be %u bytes), "
+ "configuration has to be set manually.\n", qtm_conf_size);
+ return;
+ }
+
+ atmel_ppp_irq_enable(ptc, ATMEL_PPP_IRQ1);
+ atmel_ppp_irq_disable(ptc, ATMEL_PPP_IRQ2 | ATMEL_PPP_IRQ3);
+
+ qtm_cmd.id = QTM_CMD_STOP;
+ atmel_qtm_cmd_send(ptc, &qtm_cmd);
+
+ /* Load QTM configuration. */
+ dst = (char *)ptc->qtm_mb +
+ offsetof(struct atmel_qtm_mailbox, node_group_config);
+ _memcpy_toio(dst, conf->data, qtm_conf_size);
+ release_firmware(conf);
+
+ if (atmel_ptc_of_parse(ptc))
+ dev_err(ptc->dev, "ptc_of_parse failed\n");
+
+ /* Start QTM. */
+ qtm_cmd.id = QTM_CMD_INIT;
+ qtm_cmd.data = ptc->qtm_mb->node_group_config.count;
+ atmel_qtm_cmd_send(ptc, &qtm_cmd);
+ qtm_cmd.id = QTM_CMD_SET_ACQ_MODE_TIMER;
+ qtm_cmd.data = 20;
+ atmel_qtm_cmd_send(ptc, &qtm_cmd);
+ qtm_cmd.id = QTM_CMD_RUN;
+ qtm_cmd.data = ptc->qtm_mb->node_group_config.count;
+ atmel_qtm_cmd_send(ptc, &qtm_cmd);
+}
+
+static void atmel_ppp_fw_callback(const struct firmware *fw, void *context)
+{
+ struct atmel_ptc *ptc = context;
+ int ret;
+ uint32_t firm_version;
+ struct atmel_qtm_cmd cmd;
+
+ if (!fw || !fw->size) {
+ dev_err(ptc->dev, "cannot load firmware.\n");
+ release_firmware(fw);
+ device_release_driver(ptc->dev);
+ return;
+ }
+
+ /* Command sequence to start from a clean state. */
+ atmel_ppp_cmd_send(ptc, ATMEL_PPP_CMD_ABORT);
+ atmel_ppp_irq_pending_clr(ptc, ATMEL_PPP_IRQ_MASK);
+ atmel_ppp_cmd_send(ptc, ATMEL_PPP_CMD_RESET);
+
+ _memcpy_toio(ptc->firmware, fw->data, fw->size);
+ release_firmware(fw);
+
+ atmel_ppp_cmd_send(ptc, ATMEL_PPP_CMD_RUN);
+
+ cmd.id = QTM_CMD_FIRM_VERSION;
+ firm_version = atmel_qtm_cmd_send(ptc, &cmd);
+ dev_info(ptc->dev, "firmware version: %u\n", firm_version);
+
+ /* PPP is running, it's time to load the QTM configuration. */
+ ret = request_firmware_nowait(THIS_MODULE, 1, QTM_CONF_NAME, ptc->dev,
+ GFP_KERNEL, ptc, atmel_qtm_conf_callback);
+ if (ret)
+ dev_err(ptc->dev, "QTM configuration loading failed.\n");
+}
+
+static int atmel_ptc_probe(struct platform_device *pdev)
+{
+ struct atmel_ptc *ptc;
+ struct resource *res;
+ void *shared_memory;
+ int ret;
+
+ ptc = devm_kzalloc(&pdev->dev, sizeof(*ptc), GFP_KERNEL);
+ if (!ptc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ptc);
+ ptc->dev = &pdev->dev;
+ ptc->dev->driver_data = ptc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ shared_memory = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(shared_memory))
+ return PTR_ERR(shared_memory);
+
+ ptc->firmware = shared_memory;
+ ptc->qtm_mb = shared_memory + ATMEL_QTM_MB_OFFSET;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -EINVAL;
+
+ ptc->ppp_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ptc->ppp_regs))
+ return PTR_ERR(ptc->ppp_regs);
+
+ ptc->irq = platform_get_irq(pdev, 0);
+ if (ptc->irq <= 0) {
+ if (!ptc->irq)
+ ptc->irq = -ENXIO;
+
+ return ptc->irq;
+ }
+
+ ptc->clk_per = devm_clk_get(&pdev->dev, "ptc_clk");
+ if (IS_ERR(ptc->clk_per))
+ return PTR_ERR(ptc->clk_per);
+
+ ptc->clk_int_osc = devm_clk_get(&pdev->dev, "ptc_int_osc");
+ if (IS_ERR(ptc->clk_int_osc))
+ return PTR_ERR(ptc->clk_int_osc);
+
+ ptc->clk_slow = devm_clk_get(&pdev->dev, "slow_clk");
+ if (IS_ERR(ptc->clk_slow))
+ return PTR_ERR(ptc->clk_slow);
+
+ ret = devm_request_irq(&pdev->dev, ptc->irq, atmel_ppp_irq_handler, 0,
+ pdev->dev.driver->name, ptc);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(ptc->clk_int_osc);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(ptc->clk_per);
+ if (ret)
+ goto disable_clk_int_osc;
+
+ ret = clk_prepare_enable(ptc->clk_slow);
+ if (ret)
+ goto disable_clk_per;
+
+ /* Needed to avoid unexpected behaviors. */
+ memset(ptc->firmware, 0, ATMEL_QTM_MB_OFFSET + sizeof(*ptc->qtm_mb));
+ ptc->imr = 0;
+ init_completion(&ptc->ppp_ack);
+
+ /*
+ * Expose a file to give an access to the QTM mailbox to a user space
+ * application in order to configure it or to send commands.
+ */
+ ret = sysfs_create_bin_file(&pdev->dev.kobj, &atmel_ptc_qtm_mb_attr);
+ if (ret)
+ goto disable_clk_slow;
+
+ ret = request_firmware_nowait(THIS_MODULE, 1, PPP_FIRMWARE_NAME,
+ ptc->dev, GFP_KERNEL, ptc,
+ atmel_ppp_fw_callback);
+ if (ret) {
+ dev_err(&pdev->dev, "firmware loading failed\n");
+ ret = -EPROBE_DEFER;
+ goto remove_qtm_mb;
+ }
+
+ return 0;
+
+remove_qtm_mb:
+ sysfs_remove_bin_file(&pdev->dev.kobj, &atmel_ptc_qtm_mb_attr);
+disable_clk_slow:
+ clk_disable_unprepare(ptc->clk_slow);
+disable_clk_per:
+ clk_disable_unprepare(ptc->clk_per);
+disable_clk_int_osc:
+ clk_disable_unprepare(ptc->clk_int_osc);
+
+ return ret;
+}
+
+static int atmel_ptc_remove(struct platform_device *pdev)
+{
+ struct atmel_ptc *ptc = platform_get_drvdata(pdev);
+ int i;
+
+ if (ptc->buttons_registered)
+ input_unregister_device(ptc->buttons_input);
+
+ for (i = 0; i < ATMEL_PTC_MAX_SCROLLERS; i++) {
+ struct input_dev *scroller = ptc->scroller_input[i];
+
+ if (!scroller || !ptc->scroller_registered[i])
+ continue;
+ input_unregister_device(scroller);
+ }
+
+ sysfs_remove_bin_file(&pdev->dev.kobj, &atmel_ptc_qtm_mb_attr);
+ clk_disable_unprepare(ptc->clk_slow);
+ clk_disable_unprepare(ptc->clk_per);
+ clk_disable_unprepare(ptc->clk_int_osc);
+
+ return 0;
+}
+
+static const struct of_device_id atmel_ptc_dt_match[] = {
+ {
+ .compatible = "atmel,sama5d2-ptc",
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, atmel_ptc_dt_match);
+
+static struct platform_driver atmel_ptc_driver = {
+ .probe = atmel_ptc_probe,
+ .remove = atmel_ptc_remove,
+ .driver = {
+ .name = "atmel_ptc",
+ .of_match_table = atmel_ptc_dt_match,
+ },
+};
+module_platform_driver(atmel_ptc_driver)
+
+MODULE_AUTHOR("Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>");
+MODULE_DESCRIPTION("Atmel PTC subsystem");
+MODULE_LICENSE("GPL v2");
+MODULE_FIRMWARE(PPP_FIRMWARE_NAME);
+MODULE_FIRMWARE(QTM_CONF_NAME);
diff --git a/include/uapi/linux/atmel_ptc.h b/include/uapi/linux/atmel_ptc.h
new file mode 100644
index 0000000..d15c4df
--- /dev/null
+++ b/include/uapi/linux/atmel_ptc.h
@@ -0,0 +1,355 @@
+/*
+ * Atmel PTC subsystem driver for SAMA5D2 devices and compatible.
+ *
+ * Copyright (C) 2017 Microchip,
+ * 2017 Ludovic Desroches <ludovic.desroches-UWL1GkI3JZL3oGB3hsPCZA@public.gmane.org>
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _LINUX_ATMEL_PTC_H
+#define _LINUX_ATMEL_PTC_H
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+#define ATMEL_PTC_MAX_NODES 64
+#define ATMEL_PTC_MAX_SCROLLERS 4
+
+enum atmel_qtm_command {
+ QTM_CMD_FIRM_VERSION = 8,
+ QTM_CMD_ACQ = 17,
+ QTM_CMD_INIT = 18,
+ QTM_CMD_RUN = 19,
+ QTM_CMD_STATUS = 20,
+ QTM_CMD_STOP = 21,
+ QTM_CMD_UPDATE_TOUCH_CFG = 22,
+ QTM_CMD_SET_ACQ_MODE_ON_DEMAND = 23,
+ QTM_CMD_SET_ACQ_MODE_TIMER = 24,
+ QTM_CMD_SET_ACQ_MODE_WCOMP = 25,
+ QTM_CMD_SET_TIMER_INTERVAL = 26,
+ QTM_CMD_STOP_TIMER = 27,
+ QTM_CMD_START_TIMER = 28,
+ QTM_CMD_RESET = 29,
+};
+
+enum atmel_ptc_type {
+ PTC_TYPE_MUTUAL = 0x40,
+ PTC_TYPE_SELFCAP = 0x80,
+};
+
+enum atmel_ptc_scroller_type {
+ QTM_SCROLLER_TYPE_SLIDER,
+ QTM_SCROLLER_TYPE_WHEEL,
+};
+
+enum atmel_ptc_scan {
+ PTC_SCAN_EXTINT_0 = 1,
+ PTC_SCAN_TC2_COMPA = 2,
+ PTC_SCAN_TC2_OVF = 3,
+ PTC_SCAN_4MS = 8,
+ PTC_SCAN_8MS = 9,
+ PTC_SCAN_16MS = 10,
+ PTC_SCAN_32MS = 11,
+ PTC_SCAN_64MS = 12,
+ PTC_SCAN_128MS = 13,
+ PTC_SCAN_256MS = 14,
+};
+
+enum atmel_ptc_cal_charge {
+ PTC_CAL_CHRG_2TAU,
+ PTC_CAL_CHRG_3TAU,
+ PTC_CAL_CHRG_4TAU,
+ PTC_CAL_CHRG_5TAU,
+};
+
+enum atmel_ptc_cal_auto_tune {
+ PTC_CAL_AUTO_TUNE_NONE,
+ PTC_CAL_AUTO_TUNE_RSEL,
+ PTC_CAL_AUTO_TUNE_PRSC,
+ PTC_CAL_AUTO_TUNE_CSD,
+};
+
+enum atmel_qtm_key_state {
+ QTM_KEY_STATE_DISABLE,
+ QTM_KEY_STATE_INIT,
+ QTM_KEY_STATE_CAL,
+ QTM_KEY_STATE_NO_DET,
+ QTM_KEY_STATE_FILT_IN,
+ QTM_KEY_STATE_ANTI_TCH,
+ QTM_KEY_STATE_SUSPEND,
+ QTM_KEY_STATE_DETECT = 133,
+ QTM_KEY_STATE_FILT_OUT,
+};
+
+/*
+ * PTC acquisition frequency delay setting.
+ *
+ * The PTC acquisition frequency is dependent on the Generic clock
+ * input to PTC and PTC clock prescaler setting. This delay setting
+ * inserts "n" PTC clock cycles between consecutive measurements on
+ * a given sensor, thereby changing the PTC acquisition frequency.
+ * FREQ_HOP_SEL_1 setting inserts 1 PTC clock cycle between consecutive
+ * measurements. FREQ_HOP_SEL_14 setting inserts 14 PTC clock cycles.
+ * Hence, higher delay setting will increase the total time taken for
+ * capacitance measurement on a given sensor as compared to a lower
+ * delay setting.
+ *
+ * A desired setting can be used to avoid noise around the same frequency
+ * as the acquisition frequency.
+ */
+enum atmel_ptc_freq_sel {
+ PTC_FREQ_SEL_0,
+ PTC_FREQ_SEL_1,
+ PTC_FREQ_SEL_2,
+ PTC_FREQ_SEL_3,
+ PTC_FREQ_SEL_4,
+ PTC_FREQ_SEL_5,
+ PTC_FREQ_SEL_6,
+ PTC_FREQ_SEL_7,
+ PTC_FREQ_SEL_8,
+ PTC_FREQ_SEL_9,
+ PTC_FREQ_SEL_10,
+ PTC_FREQ_SEL_11,
+ PTC_FREQ_SEL_12,
+ PTC_FREQ_SEL_13,
+ PTC_FREQ_SEL_14,
+ PTC_FREQ_SEL_15,
+ PTC_FREQ_SEL_SPREAD,
+};
+
+/*
+ * Series resistor setting. For Mutual cap mode, this series
+ * resistor is switched internally on the Y-pin. For Self cap mode,
+ * this series resistor is switched internally on the Sensor pin.
+ */
+enum atmel_ptc_rsel_val {
+ PTC_RSEL_0,
+ PTC_RSEL_20,
+ PTC_RSEL_50,
+ PTC_RSEL_100,
+};
+
+enum atmel_ptc_prsc_div_sel {
+ PTC_PRSC_DIV_1,
+ PTC_PRSC_DIV_2,
+ PTC_PRSC_DIV_4,
+ PTC_PRSC_DIV_8,
+};
+
+enum atmel_ptc_gain {
+ PTC_GAIN_1,
+ PTC_GAIN_2,
+ PTC_GAIN_4,
+ PTC_GAIN_8,
+ PTC_GAIN_16,
+ PTC_GAIN_32,
+};
+
+enum atmel_ptc_filter_level {
+ PTC_FILTER_LEVEL_1,
+ PTC_FILTER_LEVEL_2,
+ PTC_FILTER_LEVEL_4,
+ PTC_FILTER_LEVEL_8,
+ PTC_FILTER_LEVEL_16,
+ PTC_FILTER_LEVEL_32,
+ PTC_FILTER_LEVEL_64,
+};
+
+enum atmel_ptc_aks_group {
+ QTM_KEY_NO_AKS_GROUP,
+ QTM_KEY_AKS_GROUP_1,
+ QTM_KEY_AKS_GROUP_2,
+ QTM_KEY_AKS_GROUP_3,
+ QTM_KEY_AKS_GROUP_4,
+ QTM_KEY_AKS_GROUP_5,
+ QTM_KEY_AKS_GROUP_6,
+ QTM_KEY_AKS_GROUP_7,
+ MAX_QTM_KEY_AKS_GROUP,
+};
+
+enum atmel_ptc_key_hysteresis {
+ QTM_KEY_HYST_50,
+ QTM_KEY_HYST_25,
+ QTM_KEY_HYST_12_5,
+ QTM_KEY_HYST_6_25,
+ MAX_QTM_KEY_HYST,
+};
+
+enum atmel_ptc_key_recal_thr {
+ QTM_KEY_RECAL_THR_100,
+ QTM_KEY_RECAL_THR_50,
+ QTM_KEY_RECAL_THR_25,
+ QTM_KEY_RECAL_THR_12_5,
+ QTM_KEY_RECAL_THR_6_25,
+ MAX_QTM_KEY_RECAL_THR,
+};
+
+/*
+ * Reburst mode:
+ * 0 = none (application calls only)
+ * 1 = Unresolved - i.e. sensors in process of calibration / filter in / filter out and AKS groups
+ * 2 = All keys
+ */
+enum atmel_ptc_key_reburst {
+ QTM_KEY_REBURST_NONE,
+ QTM_KEY_REBURST_UNRESOLVED,
+ QTM_KEY_REBURST_ALL,
+};
+
+struct atmel_qtm_cmd {
+ uint16_t id;
+ uint16_t addr;
+ uint32_t data;
+} __attribute__ ((packed));
+
+struct atmel_qtm_node_group_config {
+ uint16_t count; /* Number of sensor nodes */
+ uint8_t ptc_type; /* Self or mutual sensors */
+ uint8_t freq_option; /* SDS or ASDV setting */
+ uint8_t calib_option; /* Hardware tuning: XX | TT 3/4/5 Tau | X | XX None/RSEL/PRSC/CSD */
+ uint8_t unused;
+} __attribute__ ((packed));
+
+struct atmel_qtm_node_config {
+ uint16_t mask_x; /* Selects the X Pins for this node (NONE for selfcapacitance configuration) */
+ uint32_t mask_y; /* Selects the Y Pins for this node */
+ uint8_t csd; /* Charge Share Delay */
+ uint8_t rsel; /* Resistor */
+ uint8_t prsc; /* Prescaler */
+ uint8_t gain_analog; /* Analog gain setting (Cint Selection) */
+ uint8_t gain_digital; /* Digital gain (Accum / Dec) */
+ uint8_t oversampling; /* Accumulator setting */
+} __attribute__ ((packed));
+
+struct atmel_qtm_node_data {
+ uint8_t status;
+ uint8_t unused;
+ uint16_t signals;
+ uint16_t comp_caps;
+} __attribute__ ((packed));
+
+struct atmel_qtm_key_config {
+ uint8_t threshold; /* Touch detection threshold */
+ uint8_t hysteresis; /* Percentage of threshold reduction to exit detect state */
+ uint8_t aks_group; /* 0 = None, 1-255 = group number */
+ uint8_t unused;
+} __attribute__ ((packed));
+
+struct atmel_qtm_key_group_config {
+ uint16_t count; /* Number of sensors */
+ uint8_t touch_di; /* Count in to Detect */
+ uint8_t max_on_time; /* Max on duration x 200ms */
+ uint8_t anti_touch_di; /* Count in to Anti-touch recal */
+ uint8_t anti_touch_recal_thr; /* Anti-touch recal threshold % */
+ uint8_t touch_drift_rate; /* One count per <200> ms */
+ uint8_t anti_touch_drift_rate; /* One count per <200> ms */
+ uint8_t drift_hold_time; /* Drift hold time */
+ uint8_t reburst_mode; /* None / Unresolved / All */
+} __attribute__ ((packed));
+
+struct atmel_qtm_key_data {
+ uint8_t status; /* Disabled, Off, On, Filter, Cal... */
+ uint8_t status_counter; /* State counter */
+ uint16_t node_struct_ptr; /* Pointer to node struct */
+ uint16_t reference; /* Reference signal */
+} __attribute__ ((packed));
+
+struct atmel_qtm_auto_scan_config {
+ uint16_t unused;
+ uint16_t node_number; /* Node Index that will be used */
+ uint8_t node_threshold;
+ uint8_t trigger;
+} __attribute__ ((packed));
+
+struct atmel_qtm_scroller_group_config {
+ uint16_t key_data;
+ uint8_t count;
+ uint8_t unused;
+} __attribute__ ((packed));
+
+struct atmel_qtm_scroller_config {
+ uint8_t type;
+ uint8_t unused;
+ uint16_t key_start;
+ uint8_t key_count;
+ uint8_t resol_deadband;
+ uint8_t position_hysteresis;
+ uint8_t unused2;
+ uint16_t contact_min_threshold;
+} __attribute__ ((packed));
+
+struct atmel_qtm_scroller_data {
+ uint8_t status;
+ uint8_t right_hyst;
+ uint8_t left_hyst;
+ uint8_t unused;
+ uint16_t raw_position;
+ uint16_t position;
+ uint16_t contact_size;
+} __attribute__ ((packed));
+
+struct atmel_qtm_fh_autotune_config {
+ uint8_t count; /* Number of sensors */
+ uint8_t num_freqs;
+ uint16_t freq_option_select;
+ uint16_t median_filter_freq; /* PTC frequencies to be used on the median filter samples */
+ uint8_t enable_freq_autotune;
+ uint8_t max_variance_limit;
+ uint8_t autotune_count_in_limit;
+ uint8_t unused;
+} __attribute__ ((packed));
+
+struct atmel_qtm_fh_autotune_data {
+ uint8_t status; /* Obligatory status byte: Bit 7 = Reburst... */
+ uint8_t current_freq; /* PTC Sampling Delay Selection - 0 to 15 PTC CLK cycles */
+ uint16_t filter_buffer; /* Filter buffer used to store past cycle signal values of sensor */
+ uint16_t acq_node_data;
+ uint16_t freq_tune_count_ins;
+} __attribute__ ((packed));
+
+struct atmel_qtm_fh_freq {
+ uint8_t freq0;
+ uint8_t freq1;
+ uint8_t freq2;
+ uint8_t unused;
+} __attribute__ ((packed));
+
+struct atmel_qtm_touch_events {
+ uint32_t key_event_id[2];
+ uint32_t key_enable_state[2];
+ uint32_t scroller_event_id;
+ uint32_t scroller_event_state;
+} __attribute__ ((packed));
+
+struct atmel_qtm_mailbox {
+ struct atmel_qtm_cmd cmd;
+ uint8_t unused[248];
+ struct atmel_qtm_node_group_config node_group_config;
+ struct atmel_qtm_node_config node_config[ATMEL_PTC_MAX_NODES];
+ struct atmel_qtm_node_data node_data[ATMEL_PTC_MAX_NODES];
+ struct atmel_qtm_key_group_config key_group_config;
+ struct atmel_qtm_key_config key_config[ATMEL_PTC_MAX_NODES];
+ struct atmel_qtm_key_data key_data[ATMEL_PTC_MAX_NODES];
+ struct atmel_qtm_auto_scan_config auto_scan_config;
+ struct atmel_qtm_scroller_group_config scroller_group_config;
+ struct atmel_qtm_scroller_config scroller_config[ATMEL_PTC_MAX_SCROLLERS];
+ struct atmel_qtm_scroller_data scroller_data[ATMEL_PTC_MAX_SCROLLERS];
+ struct atmel_qtm_fh_autotune_config fh_autotune_config;
+ struct atmel_qtm_fh_autotune_data fh_autotune_data;
+ struct atmel_qtm_fh_freq fh_freq;
+ struct atmel_qtm_touch_events touch_events;
+} __attribute__ ((packed));
+
+#endif /* _LINUX_ATMEL_PTC_H */
--
2.9.0
--
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
* [PATCH 0/4] Introduce the Atmel PTC subsystem
From: Ludovic Desroches @ 2017-03-31 15:22 UTC (permalink / raw)
To: linux-input, linux-arm-kernel, devicetree
Cc: dmitry.torokhov, nicolas.ferre, alexandre.belloni, linux-kernel,
Ludovic Desroches
Hi,
The Atmel Peripheral touch controller subsystem offers built-in hardware for
capacitive touch measurment on sensors that function as buttons, sliders and
wheels. It is available on SAMA5D2.
A firmware and a configuration file describing the topology and the parameters
of the sensor are loaded when probing the driver.
Ludovic Desroches (4):
input: misc: introduce Atmel PTC driver
ARM: dts: at91: sama5d2: add PTC subsystem device
MAINTAINERS: add Atmel PTC entries
dt-bindings: input: Add Atmel PTC subsystem bindings
.../devicetree/bindings/input/atmel,ptc.txt | 67 +++
MAINTAINERS | 7 +
arch/arm/boot/dts/sama5d2.dtsi | 16 +
drivers/input/misc/Kconfig | 12 +
drivers/input/misc/Makefile | 1 +
drivers/input/misc/atmel_ptc.c | 651 +++++++++++++++++++++
include/uapi/linux/atmel_ptc.h | 355 +++++++++++
7 files changed, 1109 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/atmel,ptc.txt
create mode 100644 drivers/input/misc/atmel_ptc.c
create mode 100644 include/uapi/linux/atmel_ptc.h
--
2.9.0
^ permalink raw reply
* Re: [PATCH V2 2/2] thermal: broadcom: add Northstar thermal driver
From: Rafał Miłecki @ 2017-03-31 14:49 UTC (permalink / raw)
To: Jon Mason, Rafał Miłecki
Cc: Mark Rutland,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
Florian Fainelli, Scott Branden, Stephen Warren, Ray Jui,
linux-pm, Lee Jones, Eduardo Valentin, Eric Anholt, Rob Herring,
BCM Kernel Feedback, linux-rpi-kernel, Zhang Rui,
linux-arm-kernel
In-Reply-To: <CAC3K-4q=npvHBjb2YeWmyCv89r14=vXdUzRW74mcrETs+NRh1Q@mail.gmail.com>
On 03/31/2017 04:23 PM, Jon Mason wrote:
> On Fri, Mar 31, 2017 at 3:03 AM, Rafał Miłecki <zajec5@gmail.com> wrote:
>> On 03/24/2017 03:35 PM, Jon Mason wrote:
>>>
>>> On Thu, Mar 23, 2017 at 11:30:45PM +0100, Rafał Miłecki wrote:
>>>>
>>>> diff --git a/drivers/thermal/broadcom/ns-thermal.c
>>>> b/drivers/thermal/broadcom/ns-thermal.c
>>>> new file mode 100644
>>>> index 000000000000..acf3a4de62a4
>>>> --- /dev/null
>>>> +++ b/drivers/thermal/broadcom/ns-thermal.c
>>>> @@ -0,0 +1,98 @@
>>>> +/*
>>>> + * Copyright (C) 2017 Rafał Miłecki <rafal@milecki.pl>
>>>> + *
>>>> + * This program is free software; you can redistribute it and/or modify
>>>> + * it under the terms of the GNU General Public License version 2 as
>>>> + * published by the Free Software Foundation.
>>>> + */
>>>> +
>>>> +#include <linux/module.h>
>>>> +#include <linux/of_address.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/thermal.h>
>>>> +
>>>> +#define PVTMON_CONTROL0 0x00
>>>> +#define PVTMON_CONTROL0_SEL_MASK 0x0000000e
>>>> +#define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000
>>>> +#define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e
>>>> +#define PVTMON_STATUS 0x08
>>>> +
>>>> +struct ns_thermal {
>>>> + void __iomem *pvtmon;
>>>> +};
>>>> +
>>>> +static int ns_thermal_get_temp(void *data, int *temp)
>>>> +{
>>>> + struct ns_thermal *ns_thermal = data;
>>>> + u32 val;
>>>> +
>>>> + val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
>>>> + if ((val & PVTMON_CONTROL0_SEL_MASK) !=
>>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
>>>> + val &= ~PVTMON_CONTROL0_SEL_MASK;
>>>> + val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
>>>
>>>
>>> I think this is slightly confusing here. If this was off, ORing in 0
>>> will not enable it. I think we need to flip the #define to make it
>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE (or a less crappy name).
>>> then use this line here to toggle it. Something like
>>>
>>> val &= ~PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE;
>>
>>
>> I don't understand this, can you help me further?
>>
>> OR-ing with 0 is only a cosmetic thing obviously - just to make it clear
>> which
>> value we expect to be set in bits 1:3. The important part is:
>> val &= ~PVTMON_CONTROL0_SEL_MASK;
>
> You are using a side effect of the masking to clear/enable the block.
> I'm simply saying that we should be explicit about enabling it. My
> concern is that using the side effect hides what is being done and
> could result in a bug somewhere down the line. I think this is
> improbable based on the code, but wanted to err on the side of
> caution.
Well, I'm clearing current mode selection and "selecting" the mode I want. By
OR-ing PVTMON_CONTROL0_SEL_TEMP_MONITOR I'm clearly indicating I want temp
monitor more.
How else I could make it more obvious? Should I add some comment maybe?
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* Re: [PATCH V2 2/2] thermal: broadcom: add Northstar thermal driver
From: Jon Mason @ 2017-03-31 14:23 UTC (permalink / raw)
To: Rafał Miłecki
Cc: Zhang Rui, Eduardo Valentin, Rob Herring, Mark Rutland,
Stephen Warren, Lee Jones, Eric Anholt, Florian Fainelli, Ray Jui,
Scott Branden, BCM Kernel Feedback,
linux-pm-u79uwXL29TY76Z2rM5mHXA,
open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel, Rafał Miłecki
In-Reply-To: <d678d252-a95a-58c0-8098-4401c67040a1-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Fri, Mar 31, 2017 at 3:03 AM, Rafał Miłecki <zajec5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> On 03/24/2017 03:35 PM, Jon Mason wrote:
>>
>> On Thu, Mar 23, 2017 at 11:30:45PM +0100, Rafał Miłecki wrote:
>>>
>>> diff --git a/drivers/thermal/broadcom/ns-thermal.c
>>> b/drivers/thermal/broadcom/ns-thermal.c
>>> new file mode 100644
>>> index 000000000000..acf3a4de62a4
>>> --- /dev/null
>>> +++ b/drivers/thermal/broadcom/ns-thermal.c
>>> @@ -0,0 +1,98 @@
>>> +/*
>>> + * Copyright (C) 2017 Rafał Miłecki <rafal-g1n6cQUeyibVItvQsEIGlw@public.gmane.org>
>>> + *
>>> + * This program is free software; you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License version 2 as
>>> + * published by the Free Software Foundation.
>>> + */
>>> +
>>> +#include <linux/module.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/thermal.h>
>>> +
>>> +#define PVTMON_CONTROL0 0x00
>>> +#define PVTMON_CONTROL0_SEL_MASK 0x0000000e
>>> +#define PVTMON_CONTROL0_SEL_TEMP_MONITOR 0x00000000
>>> +#define PVTMON_CONTROL0_SEL_TEST_MODE 0x0000000e
>>> +#define PVTMON_STATUS 0x08
>>> +
>>> +struct ns_thermal {
>>> + void __iomem *pvtmon;
>>> +};
>>> +
>>> +static int ns_thermal_get_temp(void *data, int *temp)
>>> +{
>>> + struct ns_thermal *ns_thermal = data;
>>> + u32 val;
>>> +
>>> + val = readl(ns_thermal->pvtmon + PVTMON_CONTROL0);
>>> + if ((val & PVTMON_CONTROL0_SEL_MASK) !=
>>> PVTMON_CONTROL0_SEL_TEMP_MONITOR) {
>>> + val &= ~PVTMON_CONTROL0_SEL_MASK;
>>> + val |= PVTMON_CONTROL0_SEL_TEMP_MONITOR;
>>
>>
>> I think this is slightly confusing here. If this was off, ORing in 0
>> will not enable it. I think we need to flip the #define to make it
>> PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE (or a less crappy name).
>> then use this line here to toggle it. Something like
>>
>> val &= ~PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE;
>
>
> I don't understand this, can you help me further?
>
> OR-ing with 0 is only a cosmetic thing obviously - just to make it clear
> which
> value we expect to be set in bits 1:3. The important part is:
> val &= ~PVTMON_CONTROL0_SEL_MASK;
You are using a side effect of the masking to clear/enable the block.
I'm simply saying that we should be explicit about enabling it. My
concern is that using the side effect hides what is being done and
could result in a bug somewhere down the line. I think this is
improbable based on the code, but wanted to err on the side of
caution.
>
> AFAIU selecting any mode other than TEMP_MONITOR will disable monitor
> access.
> AFAIU even switchint to TEST_MODE will prevent access to temp, so I don't
> see
> how we could use PVTMON_CONTROL0_SEL_TEMP_MONITOR_DISABLE. It could be any
> value other than 0.
--
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