Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4] ARM64: dts: meson-gx: Add reserved memory zone and usable memory range
From: Kevin Hilman @ 2017-01-13 20:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484129414-23325-1-git-send-email-narmstrong@baylibre.com>

Neil Armstrong <narmstrong@baylibre.com> writes:

> The Amlogic Meson GXBB/GXL/GXM secure monitor uses part of the memory space,
> this patch adds this reserved zone and redefines the usable memory range.
>
> The memory node is also moved from the dtsi files into the proper dts files
> to handle variants memory sizes.
>
> This patch also fixes the memory sizes for the following platforms :
> - gxl-s905x-p212 : 1GiB instead of 2GiB, a proper 2GiB dts should be pushed
> - gxm-s912-q201 : 1GiB instead of 2GiB, a proper 2GiB dts should be pushed
> - gxl-s905d-p231 : 1GiB instead of 2GiB, a proper 2GiB dts should be pushed
> - gxl-nexbox-a95x : 1GiB instead of 2GiB, a proper 2GiB dts should be pushed
>
> Signed-off-by: Neil Armstrong <narmstrong@baylibre.com>

Queued for v4.10-rc.

Kevin

^ permalink raw reply

* [PATCH v6 23/25] usb: chipidea: Pullup D+ in device mode via phy APIs
From: Stephen Boyd @ 2017-01-13 20:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170113033536.GA20723@b29397-desktop>

Quoting Peter Chen (2017-01-12 19:35:36)
> On Thu, Jan 12, 2017 at 02:49:51PM -0800, Stephen Boyd wrote:
> > 
> > With the boards I have, vbus is not routed to the phy. Instead, there's
> > a vbus comparator on the PMIC where the vbus line from the usb
> > receptacle is sent. The vbus extcon driver probes the comparator on the
> > PMIC to see if vbus is present or not and then notifies extcon users
> > when vbus changes.
> > 
> > The ULPI register we write in the phy is a vendor specific register
> > (called MISC_A) that has two bits. If you look at
> > qcom_usb_hs_phy_set_mode() in this series you'll see that we set
> > VBUSVLDEXTSEL and VBUSVLDEXT. VBUSVLDEXTSEL controls a mux in the phy
> > that chooses between an internal comparator, in the case where vbus goes
> > to the phy, or an external signal input to the phy, VBUSVLDEXT, to
> > consider as the "session valid" signal. It looks like the session valid
> > signal drives the D+ pullup resistor in the phy. These bits in MISC_A
> > don't matter when the phy is in host mode.
> > 
> > So when the board doesn't route vbus to the phy, we have to toggle the
> > VBUSVLDEXT bit to signal to the phy that the vbus is there or not. I
> > also see that we're not supposed to toggle the VBUSVLDEXTSEL bit when in
> > "normal" operating mode. So perhaps we should do everything in the
> > qcom_usb_hs_phy_set_mode() routine during the role switch as you
> > suggest, except toggle the VBUSVLDEXT bit. Toggling the VBUSVLDEXT bit
> > can be done via some new phy op when the extcon triggers?
> 
> Why not call phy_set_mode(phy, DEVICE) directly at ci_handle_vbus_change when
> you get extcon vbus event?
> 

Right, I can call phy_set_mode(phy, DEVICE) there, but is that correct?
How do we signal vbus is gone, with phy_set_mode(phy, HOST)? Mode
doesn't seem the same as "vbus status changed" so this feels wrong.

^ permalink raw reply

* [PATCH v2 3/5] ARM: davinci_all_defconfig: enable iio and ADS7950
From: David Lechner @ 2017-01-13 20:02 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3c4f8952-0a64-fc49-bd87-452dbbf7a946@ti.com>

On 01/13/2017 06:24 AM, Sekhar Nori wrote:
> On Wednesday 11 January 2017 01:53 PM, Sekhar Nori wrote:

>> I do remember I did not see these two modules did not get enabled in
>> .config after 'make davinci_all_defconfig'. Will check what I may have
>> missed.
>
> So IIO_TRIGGERED_BUFFER is not selected in my tree because I dont have
> the ADS7950 driver enabled. Same thing with IIO_BUFFER.
>
> Can you try this patch over my tree?

I've got it sorted now and I have sent a new patch.

^ permalink raw reply

* [PATCH v2 2/2] ARM: davinci_all_defconfig: enable iio
From: David Lechner @ 2017-01-13 20:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484337612-11120-1-git-send-email-david@lechnology.com>

This enables the iio subsystem. This will be used by LEGO MINDSTORMS EV3,
which has an ADS7957 chip.

Signed-off-by: David Lechner <david@lechnology.com>
---
 arch/arm/configs/davinci_all_defconfig | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/arm/configs/davinci_all_defconfig b/arch/arm/configs/davinci_all_defconfig
index f598daa..8cc0409 100644
--- a/arch/arm/configs/davinci_all_defconfig
+++ b/arch/arm/configs/davinci_all_defconfig
@@ -201,6 +201,15 @@ CONFIG_TI_EDMA=y
 CONFIG_MEMORY=y
 CONFIG_TI_AEMIF=m
 CONFIG_DA8XX_DDRCTL=y
+CONFIG_IIO=m
+CONFIG_IIO_BUFFER=y
+CONFIG_IIO_BUFFER_CB=m
+CONFIG_IIO_KFIFO_BUF=m
+CONFIG_IIO_TRIGGER=y
+CONFIG_IIO_SW_DEVICE=m
+CONFIG_IIO_SW_TRIGGER=m
+CONFIG_IIO_HRTIMER_TRIGGER=m
+CONFIG_IIO_SYSFS_TRIGGER=m
 CONFIG_PWM=y
 CONFIG_PWM_TIECAP=m
 CONFIG_PWM_TIEHRPWM=m
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 1/2] ARM: davinci: Allocate extra interrupts
From: David Lechner @ 2017-01-13 20:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484337612-11120-1-git-send-email-david@lechnology.com>

This allocates extra interrupts for mach-davinci. These extra interrupts
are need for things like IIO triggers.

Signed-off-by: David Lechner <david@lechnology.com>
---
 arch/arm/mach-davinci/include/mach/irqs.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mach-davinci/include/mach/irqs.h b/arch/arm/mach-davinci/include/mach/irqs.h
index edb2ca6..2b56bb2 100644
--- a/arch/arm/mach-davinci/include/mach/irqs.h
+++ b/arch/arm/mach-davinci/include/mach/irqs.h
@@ -403,7 +403,9 @@
 
 /* da850 currently has the most gpio pins (144) */
 #define DAVINCI_N_GPIO			144
+/* Extra IRQs for things like IIO triggers */
+#define DAVINCI_N_SPARE_IRQ		16
 /* da850 currently has the most irqs so use DA850_N_CP_INTC_IRQ */
-#define NR_IRQS				(DA850_N_CP_INTC_IRQ + DAVINCI_N_GPIO)
+#define NR_IRQS (DA850_N_CP_INTC_IRQ + DAVINCI_N_GPIO + DAVINCI_N_SPARE_IRQ)
 
 #endif /* __ASM_ARCH_IRQS_H */
-- 
2.7.4

^ permalink raw reply related

* [PATCH v2 0/2] ARM: davinci_all_defconfig: enable iio
From: David Lechner @ 2017-01-13 20:00 UTC (permalink / raw)
  To: linux-arm-kernel

Following up on another conversation [1], this series includes a fixed up
patch to enable the iio subsystem in davinci_all_defconfig. I have also
included another patch to allocate extra interrupts that are needed for
iio triggers (this patch was previously submitted, but received no comments).

[1]: https://patchwork.kernel.org/patch/9500063/

David Lechner (2):
  ARM: davinci: Allocate extra interrupts
  ARM: davinci_all_defconfig: enable iio

 arch/arm/configs/davinci_all_defconfig    | 9 +++++++++
 arch/arm/mach-davinci/include/mach/irqs.h | 4 +++-
 2 files changed, 12 insertions(+), 1 deletion(-)

-- 
2.7.4

^ permalink raw reply

* [PATCH 3/4] iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs
From: Martin Blumenstingl @ 2017-01-13 19:57 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <aeafc889-0b2f-e341-5368-5c9d49caa9dd@gmail.com>

On Fri, Jan 13, 2017 at 8:35 PM, Heiner Kallweit <hkallweit1@gmail.com> wrote:
>> This adds support for the SAR (Successive Approximation Register) ADC
>> on the Amlogic Meson SoCs.
>>
>> The code is based on the public S805 (Meson8b) and S905 (GXBB)
>> datasheets, as well as by reading (various versions of) the vendor
>> driver and by inspecting the registers on the vendor kernels of my
>> testing-hardware.
>>
>> Currently the GXBB, GXL and GXM SoCs are supported. GXBB hardware has
>> 10-bit ADC resolution, while GXL and GXM have 12-bit ADC resolution.
>> The code was written to support older SoCs (Meson8 and Meson8b) as well,
>> but due to lack of actual testing-hardware no of_device_id was added for
>> these.
>>
>> Two "features" from the vendor driver are currently missing:
>> - the vendor driver uses channel #7 for calibration (this improves the
>>   accuracy of the results - in my tests the results were less than 3%
>>   off without calibration compared to the vendor driver). Adding support
>>   for this should be easy, but is not required for most applications.
>> - channel #6 is connected to the SoCs internal temperature sensor.
>>   Adding support for this is probably not so easy since (based on the
>>   u-boot sources) most SoC versions are using different registers and
>>   algorithms for the conversion from "ADC value" to temperature.
>>
>> Supported by the hardware but currently not supported by the driver:
>> - reading multiple channels at the same time (the hardware has a FIFO
>>   buffer which stores multiple results)
>> - continuous sampling (this would require a way to enable this
>>   individually because otherwise the ADC would be drawing power
>>   constantly)
>> - interrupt support (similar to the vendor driver this new driver is
>>   polling the results. It is unclear if the IRQ-mode is supported on
>>   older (Meson6 or Meson8) hardware as well or if there are any errata)
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
>> ---
>>  drivers/iio/adc/Kconfig        |  12 +
>>  drivers/iio/adc/Makefile       |   1 +
>>  drivers/iio/adc/meson_saradc.c | 860 +++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 873 insertions(+)
>>  create mode 100644 drivers/iio/adc/meson_saradc.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 9c8b558ba19e..86059b9b91bf 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -371,6 +371,18 @@ config MEN_Z188_ADC
>>         This driver can also be built as a module. If so, the module will be
>>         called men_z188_adc.
>>
>> +config MESON_SARADC
>> +     tristate "Amlogic Meson SAR ADC driver"
>> +     default ARCH_MESON
>> +     depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
>> +     select REGMAP_MMIO
>> +     help
>> +       Say yes here to build support for the SAR ADC found in Amlogic Meson
>> +       SoCs.
>> +
>> +       To compile this driver as a module, choose M here: the
>> +       module will be called meson_saradc.
>> +
>>  config MXS_LRADC
>>          tristate "Freescale i.MX23/i.MX28 LRADC"
>>          depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index d36c4be8d1fc..de05b9e75f8f 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -36,6 +36,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
>>  obj-$(CONFIG_MCP3422) += mcp3422.o
>>  obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
>> +obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
>>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>>  obj-$(CONFIG_NAU7802) += nau7802.o
>>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
>> diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
>> new file mode 100644
>> index 000000000000..06e8ac620385
>> --- /dev/null
>> +++ b/drivers/iio/adc/meson_saradc.c
>> @@ -0,0 +1,860 @@
>> +/*
>> + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
>> + *
>> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License
>> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/clk.h>
>> +#include <linux/completion.h>
>> +#include <linux/delay.h>
>> +#include <linux/reset.h>
>> +#include <linux/regmap.h>
>> +#include <linux/regulator/consumer.h>
>> +
>> +#define SAR_ADC_REG0                                         0x00
>> +     #define SAR_ADC_REG0_PANEL_DETECT                       BIT(31)
>> +     #define SAR_ADC_REG0_BUSY_MASK                          GENMASK(30, 28)
>> +     #define SAR_ADC_REG0_DELTA_BUSY                         BIT(30)
>> +     #define SAR_ADC_REG0_AVG_BUSY                           BIT(29)
>> +     #define SAR_ADC_REG0_SAMPLE_BUSY                        BIT(28)
>> +     #define SAR_ADC_REG0_FIFO_FULL                          BIT(27)
>> +     #define SAR_ADC_REG0_FIFO_EMPTY                         BIT(26)
>> +     #define SAR_ADC_REG0_FIFO_COUNT_MASK                    GENMASK(25, 21)
>> +     #define SAR_ADC_REG0_ADC_BIAS_CTRL_MASK                 GENMASK(20, 19)
>> +     #define SAR_ADC_REG0_CURR_CHAN_ID_MASK                  GENMASK(18, 16)
>> +     #define SAR_ADC_REG0_ADC_TEMP_SEN_SEL                   BIT(15)
>> +     #define SAR_ADC_REG0_SAMPLING_STOP                      BIT(14)
>> +     #define SAR_ADC_REG0_CHAN_DELTA_EN_MASK                 GENMASK(13, 12)
>> +     #define SAR_ADC_REG0_DETECT_IRQ_POL                     BIT(10)
>> +     #define SAR_ADC_REG0_DETECT_IRQ_EN                      BIT(9)
>> +     #define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK                  GENMASK(8, 4)
>> +     #define SAR_ADC_REG0_FIFO_IRQ_EN                        BIT(3)
>> +     #define SAR_ADC_REG0_SAMPLING_START                     BIT(2)
>> +     #define SAR_ADC_REG0_CONTINUOUS_EN                      BIT(1)
>> +     #define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE               BIT(0)
>> +
>> +#define SAR_ADC_CHAN_LIST                                    0x04
>> +     #define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK                GENMASK(26, 24)
>> +     #define SAR_ADC_CHAN_CHAN_ENTRY_MASK(_chan)             \
>> +                                     (GENMASK(2, 0) << (_chan * 3))
>> +
>> +#define SAR_ADC_AVG_CNTL                                     0x08
>> +     #define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan)          \
>> +                                     (16 + (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan)           \
>> +                                     (GENMASK(17, 16) << (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan)       \
>> +                                     (0 + (_chan * 2))
>> +     #define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan)        \
>> +                                     (GENMASK(1, 0) << (_chan * 2))
>> +
>> +#define SAR_ADC_REG3                                         0x0c
>> +     #define SAR_ADC_REG3_CNTL_USE_SC_DLY                    BIT(31)
>> +     #define SAR_ADC_REG3_CLK_EN                             BIT(30)
>> +     #define SAR_ADC_REG3_BL30_INITIALIZED                   BIT(28)
>> +     #define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN          BIT(27)
>> +     #define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE          BIT(26)
>> +     #define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK            GENMASK(25, 23)
>> +     #define SAR_ADC_REG3_DETECT_EN                          BIT(22)
>> +     #define SAR_ADC_REG3_ADC_EN                             BIT(21)
>> +     #define SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK            GENMASK(20, 18)
>> +     #define SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK        GENMASK(17, 16)
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_SHIFT                  10
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_WIDTH                  5
>> +     #define SAR_ADC_REG3_ADC_CLK_DIV_MASK                   GENMASK(15, 10)
>> +     #define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK                 GENMASK(9, 8)
>> +     #define SAR_ADC_REG3_BLOCK_DLY_MASK                     GENMASK(7, 0)
>> +
>> +#define SAR_ADC_DELAY                                                0x10
>> +     #define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK                GENMASK(25, 24)
>> +     #define SAR_ADC_DELAY_BL30_BUSY                         BIT(15)
>> +     #define SAR_ADC_DELAY_KERNEL_BUSY                       BIT(14)
>> +     #define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK                GENMASK(23, 16)
>> +     #define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK               GENMASK(9, 8)
>> +     #define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK               GENMASK(7, 0)
>> +
>> +#define SAR_ADC_LAST_RD                                              0x14
>> +     #define SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK              GENMASK(23, 16)
>> +     #define SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK              GENMASK(9, 0)
>> +
>> +#define SAR_ADC_FIFO_RD                                              0x18
>> +     #define SAR_ADC_FIFO_RD_CHAN_ID_MASK                    GENMASK(14, 12)
>> +     #define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK               GENMASK(11, 0)
>> +
>> +#define SAR_ADC_AUX_SW                                               0x1c
>> +     #define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)         \
>> +                                     (GENMASK(10, 8) << ((_chan - 2) * 2))
>> +     #define SAR_ADC_AUX_SW_VREF_P_MUX                       BIT(6)
>> +     #define SAR_ADC_AUX_SW_VREF_N_MUX                       BIT(5)
>> +     #define SAR_ADC_AUX_SW_MODE_SEL                         BIT(4)
>> +     #define SAR_ADC_AUX_SW_YP_DRIVE_SW                      BIT(3)
>> +     #define SAR_ADC_AUX_SW_XP_DRIVE_SW                      BIT(2)
>> +     #define SAR_ADC_AUX_SW_YM_DRIVE_SW                      BIT(1)
>> +     #define SAR_ADC_AUX_SW_XM_DRIVE_SW                      BIT(0)
>> +
>> +#define SAR_ADC_CHAN_10_SW                                   0x20
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK           GENMASK(25, 23)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX             BIT(22)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX             BIT(21)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL               BIT(20)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW            BIT(19)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW            BIT(18)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW            BIT(17)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW            BIT(16)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK           GENMASK(9, 7)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX             BIT(6)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX             BIT(5)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL               BIT(4)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW            BIT(3)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW            BIT(2)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW            BIT(1)
>> +     #define SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW            BIT(0)
>> +
>> +#define SAR_ADC_DETECT_IDLE_SW                                       0x24
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN             BIT(26)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK     GENMASK(25, 23)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_P_MUX   BIT(22)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_N_MUX   BIT(21)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL          BIT(20)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YP_DRIVE_SW  BIT(19)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XP_DRIVE_SW  BIT(18)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YM_DRIVE_SW  BIT(17)
>> +     #define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XM_DRIVE_SW  BIT(16)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK   GENMASK(9, 7)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_P_MUX     BIT(6)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_N_MUX     BIT(5)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL            BIT(4)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YP_DRIVE_SW    BIT(3)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XP_DRIVE_SW    BIT(2)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YM_DRIVE_SW    BIT(1)
>> +     #define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XM_DRIVE_SW    BIT(0)
>> +
>> +#define SAR_ADC_DELTA_10                                     0x28
>> +     #define SAR_ADC_DELTA_10_TEMP_SEL                       BIT(27)
>> +     #define SAR_ADC_DELTA_10_TS_REVE1                       BIT(26)
>> +     #define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_SHIFT        16
>> +     #define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK         GENMASK(25, 16)
>> +     #define SAR_ADC_DELTA_10_TS_REVE0                       BIT(15)
>> +     #define SAR_ADC_DELTA_10_TS_C_SHIFT                     11
>> +     #define SAR_ADC_DELTA_10_TS_C_MASK                      GENMASK(14, 11)
>> +     #define SAR_ADC_DELTA_10_TS_VBG_EN                      BIT(10)
>> +     #define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_SHIFT        0
>> +     #define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK         GENMASK(9, 0)
>> +
>> +/* NOTE: registers from here are undocumented (the vendor Linux kernel driver
>> + * and u-boot source served as reference). These only seem to be relevant on
>> + * GXBB and newer.
>> + */
>> +#define SAR_ADC_REG11                                                0x2c
>> +     #define SAR_ADC_REG11_BANDGAP_EN                        BIT(13)
>> +
>> +#define SAR_ADC_REG13                                                0x34
>> +     #define SAR_ADC_REG13_12BIT_CALIBRATION_MASK            GENMASK(13, 8)
>> +
>> +#define SAR_ADC_MAX_FIFO_SIZE                32
>> +#define SAR_ADC_NUM_CHANNELS         ARRAY_SIZE(meson_saradc_iio_channels)
>> +#define SAR_ADC_VALUE_MASK(_priv)    (BIT(_priv->resolution) - 1)
>> +
>> +#define MESON_SAR_ADC_CHAN(_chan, _type) {                           \
>> +     .type = _type,                                                  \
>> +     .indexed = true,                                                \
>> +     .channel = _chan,                                               \
>> +     .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |                  \
>> +                             BIT(IIO_CHAN_INFO_AVERAGE_RAW),         \
>> +     .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),           \
>> +     .datasheet_name = "SAR_ADC_CH"#_chan,                           \
>> +}
>> +
>> +/* TODO: the hardware supports IIO_TEMP for channel 6 as well which is
>> + * currently not supported by this driver.
>> + */
>> +static const struct iio_chan_spec meson_saradc_iio_channels[] = {
>> +     MESON_SAR_ADC_CHAN(0, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(1, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(2, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(3, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(4, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(5, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(6, IIO_VOLTAGE),
>> +     MESON_SAR_ADC_CHAN(7, IIO_VOLTAGE),
>> +     IIO_CHAN_SOFT_TIMESTAMP(8),
>> +};
>> +
>> +enum meson_saradc_avg_mode {
>> +     NO_AVERAGING = 0x0,
>> +     MEAN_AVERAGING = 0x1,
>> +     MEDIAN_AVERAGING = 0x2,
>> +};
>> +
>> +enum meson_saradc_num_samples {
>> +     ONE_SAMPLE = 0x0,
>> +     TWO_SAMPLES = 0x1,
>> +     FOUR_SAMPLES = 0x2,
>> +     EIGHT_SAMPLES = 0x3,
>> +};
>> +
>> +enum meson_saradc_chan7_mux_sel {
>> +     CHAN7_MUX_VSS = 0x0,
>> +     CHAN7_MUX_VDD_DIV4 = 0x1,
>> +     CHAN7_MUX_VDD_DIV2 = 0x2,
>> +     CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
>> +     CHAN7_MUX_VDD = 0x4,
>> +     CHAN7_MUX_CH7_INPUT = 0x7,
>> +};
>> +
>> +struct meson_saradc_priv {
>> +     struct regmap                   *regmap;
>> +     struct clk                      *clkin;
>> +     struct clk                      *core_clk;
>> +     struct clk                      *sana_clk;
>> +     struct clk                      *adc_sel_clk;
>> +     struct clk                      *adc_clk;
>> +     struct clk_gate                 clk_gate;
>> +     struct clk                      *adc_div_clk;
>> +     struct clk_divider              clk_div;
>> +     struct regulator                *vref;
>> +     struct completion               completion;
> This struct completion isn't used currently. Most likely it was meant
> in peparation of using interrupt mode.
indeed

>> +     u8                              resolution;
>> +};
>> +
>> +static const struct regmap_config meson_saradc_regmap_config = {
>> +     .reg_bits = 8,
>> +     .val_bits = 32,
>> +     .reg_stride = 4,
>> +     .max_register = SAR_ADC_REG13,
>> +};
>> +
>> +static unsigned int meson_saradc_get_fifo_count(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
>> +
>> +     return FIELD_GET(SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
>> +}
>> +
>> +static int meson_saradc_wait_busy_clear(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int regval, timeout = 10000;
>> +
>> +     do {
>> +             udelay(1);
>> +             regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
>> +     } while (FIELD_GET(SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
>> +
>> +     if (timeout < 0)
>> +             return -ETIMEDOUT;
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_read_raw_sample(struct iio_dev *indio_dev,
>> +                                     const struct iio_chan_spec *chan,
>> +                                     int *val)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
>> +
>> +     ret = meson_saradc_wait_busy_clear(indio_dev);
>> +     if (ret)
>> +             return ret;
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> The resulting regval value isn't used, therefore this statement doesn't seem
> to be needed.
I can probably replace this with "0", good catch!

> In the vendor driver there is such a dummy statement before reading the busy
> flags in REG0 after starting sampling. Reason seems to be a potential race
> when we try to read the busy flags before the sampling engine has set them.
> This isn't needed in meson_saradc_wait_busy_clear here as an udelay(1) is
> done first always.
do you think it's worth adding a comment here that a do ... while loop
is there on purpose?

>> +
>> +     while (meson_saradc_get_fifo_count(indio_dev) > 0 &&
> IMHO this loop isn't needed. When we come here the FIFO contains exactly
> one element. This is true also in averaging mode as the averaging engine
> writes only the resulting mean value to the FIFO.
>
> And we can't have multiple samples active in parallel due to the locking
> done in meson_saradc_get_sample.
>
> By the way: I use an IRQ here to wake up when the FIFO contains one
> element. But as you wrote: It's not clear whether this works on all
> Meson systems.
maybe I should switch to IRQ mode as even the old Meson6 vendor kernel
sources indicate that the SAR ADC has IRQ support?

>> +            count < SAR_ADC_MAX_FIFO_SIZE) {
>> +             regmap_read(priv->regmap, SAR_ADC_FIFO_RD, &regval);
>> +
>> +             fifo_chan = FIELD_GET(SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
>> +             if (fifo_chan == chan->channel) {
>> +                     fifo_val = FIELD_GET(SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
>> +                                          regval) & SAR_ADC_VALUE_MASK(priv);
>> +                     sum += fifo_val;
>> +                     count++;
>> +             }
>> +     }
>> +
>> +     if (!count)
>> +             return -ENOENT;
>> +
>> +     *val = sum / count;
>> +
>> +     return 0;
>> +}
>> +
>> +static void meson_saradc_set_averaging(struct iio_dev *indio_dev,
>> +                                    const struct iio_chan_spec *chan,
>> +                                    enum meson_saradc_avg_mode mode,
>> +                                    enum meson_saradc_num_samples samples)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 val;
>> +
>> +     val = samples << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
>> +                        SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(chan->channel),
>> +                        val);
>> +
>> +     val = mode << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
>> +                        SAR_ADC_AVG_CNTL_AVG_MODE_MASK(chan->channel), val);
>> +}
>> +
>> +static void meson_saradc_enable_channel(struct iio_dev *indio_dev,
>> +                                     const struct iio_chan_spec *chan)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     /* the SAR ADC engine allows sampling multiple channels at the same
>> +      * time. to keep it simple we're only working with one *internal*
>> +      * channel, which starts counting at index 0 (which means: count = 1).
>> +      */
>> +     regval = FIELD_PREP(SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
>> +                        SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
>> +
>> +     /* map channel index 0 to the channel which we want to read */
>> +     regval = FIELD_PREP(SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
>> +                        SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), regval);
>> +
>> +     regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
>> +                         chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
>> +                        SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
>> +                        regval);
>> +
>> +     regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
>> +                         chan->channel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
>> +                        SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
>> +                        regval);
>> +
>> +     if (chan->channel == 6)
>> +             regmap_update_bits(priv->regmap, SAR_ADC_DELTA_10,
>> +                                SAR_ADC_DELTA_10_TEMP_SEL, 0);
>> +}
>> +
>> +static void meson_saradc_set_channel7_mux(struct iio_dev *indio_dev,
>> +                                       enum meson_saradc_chan7_mux_sel sel)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     u32 regval;
>> +
>> +     regval = FIELD_PREP(SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
>> +
>> +     usleep_range(10, 20);
>> +}
>> +
>> +static void meson_saradc_start_sample_engine(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLING_START,
>> +                        SAR_ADC_REG0_SAMPLING_START);
>> +}
>> +
>> +static void meson_saradc_stop_sample_engine(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLING_STOP,
>> +                        SAR_ADC_REG0_SAMPLING_STOP);
>> +
>> +     /* wait until all modules are stopped */
>> +     meson_saradc_wait_busy_clear(indio_dev);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                        SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
>> +}
>> +
>> +static void meson_saradc_lock(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int val;
>> +
>> +     mutex_lock(&indio_dev->mlock);
>> +
>> +     /* prevent BL30 from using the SAR ADC while we are using it */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY);
>> +
>> +     /* wait until BL30 releases it's lock (so we can use the SAR ADC) */
>> +     do {
>> +             udelay(1);
>> +             regmap_read(priv->regmap, SAR_ADC_DELAY, &val);
>> +     } while (val & SAR_ADC_DELAY_BL30_BUSY);
>> +}
>> +
>> +static void meson_saradc_unlock(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     /* allow BL30 to use the SAR ADC again */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_KERNEL_BUSY, 0);
>> +
>> +     mutex_unlock(&indio_dev->mlock);
>> +}
>> +
>> +static int meson_saradc_get_sample(struct iio_dev *indio_dev,
>> +                                const struct iio_chan_spec *chan,
>> +                                enum meson_saradc_avg_mode avg_mode,
>> +                                enum meson_saradc_num_samples avg_samples,
>> +                                int *val)
>> +{
>> +     int ret, tmp;
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     /* clear old values from the FIFO buffer, ignoring errors */
>> +     meson_saradc_read_raw_sample(indio_dev, chan, &tmp);
>> +
>> +     meson_saradc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
>> +
>> +     meson_saradc_enable_channel(indio_dev, chan);
>> +
>> +     meson_saradc_start_sample_engine(indio_dev);
>> +     ret = meson_saradc_read_raw_sample(indio_dev, chan, val);
>> +     meson_saradc_stop_sample_engine(indio_dev);
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +
>> +     if (ret) {
>> +             dev_warn(&indio_dev->dev,
> Using the struct device in indio_dev results in IMHO ugly messages like
> iio iio:device0: already initialized by BL30
>
> We should use the parent instead, this is more readable:
> meson-saradc c1108680.adc: already initialized by BL30
>
> For this we need to move the assignment to indio_dev->dev.parent
> in probe, else messages may be written when parent isn't set yet.
indeed, I'll change this - thanks for the hint!

>> +                      "failed to read sample for channel %d: %d\n",
>> +                      chan->channel, ret);
>> +             return ret;
>> +     }
>> +
>> +     return IIO_VAL_INT;
>> +}
>> +
>> +static int meson_saradc_iio_info_read_raw(struct iio_dev *indio_dev,
>> +                                       const struct iio_chan_spec *chan,
>> +                                       int *val, int *val2, long mask)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     switch (mask) {
>> +     case IIO_CHAN_INFO_RAW:
>> +             return meson_saradc_get_sample(indio_dev, chan, NO_AVERAGING,
>> +                                            ONE_SAMPLE, val);
>> +             break;
>> +
>> +     case IIO_CHAN_INFO_AVERAGE_RAW:
>> +             return meson_saradc_get_sample(indio_dev, chan, MEAN_AVERAGING,
>> +                                            EIGHT_SAMPLES, val);
>> +             break;
>> +
>> +     case IIO_CHAN_INFO_SCALE:
>> +             ret = regulator_get_voltage(priv->vref);
>> +             if (ret < 0) {
>> +                     dev_err(&indio_dev->dev,
>> +                             "failed to get vref voltage: %d\n", ret);
>> +                     return ret;
>> +             }
>> +
>> +             *val = ret / 1000;
>> +             *val2 = priv->resolution;
>> +             return IIO_VAL_FRACTIONAL_LOG2;
>> +
>> +     default:
>> +             return -EINVAL;
>> +     }
>> +}
>> +
>> +static int meson_saradc_clk_init(struct iio_dev *indio_dev, void __iomem *base)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     struct clk_init_data init;
>> +     char clk_name[32];
>> +     const char *clk_parents[1];
>> +
>> +     snprintf(clk_name, sizeof(clk_name), "%s#adc_div",
>> +              of_node_full_name(indio_dev->dev.of_node));
>> +     init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
> Consider replacing snprintf + devm_kstrdup with devm_kasprintf
I must have missed that, thanks for another good catch!

>> +     init.flags = 0;
>> +     init.ops = &clk_divider_ops;
>> +     clk_parents[0] = __clk_get_name(priv->clkin);
>> +     init.parent_names = clk_parents;
>> +     init.num_parents = 1;
>> +
>> +     priv->clk_div.reg = base + SAR_ADC_REG3;
>> +     priv->clk_div.shift = SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
>> +     priv->clk_div.width = SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
>> +     priv->clk_div.hw.init = &init;
>> +     priv->clk_div.flags = 0;
>> +
>> +     priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
>> +                                           &priv->clk_div.hw);
>> +     if (WARN_ON(IS_ERR(priv->adc_div_clk)))
>> +             return PTR_ERR(priv->adc_div_clk);
>> +
>> +     snprintf(clk_name, sizeof(clk_name), "%s#adc_en",
>> +              of_node_full_name(indio_dev->dev.of_node));
>> +     init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
>> +     init.flags = CLK_SET_RATE_PARENT;
>> +     init.ops = &clk_gate_ops;
>> +     clk_parents[0] = __clk_get_name(priv->adc_div_clk);
>> +     init.parent_names = clk_parents;
>> +     init.num_parents = 1;
>> +
>> +     priv->clk_gate.reg = base + SAR_ADC_REG3;
>> +     priv->clk_gate.bit_idx = fls(SAR_ADC_REG3_CLK_EN);
>> +     priv->clk_gate.hw.init = &init;
>> +
>> +     priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
>> +     if (WARN_ON(IS_ERR(priv->adc_clk)))
>> +             return PTR_ERR(priv->adc_clk);
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_init(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int regval, ret;
>> +
>> +     /* make sure we start at CH7 input */
>> +     meson_saradc_set_channel7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
>> +
>> +     regmap_read(priv->regmap, SAR_ADC_REG3, &regval);
>> +     if (regval & SAR_ADC_REG3_BL30_INITIALIZED) {
>> +             dev_info(&indio_dev->dev, "already initialized by BL30\n");
>> +             return 0;
>> +     }
>> +
>> +     dev_info(&indio_dev->dev, "initializing SAR ADC\n");
>> +
>> +     meson_saradc_stop_sample_engine(indio_dev);
>> +
>> +     /* update the channel 6 MUX to select the temperature sensor */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG0,
>> +                     SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
>> +                     SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
>> +
>> +     /* disable all channels by default */
>> +     regmap_write(priv->regmap, SAR_ADC_CHAN_LIST, 0x0);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3,
>> +                        SAR_ADC_REG3_CNTL_USE_SC_DLY,
>> +                        SAR_ADC_REG3_CNTL_USE_SC_DLY);
>> +
>> +     /* delay between two samples = (10+1) * 1uS */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 10));
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 0));
>> +
>> +     /* delay between two samples = (10+1) * 1uS */
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 10));
>> +     regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
>> +                        SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
>> +                        FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1));
>> +
>> +     ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev,
>> +                     "failed to set adc parent to clkin\n");
>> +             return ret;
>> +     }
>> +
>> +     ret = clk_set_rate(priv->adc_clk, 1200000);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to set adc clock rate\n");
>> +             return ret;
>> +     }
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_hw_enable(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +     int ret;
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     ret = regulator_enable(priv->vref);
>> +     if (ret < 0) {
>> +             dev_err(&indio_dev->dev, "failed to enable vref regulator\n");
>> +             goto err_vref;
>> +     }
>> +
>> +     ret = clk_prepare_enable(priv->core_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable core clk\n");
>> +             goto err_core_clk;
>> +     }
>> +
>> +     ret = clk_prepare_enable(priv->sana_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable sana clk\n");
>> +             goto err_sana_clk;
>> +     }
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG11,
>> +                        SAR_ADC_REG11_BANDGAP_EN, SAR_ADC_REG11_BANDGAP_EN);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN,
>> +                        SAR_ADC_REG3_ADC_EN);
>> +
>> +     udelay(5);
>> +
>> +     ret = clk_prepare_enable(priv->adc_clk);
>> +     if (ret) {
>> +             dev_err(&indio_dev->dev, "failed to enable adc_en clk\n");
>> +             goto err_adc_clk;
>> +     }
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +
>> +     return 0;
>> +
>> +err_adc_clk:
>> +     clk_disable_unprepare(priv->sana_clk);
>> +err_sana_clk:
>> +     clk_disable_unprepare(priv->core_clk);
>> +err_core_clk:
>> +     regulator_disable(priv->vref);
>> +err_vref:
>> +     meson_saradc_unlock(indio_dev);
>> +     return ret;
>> +}
>> +
>> +static void meson_saradc_hw_disable(struct iio_dev *indio_dev)
>> +{
>> +     struct meson_saradc_priv *priv = iio_priv(indio_dev);
>> +
>> +     meson_saradc_lock(indio_dev);
>> +
>> +     clk_disable_unprepare(priv->adc_clk);
>> +
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
>> +     regmap_update_bits(priv->regmap, SAR_ADC_REG11,
>> +                        SAR_ADC_REG11_BANDGAP_EN, 0);
>> +
>> +     clk_disable_unprepare(priv->sana_clk);
>> +     clk_disable_unprepare(priv->core_clk);
>> +
>> +     regulator_disable(priv->vref);
>> +
>> +     meson_saradc_unlock(indio_dev);
>> +}
>> +
>> +static const struct iio_info meson_saradc_iio_info = {
>> +     .read_raw = meson_saradc_iio_info_read_raw,
>> +     .driver_module = THIS_MODULE,
>> +};
>> +
>> +static const struct of_device_id meson_saradc_of_match[] = {
>> +     {
>> +             .compatible = "amlogic,meson-gxbb-saradc",
>> +             .data = (void *)10,
>> +     }, {
>> +             .compatible = "amlogic,meson-gxl-saradc",
>> +             .data = (void *)12,
>> +     },
>> +     {},
>> +};
>> +MODULE_DEVICE_TABLE(of, meson_saradc_of_match);
>> +
>> +static int meson_saradc_probe(struct platform_device *pdev)
>> +{
>> +     struct meson_saradc_priv *priv;
>> +     struct iio_dev *indio_dev;
>> +     struct resource *res;
>> +     void __iomem *base;
>> +     const struct of_device_id *match;
>> +     int ret;
>> +
>> +     indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
>> +     if (!indio_dev) {
>> +             dev_err(&pdev->dev, "failed allocating iio device\n");
>> +             return -ENOMEM;
>> +     }
>> +
>> +     priv = iio_priv(indio_dev);
>> +
>> +     match = of_match_device(meson_saradc_of_match, &pdev->dev);
>> +     priv->resolution = (unsigned long)match->data;
>> +
>> +     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +     base = devm_ioremap_resource(&pdev->dev, res);
>> +     if (IS_ERR(base))
>> +             return PTR_ERR(base);
>> +
>> +     priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
>> +                                          &meson_saradc_regmap_config);
>> +     if (IS_ERR(priv->regmap))
>> +             return PTR_ERR(priv->regmap);
>> +
>> +     init_completion(&priv->completion);
>> +
>> +     priv->clkin = devm_clk_get(&pdev->dev, "clkin");
>> +     if (IS_ERR(priv->clkin)) {
>> +             dev_err(&pdev->dev, "failed to get clkin\n");
>> +             return PTR_ERR(priv->clkin);
>> +     }
>> +
>> +     priv->core_clk = devm_clk_get(&pdev->dev, "core");
>> +     if (IS_ERR(priv->core_clk)) {
>> +             dev_err(&pdev->dev, "failed to get core clk\n");
>> +             return PTR_ERR(priv->core_clk);
>> +     }
>> +
>> +     priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
>> +     if (IS_ERR(priv->sana_clk)) {
>> +             if (PTR_ERR(priv->sana_clk) == -ENOENT) {
>> +                     priv->sana_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get sana clk\n");
>> +                     return PTR_ERR(priv->sana_clk);
>> +             }
>> +     }
>> +
>> +     priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
>> +     if (IS_ERR(priv->adc_clk)) {
>> +             if (PTR_ERR(priv->adc_clk) == -ENOENT) {
>> +                     priv->adc_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get adc clk\n");
>> +                     return PTR_ERR(priv->adc_clk);
>> +             }
>> +     }
>> +
>> +     priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
>> +     if (IS_ERR(priv->adc_sel_clk)) {
>> +             if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
>> +                     priv->adc_sel_clk = NULL;
>> +             } else {
>> +                     dev_err(&pdev->dev, "failed to get adc_sel clk\n");
>> +                     return PTR_ERR(priv->adc_sel_clk);
>> +             }
>> +     }
>> +
>> +     /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
>> +     if (!priv->adc_clk) {
>> +             ret = meson_saradc_clk_init(indio_dev, base);
>> +             if (ret)
>> +                     return ret;
>> +     }
>> +
>> +     priv->vref = devm_regulator_get(&pdev->dev, "vref");
>> +     if (IS_ERR(priv->vref)) {
>> +             dev_err(&pdev->dev, "failed to get vref regulator\n");
>> +             return PTR_ERR(priv->vref);
>> +     }
>> +
>> +     ret = meson_saradc_init(indio_dev);
>> +     if (ret)
>> +             goto err;
>> +
>> +     ret = meson_saradc_hw_enable(indio_dev);
>> +     if (ret)
>> +             goto err;
>> +
>> +     platform_set_drvdata(pdev, indio_dev);
>> +
>> +     indio_dev->name = dev_name(&pdev->dev);
>> +     indio_dev->dev.parent = &pdev->dev;
>> +     indio_dev->dev.of_node = pdev->dev.of_node;
>> +     indio_dev->modes = INDIO_DIRECT_MODE;
>> +     indio_dev->info = &meson_saradc_iio_info;
>> +
>> +     indio_dev->channels = meson_saradc_iio_channels;
>> +     indio_dev->num_channels = SAR_ADC_NUM_CHANNELS;
>> +
>> +     ret = iio_device_register(indio_dev);
>> +     if (ret)
>> +             goto err_hw;
>> +
>> +     return 0;
>> +
>> +err_hw:
>> +     meson_saradc_hw_disable(indio_dev);
>> +err:
>> +     return ret;
>> +}
>> +
>> +static int meson_saradc_remove(struct platform_device *pdev)
>> +{
>> +     struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +     meson_saradc_hw_disable(indio_dev);
>> +     iio_device_unregister(indio_dev);
>> +
>> +     return 0;
>> +}
>> +
>> +#ifdef CONFIG_PM_SLEEP
>> +static int meson_saradc_suspend(struct device *dev)
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +
>> +     meson_saradc_hw_disable(indio_dev);
>> +
>> +     return 0;
>> +}
>> +
>> +static int meson_saradc_resume(struct device *dev)
>> +{
>> +     struct iio_dev *indio_dev = dev_get_drvdata(dev);
>> +
>> +     return meson_saradc_hw_enable(indio_dev);
>> +}
>> +#endif /* CONFIG_PM_SLEEP */
>> +
>> +static SIMPLE_DEV_PM_OPS(meson_saradc_pm_ops,
>> +                      meson_saradc_suspend, meson_saradc_resume);
>> +
>> +static struct platform_driver meson_saradc_driver = {
>> +     .probe          = meson_saradc_probe,
>> +     .remove         = meson_saradc_remove,
>> +     .driver         = {
>> +             .name   = "meson-saradc",
>> +             .of_match_table = meson_saradc_of_match,
>> +             .pm = &meson_saradc_pm_ops,
>> +     },
>> +};
>> +
>> +module_platform_driver(meson_saradc_driver);
>> +
>> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>");
>> +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
>> +MODULE_LICENSE("GPL v2");
>>
>
>

^ permalink raw reply

* [PATCH 4/4] ARM64: dts: meson: meson-gx: add the SAR ADC
From: Martin Blumenstingl @ 2017-01-13 19:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <2c7996a6-9c55-4cee-75a1-01be8732c42a@gmail.com>

Hi Heiner,

On Fri, Jan 13, 2017 at 8:32 PM, Heiner Kallweit <hkallweit1@gmail.com> wrote:
> Sorry, I'm not subscribed to the two mailing lists, therefore my reply
> is outside the thread.
>
> I'm currently experimenting with an own rudimentary driver for SAR ADC
> on a Odroid C2 (S905GXBB). So I have some remarks based on my experience.
I hope that we haven't been duplicating too much work!

> Rgds, Heiner
>
>> Add the SAR ADC to meson-gxbb.dtsi and meson-gxl.dtsi. GXBB provides a
>> 10-bit ADC while GXL (and GXM, which uses the same ADC as GXL) provides
>> a 12-bit ADC.
>> Some boards use resistor ladder buttons connected through one of the ADC
>> channels. On newer devices (GXL and GXM) some boards use pull-ups/downs
>> to change the resistance (and thus the ADC value) on of the ADC channels
>> to indicate the board revision.
>>
>> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
>> ---
>>  arch/arm64/boot/dts/amlogic/meson-gx.dtsi   |  8 ++++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxbb.dtsi | 10 ++++++++++
>>  arch/arm64/boot/dts/amlogic/meson-gxl.dtsi  | 10 ++++++++++
>>  3 files changed, 28 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
>> index cddad8c795ec..ed3bf29eb76a 100644
>> --- a/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
>> +++ b/arch/arm64/boot/dts/amlogic/meson-gx.dtsi
>> @@ -237,6 +237,14 @@
>>                               status = "disabled";
>>                       };
>>
>> +                     saradc: adc at 8680 {
>> +                             compatible = "amlogic,meson-saradc";
>> +                             #io-channel-cells = <1>;
>> +                             status = "disabled";
>> +                             reg = <0x0 0x8680 0x0 0x34>;
>> +                             interrupts = <GIC_SPI 9 IRQ_TYPE_EDGE_RISING>;
> IRQ 9 dosn't work for me, where does this number come from?
> With IRQ 73 interrupt mode is working fine here.
> Of course I can't speak for all other Meson variants.
I think I took the IRQ from the vendor's mesongxbb.dtsi, depending on
whether I'll add IRQ support or not I'll remove or fix this. Thanks
for spotting this!


Regards,
Martin

^ permalink raw reply

* [PATCH 09/10] ARM: dts: da850: add the SATA node
From: David Lechner @ 2017-01-13 19:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484311084-31547-10-git-send-email-bgolaszewski@baylibre.com>

On 01/13/2017 06:38 AM, Bartosz Golaszewski wrote:
> Add the SATA node to the da850 device tree.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  arch/arm/boot/dts/da850.dtsi | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
> index 1f6a47d..f5086b1 100644
> --- a/arch/arm/boot/dts/da850.dtsi
> +++ b/arch/arm/boot/dts/da850.dtsi
> @@ -427,6 +427,12 @@
>  			phy-names = "usb-phy";
>  			status = "disabled";
>  		};
> +		sata: ahci at 0x218000 {

0x needs to be omitted.

	sata: ahci at 218000 {

> +			compatible = "ti,da850-ahci";
> +			reg = <0x218000 0x2000>, <0x22c018 0x4>;
> +			interrupts = <67>;
> +			status = "disabled";
> +		};
>  		mdio: mdio at 224000 {
>  			compatible = "ti,davinci_mdio";
>  			#address-cells = <1>;
>

^ permalink raw reply

* [PATCH 3/4] iio: adc: add a driver for the SAR ADC found in Amlogic Meson SoCs
From: Heiner Kallweit @ 2017-01-13 19:35 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <02fbde00-f325-56a6-7367-7101f7d4ee21@gmail.com>

> This adds support for the SAR (Successive Approximation Register) ADC
> on the Amlogic Meson SoCs.
> 
> The code is based on the public S805 (Meson8b) and S905 (GXBB)
> datasheets, as well as by reading (various versions of) the vendor
> driver and by inspecting the registers on the vendor kernels of my
> testing-hardware.
> 
> Currently the GXBB, GXL and GXM SoCs are supported. GXBB hardware has
> 10-bit ADC resolution, while GXL and GXM have 12-bit ADC resolution.
> The code was written to support older SoCs (Meson8 and Meson8b) as well,
> but due to lack of actual testing-hardware no of_device_id was added for
> these.
> 
> Two "features" from the vendor driver are currently missing:
> - the vendor driver uses channel #7 for calibration (this improves the
>   accuracy of the results - in my tests the results were less than 3%
>   off without calibration compared to the vendor driver). Adding support
>   for this should be easy, but is not required for most applications.
> - channel #6 is connected to the SoCs internal temperature sensor.
>   Adding support for this is probably not so easy since (based on the
>   u-boot sources) most SoC versions are using different registers and
>   algorithms for the conversion from "ADC value" to temperature.
> 
> Supported by the hardware but currently not supported by the driver:
> - reading multiple channels at the same time (the hardware has a FIFO
>   buffer which stores multiple results)
> - continuous sampling (this would require a way to enable this
>   individually because otherwise the ADC would be drawing power
>   constantly)
> - interrupt support (similar to the vendor driver this new driver is
>   polling the results. It is unclear if the IRQ-mode is supported on
>   older (Meson6 or Meson8) hardware as well or if there are any errata)
> 
> Signed-off-by: Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
> ---
>  drivers/iio/adc/Kconfig        |  12 +
>  drivers/iio/adc/Makefile       |   1 +
>  drivers/iio/adc/meson_saradc.c | 860 +++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 873 insertions(+)
>  create mode 100644 drivers/iio/adc/meson_saradc.c
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 9c8b558ba19e..86059b9b91bf 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -371,6 +371,18 @@ config MEN_Z188_ADC
>  	  This driver can also be built as a module. If so, the module will be
>  	  called men_z188_adc.
>  
> +config MESON_SARADC
> +	tristate "Amlogic Meson SAR ADC driver"
> +	default ARCH_MESON
> +	depends on OF && COMMON_CLK && (ARCH_MESON || COMPILE_TEST)
> +	select REGMAP_MMIO
> +	help
> +	  Say yes here to build support for the SAR ADC found in Amlogic Meson
> +	  SoCs.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called meson_saradc.
> +
>  config MXS_LRADC
>          tristate "Freescale i.MX23/i.MX28 LRADC"
>          depends on (ARCH_MXS || COMPILE_TEST) && HAS_IOMEM
> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
> index d36c4be8d1fc..de05b9e75f8f 100644
> --- a/drivers/iio/adc/Makefile
> +++ b/drivers/iio/adc/Makefile
> @@ -36,6 +36,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o
>  obj-$(CONFIG_MCP3422) += mcp3422.o
>  obj-$(CONFIG_MEDIATEK_MT6577_AUXADC) += mt6577_auxadc.o
>  obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
> +obj-$(CONFIG_MESON_SARADC) += meson_saradc.o
>  obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o
>  obj-$(CONFIG_NAU7802) += nau7802.o
>  obj-$(CONFIG_PALMAS_GPADC) += palmas_gpadc.o
> diff --git a/drivers/iio/adc/meson_saradc.c b/drivers/iio/adc/meson_saradc.c
> new file mode 100644
> index 000000000000..06e8ac620385
> --- /dev/null
> +++ b/drivers/iio/adc/meson_saradc.c
> @@ -0,0 +1,860 @@
> +/*
> + * Amlogic Meson Successive Approximation Register (SAR) A/D Converter
> + *
> + * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>
> + *
> + * 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.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program. If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/clk-provider.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/iio/iio.h>
> +#include <linux/of.h>
> +#include <linux/of_device.h>
> +#include <linux/clk.h>
> +#include <linux/completion.h>
> +#include <linux/delay.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/regulator/consumer.h>
> +
> +#define SAR_ADC_REG0						0x00
> +	#define SAR_ADC_REG0_PANEL_DETECT			BIT(31)
> +	#define SAR_ADC_REG0_BUSY_MASK				GENMASK(30, 28)
> +	#define SAR_ADC_REG0_DELTA_BUSY				BIT(30)
> +	#define SAR_ADC_REG0_AVG_BUSY				BIT(29)
> +	#define SAR_ADC_REG0_SAMPLE_BUSY			BIT(28)
> +	#define SAR_ADC_REG0_FIFO_FULL				BIT(27)
> +	#define SAR_ADC_REG0_FIFO_EMPTY				BIT(26)
> +	#define SAR_ADC_REG0_FIFO_COUNT_MASK			GENMASK(25, 21)
> +	#define SAR_ADC_REG0_ADC_BIAS_CTRL_MASK			GENMASK(20, 19)
> +	#define SAR_ADC_REG0_CURR_CHAN_ID_MASK			GENMASK(18, 16)
> +	#define SAR_ADC_REG0_ADC_TEMP_SEN_SEL			BIT(15)
> +	#define SAR_ADC_REG0_SAMPLING_STOP			BIT(14)
> +	#define SAR_ADC_REG0_CHAN_DELTA_EN_MASK			GENMASK(13, 12)
> +	#define SAR_ADC_REG0_DETECT_IRQ_POL			BIT(10)
> +	#define SAR_ADC_REG0_DETECT_IRQ_EN			BIT(9)
> +	#define SAR_ADC_REG0_FIFO_CNT_IRQ_MASK			GENMASK(8, 4)
> +	#define SAR_ADC_REG0_FIFO_IRQ_EN			BIT(3)
> +	#define SAR_ADC_REG0_SAMPLING_START			BIT(2)
> +	#define SAR_ADC_REG0_CONTINUOUS_EN			BIT(1)
> +	#define SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE		BIT(0)
> +
> +#define SAR_ADC_CHAN_LIST					0x04
> +	#define SAR_ADC_CHAN_LIST_MAX_INDEX_MASK		GENMASK(26, 24)
> +	#define SAR_ADC_CHAN_CHAN_ENTRY_MASK(_chan)		\
> +					(GENMASK(2, 0) << (_chan * 3))
> +
> +#define SAR_ADC_AVG_CNTL					0x08
> +	#define SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan)		\
> +					(16 + (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan)		\
> +					(GENMASK(17, 16) << (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan)	\
> +					(0 + (_chan * 2))
> +	#define SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan)	\
> +					(GENMASK(1, 0) << (_chan * 2))
> +
> +#define SAR_ADC_REG3						0x0c
> +	#define SAR_ADC_REG3_CNTL_USE_SC_DLY			BIT(31)
> +	#define SAR_ADC_REG3_CLK_EN				BIT(30)
> +	#define SAR_ADC_REG3_BL30_INITIALIZED			BIT(28)
> +	#define SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN		BIT(27)
> +	#define SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE		BIT(26)
> +	#define SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK		GENMASK(25, 23)
> +	#define SAR_ADC_REG3_DETECT_EN				BIT(22)
> +	#define SAR_ADC_REG3_ADC_EN				BIT(21)
> +	#define SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK		GENMASK(20, 18)
> +	#define SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK	GENMASK(17, 16)
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_SHIFT			10
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_WIDTH			5
> +	#define SAR_ADC_REG3_ADC_CLK_DIV_MASK			GENMASK(15, 10)
> +	#define SAR_ADC_REG3_BLOCK_DLY_SEL_MASK			GENMASK(9, 8)
> +	#define SAR_ADC_REG3_BLOCK_DLY_MASK			GENMASK(7, 0)
> +
> +#define SAR_ADC_DELAY						0x10
> +	#define SAR_ADC_DELAY_INPUT_DLY_SEL_MASK		GENMASK(25, 24)
> +	#define SAR_ADC_DELAY_BL30_BUSY				BIT(15)
> +	#define SAR_ADC_DELAY_KERNEL_BUSY			BIT(14)
> +	#define SAR_ADC_DELAY_INPUT_DLY_CNT_MASK		GENMASK(23, 16)
> +	#define SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK		GENMASK(9, 8)
> +	#define SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK		GENMASK(7, 0)
> +
> +#define SAR_ADC_LAST_RD						0x14
> +	#define SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK		GENMASK(23, 16)
> +	#define SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK		GENMASK(9, 0)
> +
> +#define SAR_ADC_FIFO_RD						0x18
> +	#define SAR_ADC_FIFO_RD_CHAN_ID_MASK			GENMASK(14, 12)
> +	#define SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK		GENMASK(11, 0)
> +
> +#define SAR_ADC_AUX_SW						0x1c
> +	#define SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan)		\
> +					(GENMASK(10, 8) << ((_chan - 2) * 2))
> +	#define SAR_ADC_AUX_SW_VREF_P_MUX			BIT(6)
> +	#define SAR_ADC_AUX_SW_VREF_N_MUX			BIT(5)
> +	#define SAR_ADC_AUX_SW_MODE_SEL				BIT(4)
> +	#define SAR_ADC_AUX_SW_YP_DRIVE_SW			BIT(3)
> +	#define SAR_ADC_AUX_SW_XP_DRIVE_SW			BIT(2)
> +	#define SAR_ADC_AUX_SW_YM_DRIVE_SW			BIT(1)
> +	#define SAR_ADC_AUX_SW_XM_DRIVE_SW			BIT(0)
> +
> +#define SAR_ADC_CHAN_10_SW					0x20
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK		GENMASK(25, 23)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX		BIT(22)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX		BIT(21)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL		BIT(20)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW		BIT(19)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW		BIT(18)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW		BIT(17)
> +	#define SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW		BIT(16)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK		GENMASK(9, 7)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX		BIT(6)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX		BIT(5)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL		BIT(4)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW		BIT(3)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW		BIT(2)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW		BIT(1)
> +	#define SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW		BIT(0)
> +
> +#define SAR_ADC_DETECT_IDLE_SW					0x24
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN		BIT(26)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK	GENMASK(25, 23)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_P_MUX	BIT(22)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_VREF_N_MUX	BIT(21)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL		BIT(20)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YP_DRIVE_SW	BIT(19)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XP_DRIVE_SW	BIT(18)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_YM_DRIVE_SW	BIT(17)
> +	#define SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_XM_DRIVE_SW	BIT(16)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK	GENMASK(9, 7)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_P_MUX	BIT(6)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_VREF_N_MUX	BIT(5)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL		BIT(4)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YP_DRIVE_SW	BIT(3)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XP_DRIVE_SW	BIT(2)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_YM_DRIVE_SW	BIT(1)
> +	#define SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_XM_DRIVE_SW	BIT(0)
> +
> +#define SAR_ADC_DELTA_10					0x28
> +	#define SAR_ADC_DELTA_10_TEMP_SEL			BIT(27)
> +	#define SAR_ADC_DELTA_10_TS_REVE1			BIT(26)
> +	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_SHIFT	16
> +	#define SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK		GENMASK(25, 16)
> +	#define SAR_ADC_DELTA_10_TS_REVE0			BIT(15)
> +	#define SAR_ADC_DELTA_10_TS_C_SHIFT			11
> +	#define SAR_ADC_DELTA_10_TS_C_MASK			GENMASK(14, 11)
> +	#define SAR_ADC_DELTA_10_TS_VBG_EN			BIT(10)
> +	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_SHIFT	0
> +	#define SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK		GENMASK(9, 0)
> +
> +/* NOTE: registers from here are undocumented (the vendor Linux kernel driver
> + * and u-boot source served as reference). These only seem to be relevant on
> + * GXBB and newer.
> + */
> +#define SAR_ADC_REG11						0x2c
> +	#define SAR_ADC_REG11_BANDGAP_EN			BIT(13)
> +
> +#define SAR_ADC_REG13						0x34
> +	#define SAR_ADC_REG13_12BIT_CALIBRATION_MASK		GENMASK(13, 8)
> +
> +#define SAR_ADC_MAX_FIFO_SIZE		32
> +#define SAR_ADC_NUM_CHANNELS		ARRAY_SIZE(meson_saradc_iio_channels)
> +#define SAR_ADC_VALUE_MASK(_priv)	(BIT(_priv->resolution) - 1)
> +
> +#define MESON_SAR_ADC_CHAN(_chan, _type) {				\
> +	.type = _type,							\
> +	.indexed = true,						\
> +	.channel = _chan,						\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |			\
> +				BIT(IIO_CHAN_INFO_AVERAGE_RAW),		\
> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),		\
> +	.datasheet_name = "SAR_ADC_CH"#_chan,				\
> +}
> +
> +/* TODO: the hardware supports IIO_TEMP for channel 6 as well which is
> + * currently not supported by this driver.
> + */
> +static const struct iio_chan_spec meson_saradc_iio_channels[] = {
> +	MESON_SAR_ADC_CHAN(0, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(1, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(2, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(3, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(4, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(5, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(6, IIO_VOLTAGE),
> +	MESON_SAR_ADC_CHAN(7, IIO_VOLTAGE),
> +	IIO_CHAN_SOFT_TIMESTAMP(8),
> +};
> +
> +enum meson_saradc_avg_mode {
> +	NO_AVERAGING = 0x0,
> +	MEAN_AVERAGING = 0x1,
> +	MEDIAN_AVERAGING = 0x2,
> +};
> +
> +enum meson_saradc_num_samples {
> +	ONE_SAMPLE = 0x0,
> +	TWO_SAMPLES = 0x1,
> +	FOUR_SAMPLES = 0x2,
> +	EIGHT_SAMPLES = 0x3,
> +};
> +
> +enum meson_saradc_chan7_mux_sel {
> +	CHAN7_MUX_VSS = 0x0,
> +	CHAN7_MUX_VDD_DIV4 = 0x1,
> +	CHAN7_MUX_VDD_DIV2 = 0x2,
> +	CHAN7_MUX_VDD_MUL3_DIV4 = 0x3,
> +	CHAN7_MUX_VDD = 0x4,
> +	CHAN7_MUX_CH7_INPUT = 0x7,
> +};
> +
> +struct meson_saradc_priv {
> +	struct regmap			*regmap;
> +	struct clk			*clkin;
> +	struct clk			*core_clk;
> +	struct clk			*sana_clk;
> +	struct clk			*adc_sel_clk;
> +	struct clk			*adc_clk;
> +	struct clk_gate			clk_gate;
> +	struct clk			*adc_div_clk;
> +	struct clk_divider		clk_div;
> +	struct regulator		*vref;
> +	struct completion		completion;
This struct completion isn't used currently. Most likely it was meant
in peparation of using interrupt mode.

> +	u8				resolution;
> +};
> +
> +static const struct regmap_config meson_saradc_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 32,
> +	.reg_stride = 4,
> +	.max_register = SAR_ADC_REG13,
> +};
> +
> +static unsigned int meson_saradc_get_fifo_count(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> +
> +	return FIELD_GET(SAR_ADC_REG0_FIFO_COUNT_MASK, regval);
> +}
> +
> +static int meson_saradc_wait_busy_clear(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int regval, timeout = 10000;
> +
> +	do {
> +		udelay(1);
> +		regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
> +	} while (FIELD_GET(SAR_ADC_REG0_BUSY_MASK, regval) && timeout--);
> +
> +	if (timeout < 0)
> +		return -ETIMEDOUT;
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_read_raw_sample(struct iio_dev *indio_dev,
> +					const struct iio_chan_spec *chan,
> +					int *val)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret, regval, fifo_chan, fifo_val, sum = 0, count = 0;
> +
> +	ret = meson_saradc_wait_busy_clear(indio_dev);
> +	if (ret)
> +		return ret;
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG0, &regval);
The resulting regval value isn't used, therefore this statement doesn't seem
to be needed.
In the vendor driver there is such a dummy statement before reading the busy
flags in REG0 after starting sampling. Reason seems to be a potential race
when we try to read the busy flags before the sampling engine has set them.
This isn't needed in meson_saradc_wait_busy_clear here as an udelay(1) is
done first always.

> +
> +	while (meson_saradc_get_fifo_count(indio_dev) > 0 &&
IMHO this loop isn't needed. When we come here the FIFO contains exactly
one element. This is true also in averaging mode as the averaging engine
writes only the resulting mean value to the FIFO.

And we can't have multiple samples active in parallel due to the locking
done in meson_saradc_get_sample.

By the way: I use an IRQ here to wake up when the FIFO contains one
element. But as you wrote: It's not clear whether this works on all
Meson systems.

> +	       count < SAR_ADC_MAX_FIFO_SIZE) {
> +		regmap_read(priv->regmap, SAR_ADC_FIFO_RD, &regval);
> +
> +		fifo_chan = FIELD_GET(SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval);
> +		if (fifo_chan == chan->channel) {
> +			fifo_val = FIELD_GET(SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK,
> +					     regval) & SAR_ADC_VALUE_MASK(priv);
> +			sum += fifo_val;
> +			count++;
> +		}
> +	}
> +
> +	if (!count)
> +		return -ENOENT;
> +
> +	*val = sum / count;
> +
> +	return 0;
> +}
> +
> +static void meson_saradc_set_averaging(struct iio_dev *indio_dev,
> +				       const struct iio_chan_spec *chan,
> +				       enum meson_saradc_avg_mode mode,
> +				       enum meson_saradc_num_samples samples)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 val;
> +
> +	val = samples << SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
> +			   SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(chan->channel),
> +			   val);
> +
> +	val = mode << SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_AVG_CNTL,
> +			   SAR_ADC_AVG_CNTL_AVG_MODE_MASK(chan->channel), val);
> +}
> +
> +static void meson_saradc_enable_channel(struct iio_dev *indio_dev,
> +					const struct iio_chan_spec *chan)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	/* the SAR ADC engine allows sampling multiple channels at the same
> +	 * time. to keep it simple we're only working with one *internal*
> +	 * channel, which starts counting at index 0 (which means: count = 1).
> +	 */
> +	regval = FIELD_PREP(SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
> +			   SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval);
> +
> +	/* map channel index 0 to the channel which we want to read */
> +	regval = FIELD_PREP(SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_CHAN_LIST,
> +			   SAR_ADC_CHAN_CHAN_ENTRY_MASK(0), regval);
> +
> +	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
> +			    chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
> +			   SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_MUX_MASK,
> +			   regval);
> +
> +	regval = FIELD_PREP(SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
> +			    chan->channel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_DETECT_IDLE_SW,
> +			   SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_MUX_SEL_MASK,
> +			   regval);
> +
> +	if (chan->channel == 6)
> +		regmap_update_bits(priv->regmap, SAR_ADC_DELTA_10,
> +				   SAR_ADC_DELTA_10_TEMP_SEL, 0);
> +}
> +
> +static void meson_saradc_set_channel7_mux(struct iio_dev *indio_dev,
> +					  enum meson_saradc_chan7_mux_sel sel)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	u32 regval;
> +
> +	regval = FIELD_PREP(SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval);
> +
> +	usleep_range(10, 20);
> +}
> +
> +static void meson_saradc_start_sample_engine(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLING_START,
> +			   SAR_ADC_REG0_SAMPLING_START);
> +}
> +
> +static void meson_saradc_stop_sample_engine(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLING_STOP,
> +			   SAR_ADC_REG0_SAMPLING_STOP);
> +
> +	/* wait until all modules are stopped */
> +	meson_saradc_wait_busy_clear(indio_dev);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			   SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0);
> +}
> +
> +static void meson_saradc_lock(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int val;
> +
> +	mutex_lock(&indio_dev->mlock);
> +
> +	/* prevent BL30 from using the SAR ADC while we are using it */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY);
> +
> +	/* wait until BL30 releases it's lock (so we can use the SAR ADC) */
> +	do {
> +		udelay(1);
> +		regmap_read(priv->regmap, SAR_ADC_DELAY, &val);
> +	} while (val & SAR_ADC_DELAY_BL30_BUSY);
> +}
> +
> +static void meson_saradc_unlock(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	/* allow BL30 to use the SAR ADC again */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_KERNEL_BUSY, 0);
> +
> +	mutex_unlock(&indio_dev->mlock);
> +}
> +
> +static int meson_saradc_get_sample(struct iio_dev *indio_dev,
> +				   const struct iio_chan_spec *chan,
> +				   enum meson_saradc_avg_mode avg_mode,
> +				   enum meson_saradc_num_samples avg_samples,
> +				   int *val)
> +{
> +	int ret, tmp;
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	/* clear old values from the FIFO buffer, ignoring errors */
> +	meson_saradc_read_raw_sample(indio_dev, chan, &tmp);
> +
> +	meson_saradc_set_averaging(indio_dev, chan, avg_mode, avg_samples);
> +
> +	meson_saradc_enable_channel(indio_dev, chan);
> +
> +	meson_saradc_start_sample_engine(indio_dev);
> +	ret = meson_saradc_read_raw_sample(indio_dev, chan, val);
> +	meson_saradc_stop_sample_engine(indio_dev);
> +
> +	meson_saradc_unlock(indio_dev);
> +
> +	if (ret) {
> +		dev_warn(&indio_dev->dev,
Using the struct device in indio_dev results in IMHO ugly messages like
iio iio:device0: already initialized by BL30

We should use the parent instead, this is more readable:
meson-saradc c1108680.adc: already initialized by BL30

For this we need to move the assignment to indio_dev->dev.parent
in probe, else messages may be written when parent isn't set yet.

> +			 "failed to read sample for channel %d: %d\n",
> +			 chan->channel, ret);
> +		return ret;
> +	}
> +
> +	return IIO_VAL_INT;
> +}
> +
> +static int meson_saradc_iio_info_read_raw(struct iio_dev *indio_dev,
> +					  const struct iio_chan_spec *chan,
> +					  int *val, int *val2, long mask)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret;
> +
> +	switch (mask) {
> +	case IIO_CHAN_INFO_RAW:
> +		return meson_saradc_get_sample(indio_dev, chan, NO_AVERAGING,
> +					       ONE_SAMPLE, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_AVERAGE_RAW:
> +		return meson_saradc_get_sample(indio_dev, chan, MEAN_AVERAGING,
> +					       EIGHT_SAMPLES, val);
> +		break;
> +
> +	case IIO_CHAN_INFO_SCALE:
> +		ret = regulator_get_voltage(priv->vref);
> +		if (ret < 0) {
> +			dev_err(&indio_dev->dev,
> +				"failed to get vref voltage: %d\n", ret);
> +			return ret;
> +		}
> +
> +		*val = ret / 1000;
> +		*val2 = priv->resolution;
> +		return IIO_VAL_FRACTIONAL_LOG2;
> +
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int meson_saradc_clk_init(struct iio_dev *indio_dev, void __iomem *base)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	struct clk_init_data init;
> +	char clk_name[32];
> +	const char *clk_parents[1];
> +
> +	snprintf(clk_name, sizeof(clk_name), "%s#adc_div",
> +		 of_node_full_name(indio_dev->dev.of_node));
> +	init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
Consider replacing snprintf + devm_kstrdup with devm_kasprintf

> +	init.flags = 0;
> +	init.ops = &clk_divider_ops;
> +	clk_parents[0] = __clk_get_name(priv->clkin);
> +	init.parent_names = clk_parents;
> +	init.num_parents = 1;
> +
> +	priv->clk_div.reg = base + SAR_ADC_REG3;
> +	priv->clk_div.shift = SAR_ADC_REG3_ADC_CLK_DIV_SHIFT;
> +	priv->clk_div.width = SAR_ADC_REG3_ADC_CLK_DIV_WIDTH;
> +	priv->clk_div.hw.init = &init;
> +	priv->clk_div.flags = 0;
> +
> +	priv->adc_div_clk = devm_clk_register(&indio_dev->dev,
> +					      &priv->clk_div.hw);
> +	if (WARN_ON(IS_ERR(priv->adc_div_clk)))
> +		return PTR_ERR(priv->adc_div_clk);
> +
> +	snprintf(clk_name, sizeof(clk_name), "%s#adc_en",
> +		 of_node_full_name(indio_dev->dev.of_node));
> +	init.name = devm_kstrdup(&indio_dev->dev, clk_name, GFP_KERNEL);
> +	init.flags = CLK_SET_RATE_PARENT;
> +	init.ops = &clk_gate_ops;
> +	clk_parents[0] = __clk_get_name(priv->adc_div_clk);
> +	init.parent_names = clk_parents;
> +	init.num_parents = 1;
> +
> +	priv->clk_gate.reg = base + SAR_ADC_REG3;
> +	priv->clk_gate.bit_idx = fls(SAR_ADC_REG3_CLK_EN);
> +	priv->clk_gate.hw.init = &init;
> +
> +	priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw);
> +	if (WARN_ON(IS_ERR(priv->adc_clk)))
> +		return PTR_ERR(priv->adc_clk);
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_init(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int regval, ret;
> +
> +	/* make sure we start at CH7 input */
> +	meson_saradc_set_channel7_mux(indio_dev, CHAN7_MUX_CH7_INPUT);
> +
> +	regmap_read(priv->regmap, SAR_ADC_REG3, &regval);
> +	if (regval & SAR_ADC_REG3_BL30_INITIALIZED) {
> +		dev_info(&indio_dev->dev, "already initialized by BL30\n");
> +		return 0;
> +	}
> +
> +	dev_info(&indio_dev->dev, "initializing SAR ADC\n");
> +
> +	meson_saradc_stop_sample_engine(indio_dev);
> +
> +	/* update the channel 6 MUX to select the temperature sensor */
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG0,
> +			SAR_ADC_REG0_ADC_TEMP_SEN_SEL,
> +			SAR_ADC_REG0_ADC_TEMP_SEN_SEL);
> +
> +	/* disable all channels by default */
> +	regmap_write(priv->regmap, SAR_ADC_CHAN_LIST, 0x0);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3,
> +			   SAR_ADC_REG3_CNTL_USE_SC_DLY,
> +			   SAR_ADC_REG3_CNTL_USE_SC_DLY);
> +
> +	/* delay between two samples = (10+1) * 1uS */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 10));
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 0));
> +
> +	/* delay between two samples = (10+1) * 1uS */
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_CNT_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 10));
> +	regmap_update_bits(priv->regmap, SAR_ADC_DELAY,
> +			   SAR_ADC_DELAY_INPUT_DLY_SEL_MASK,
> +			   FIELD_PREP(SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 1));
> +
> +	ret = clk_set_parent(priv->adc_sel_clk, priv->clkin);
> +	if (ret) {
> +		dev_err(&indio_dev->dev,
> +			"failed to set adc parent to clkin\n");
> +		return ret;
> +	}
> +
> +	ret = clk_set_rate(priv->adc_clk, 1200000);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to set adc clock rate\n");
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_hw_enable(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +	int ret;
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	ret = regulator_enable(priv->vref);
> +	if (ret < 0) {
> +		dev_err(&indio_dev->dev, "failed to enable vref regulator\n");
> +		goto err_vref;
> +	}
> +
> +	ret = clk_prepare_enable(priv->core_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable core clk\n");
> +		goto err_core_clk;
> +	}
> +
> +	ret = clk_prepare_enable(priv->sana_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable sana clk\n");
> +		goto err_sana_clk;
> +	}
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
> +			   SAR_ADC_REG11_BANDGAP_EN, SAR_ADC_REG11_BANDGAP_EN);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN,
> +			   SAR_ADC_REG3_ADC_EN);
> +
> +	udelay(5);
> +
> +	ret = clk_prepare_enable(priv->adc_clk);
> +	if (ret) {
> +		dev_err(&indio_dev->dev, "failed to enable adc_en clk\n");
> +		goto err_adc_clk;
> +	}
> +
> +	meson_saradc_unlock(indio_dev);
> +
> +	return 0;
> +
> +err_adc_clk:
> +	clk_disable_unprepare(priv->sana_clk);
> +err_sana_clk:
> +	clk_disable_unprepare(priv->core_clk);
> +err_core_clk:
> +	regulator_disable(priv->vref);
> +err_vref:
> +	meson_saradc_unlock(indio_dev);
> +	return ret;
> +}
> +
> +static void meson_saradc_hw_disable(struct iio_dev *indio_dev)
> +{
> +	struct meson_saradc_priv *priv = iio_priv(indio_dev);
> +
> +	meson_saradc_lock(indio_dev);
> +
> +	clk_disable_unprepare(priv->adc_clk);
> +
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG3, SAR_ADC_REG3_ADC_EN, 0);
> +	regmap_update_bits(priv->regmap, SAR_ADC_REG11,
> +			   SAR_ADC_REG11_BANDGAP_EN, 0);
> +
> +	clk_disable_unprepare(priv->sana_clk);
> +	clk_disable_unprepare(priv->core_clk);
> +
> +	regulator_disable(priv->vref);
> +
> +	meson_saradc_unlock(indio_dev);
> +}
> +
> +static const struct iio_info meson_saradc_iio_info = {
> +	.read_raw = meson_saradc_iio_info_read_raw,
> +	.driver_module = THIS_MODULE,
> +};
> +
> +static const struct of_device_id meson_saradc_of_match[] = {
> +	{
> +		.compatible = "amlogic,meson-gxbb-saradc",
> +		.data = (void *)10,
> +	}, {
> +		.compatible = "amlogic,meson-gxl-saradc",
> +		.data = (void *)12,
> +	},
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, meson_saradc_of_match);
> +
> +static int meson_saradc_probe(struct platform_device *pdev)
> +{
> +	struct meson_saradc_priv *priv;
> +	struct iio_dev *indio_dev;
> +	struct resource *res;
> +	void __iomem *base;
> +	const struct of_device_id *match;
> +	int ret;
> +
> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv));
> +	if (!indio_dev) {
> +		dev_err(&pdev->dev, "failed allocating iio device\n");
> +		return -ENOMEM;
> +	}
> +
> +	priv = iio_priv(indio_dev);
> +
> +	match = of_match_device(meson_saradc_of_match, &pdev->dev);
> +	priv->resolution = (unsigned long)match->data;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(base))
> +		return PTR_ERR(base);
> +
> +	priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
> +					     &meson_saradc_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return PTR_ERR(priv->regmap);
> +
> +	init_completion(&priv->completion);
> +
> +	priv->clkin = devm_clk_get(&pdev->dev, "clkin");
> +	if (IS_ERR(priv->clkin)) {
> +		dev_err(&pdev->dev, "failed to get clkin\n");
> +		return PTR_ERR(priv->clkin);
> +	}
> +
> +	priv->core_clk = devm_clk_get(&pdev->dev, "core");
> +	if (IS_ERR(priv->core_clk)) {
> +		dev_err(&pdev->dev, "failed to get core clk\n");
> +		return PTR_ERR(priv->core_clk);
> +	}
> +
> +	priv->sana_clk = devm_clk_get(&pdev->dev, "sana");
> +	if (IS_ERR(priv->sana_clk)) {
> +		if (PTR_ERR(priv->sana_clk) == -ENOENT) {
> +			priv->sana_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get sana clk\n");
> +			return PTR_ERR(priv->sana_clk);
> +		}
> +	}
> +
> +	priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk");
> +	if (IS_ERR(priv->adc_clk)) {
> +		if (PTR_ERR(priv->adc_clk) == -ENOENT) {
> +			priv->adc_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get adc clk\n");
> +			return PTR_ERR(priv->adc_clk);
> +		}
> +	}
> +
> +	priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel");
> +	if (IS_ERR(priv->adc_sel_clk)) {
> +		if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) {
> +			priv->adc_sel_clk = NULL;
> +		} else {
> +			dev_err(&pdev->dev, "failed to get adc_sel clk\n");
> +			return PTR_ERR(priv->adc_sel_clk);
> +		}
> +	}
> +
> +	/* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */
> +	if (!priv->adc_clk) {
> +		ret = meson_saradc_clk_init(indio_dev, base);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	priv->vref = devm_regulator_get(&pdev->dev, "vref");
> +	if (IS_ERR(priv->vref)) {
> +		dev_err(&pdev->dev, "failed to get vref regulator\n");
> +		return PTR_ERR(priv->vref);
> +	}
> +
> +	ret = meson_saradc_init(indio_dev);
> +	if (ret)
> +		goto err;
> +
> +	ret = meson_saradc_hw_enable(indio_dev);
> +	if (ret)
> +		goto err;
> +
> +	platform_set_drvdata(pdev, indio_dev);
> +
> +	indio_dev->name = dev_name(&pdev->dev);
> +	indio_dev->dev.parent = &pdev->dev;
> +	indio_dev->dev.of_node = pdev->dev.of_node;
> +	indio_dev->modes = INDIO_DIRECT_MODE;
> +	indio_dev->info = &meson_saradc_iio_info;
> +
> +	indio_dev->channels = meson_saradc_iio_channels;
> +	indio_dev->num_channels = SAR_ADC_NUM_CHANNELS;
> +
> +	ret = iio_device_register(indio_dev);
> +	if (ret)
> +		goto err_hw;
> +
> +	return 0;
> +
> +err_hw:
> +	meson_saradc_hw_disable(indio_dev);
> +err:
> +	return ret;
> +}
> +
> +static int meson_saradc_remove(struct platform_device *pdev)
> +{
> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> +
> +	meson_saradc_hw_disable(indio_dev);
> +	iio_device_unregister(indio_dev);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int meson_saradc_suspend(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	meson_saradc_hw_disable(indio_dev);
> +
> +	return 0;
> +}
> +
> +static int meson_saradc_resume(struct device *dev)
> +{
> +	struct iio_dev *indio_dev = dev_get_drvdata(dev);
> +
> +	return meson_saradc_hw_enable(indio_dev);
> +}
> +#endif /* CONFIG_PM_SLEEP */
> +
> +static SIMPLE_DEV_PM_OPS(meson_saradc_pm_ops,
> +			 meson_saradc_suspend, meson_saradc_resume);
> +
> +static struct platform_driver meson_saradc_driver = {
> +	.probe		= meson_saradc_probe,
> +	.remove		= meson_saradc_remove,
> +	.driver		= {
> +		.name	= "meson-saradc",
> +		.of_match_table = meson_saradc_of_match,
> +		.pm = &meson_saradc_pm_ops,
> +	},
> +};
> +
> +module_platform_driver(meson_saradc_driver);
> +
> +MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@xxxxxxxxxxxxxx>");
> +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver");
> +MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply

* [PATCH 07/10] sata: ahci_da850: add support for the da850,clk_multiplier DT property
From: David Lechner @ 2017-01-13 19:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484311084-31547-8-git-send-email-bgolaszewski@baylibre.com>

On 01/13/2017 06:38 AM, Bartosz Golaszewski wrote:
> Currently the clock multiplier is hardcoded in the driver for
> the da850-evm board. Make it configurable over DT, but keep the
> previous value as default in case the property is missing.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  drivers/ata/ahci_da850.c | 83 +++++++++++++++++++++++++++++++++++++++++++-----
>  1 file changed, 75 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
> index bb9eb4c..cd04caf 100644
> --- a/drivers/ata/ahci_da850.c
> +++ b/drivers/ata/ahci_da850.c
> @@ -28,17 +28,70 @@
>  #define SATA_PHY_TXSWING(x)	((x) << 19)
>  #define SATA_PHY_ENPLL(x)	((x) << 31)
>
> +struct da850_sata_mpy_mapping {
> +	unsigned int multiplier;
> +	unsigned int regval;
> +};
> +
> +static const struct da850_sata_mpy_mapping da850_sata_mpy_table[] = {
> +	{
> +		.multiplier	= 5,
> +		.regval		= 0x01,
> +	},
> +	{
> +		.multiplier	= 6,
> +		.regval		= 0x02,
> +	},
> +	{
> +		.multiplier	= 8,
> +		.regval		= 0x04,
> +	},
> +	{
> +		.multiplier	= 10,
> +		.regval		= 0x05,
> +	},
> +	{
> +		.multiplier	= 12,
> +		.regval		= 0x06,
> +	},
> +	/* TODO Add 12.5 multiplier. */

Looks like you should be using an enum here for the multiplier field.

> +	{
> +		.multiplier	= 15,
> +		.regval		= 0x08,
> +	},
> +	{
> +		.multiplier	= 20,
> +		.regval		= 0x09,
> +	},
> +	{
> +		.multiplier	= 25,
> +		.regval		= 0x0a,
> +	}
> +};
> +
> +static const struct da850_sata_mpy_mapping *
> +da850_sata_get_mpy(unsigned int multiplier)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(da850_sata_mpy_table); i++)
> +		if (da850_sata_mpy_table[i].multiplier == multiplier)
> +			return &da850_sata_mpy_table[i];
> +
> +	return NULL;
> +}
> +
>  /*
>   * The multiplier needed for 1.5GHz PLL output.
>   *
> - * NOTE: This is currently hardcoded to be suitable for 100MHz crystal
> - * frequency (which is used by DA850 EVM board) and may need to be changed
> - * if you would like to use this driver on some other board.
> + * This is the default value suitable for the 100MHz crystal frequency
> + * used by DA850 EVM board, which doesn't use DT.

As I said in a reply on another patch, it seems like it would be better 
to use a clock that represents the crystal and use clk_get_rate() and 
calculate the multiplier from that.

For example, we have done something like this in 
usb20_phy_clk_set_parent() in arch/arm/mach-davinci/usb-da8xx.c.

>   */
> -#define DA850_SATA_CLK_MULTIPLIER	7
> +#define DA850_SATA_CLK_MULTIPLIER_DEFAULT	15
>
>  static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
> -			    void __iomem *ahci_base)
> +			    void __iomem *ahci_base,
> +			    const struct da850_sata_mpy_mapping *mpy)
>  {
>  	unsigned int val;
>
> @@ -47,7 +100,7 @@ static void da850_sata_init(struct device *dev, void __iomem *pwrdn_reg,
>  	val &= ~BIT(0);
>  	writel(val, pwrdn_reg);
>
> -	val = SATA_PHY_MPY(DA850_SATA_CLK_MULTIPLIER + 1) | SATA_PHY_LOS(1) |
> +	val = SATA_PHY_MPY(mpy->regval) | SATA_PHY_LOS(1) |
>  	      SATA_PHY_RXCDR(4) | SATA_PHY_RXEQ(1) | SATA_PHY_TXSWING(3) |
>  	      SATA_PHY_ENPLL(1);
>
> @@ -87,10 +140,12 @@ static struct scsi_host_template ahci_platform_sht = {
>
>  static int ahci_da850_probe(struct platform_device *pdev)
>  {
> +	const struct da850_sata_mpy_mapping *mpy;
>  	struct device *dev = &pdev->dev;
>  	struct ahci_host_priv *hpriv;
> -	struct resource *res;
> +	unsigned int multiplier;
>  	void __iomem *pwrdn_reg;
> +	struct resource *res;
>  	int rc;
>
>  	hpriv = ahci_platform_get_resources(pdev);
> @@ -109,7 +164,19 @@ static int ahci_da850_probe(struct platform_device *pdev)
>  	if (!pwrdn_reg)
>  		goto disable_resources;
>
> -	da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
> +	rc = of_property_read_u32(dev->of_node,
> +				  "da850,clk_multiplier", &multiplier);
> +	if (rc)
> +		multiplier = DA850_SATA_CLK_MULTIPLIER_DEFAULT;
> +
> +	mpy = da850_sata_get_mpy(multiplier);
> +	if (!mpy) {
> +		dev_err(dev, "invalid multiplier value: %u\n", multiplier);
> +		rc = -EINVAL;
> +		goto disable_resources;
> +	}
> +
> +	da850_sata_init(dev, pwrdn_reg, hpriv->mmio, mpy);
>
>  	rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
>  				     &ahci_platform_sht);
>

^ permalink raw reply

* [PATCH v18 00/15] acpi, clocksource: add GTDT driver and GTDT support in arm_arch_timer
From: Mark Rutland @ 2017-01-13 19:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20161208173319.6618-1-fu.wei@linaro.org>

Hi,

On Fri, Dec 09, 2016 at 01:33:04AM +0800, fu.wei at linaro.org wrote:
> From: Fu Wei <fu.wei@linaro.org>
> 
> This patchset:
>     (1)Preparation for adding GTDT support in arm_arch_timer:
>         1. Move some enums and marcos to header file;
>         2. Add a new enum for spi type;
>         3. Improve printk relevant code;
>         4. Rename some enums and defines;
>         5. Rework PPI determination;
>         6. Rework counter frequency detection;
>         7. Refactor arch_timer_needs_probing, move it into DT init call
>         8. Introduce some new structs and refactor the MMIO timer init code
>         for reusing some common code.
> 
>     (2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
>     Parse all kinds of timer in GTDT table of ACPI:arch timer,
>     memory-mapped timer and SBSA Generic Watchdog timer.
>     This driver can help to simplify all the relevant timer drivers,
>     and separate all the ACPI GTDT knowledge from them.
> 
>     (3)Simplify ACPI code for arm_arch_timer
> 
>     (4)Add GTDT support for ARM memory-mapped timer.
> 
> This patchset has been tested on the following platforms with ACPI enabled:
>     (1)ARM Foundation v8 model

Once v4.10-rc4 comes out this weekend, could you please rebase and
repost this?

Marc and I will be happy to take a look then.

Thanks,
Mark.

^ permalink raw reply

* [PATCH v3 2/4] dt-bindings: Add TI SCI PM Domains
From: Rob Herring @ 2017-01-13 19:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3bb89649-fd2a-acc6-6968-e54a00842ce2@ti.com>

On Thu, Jan 12, 2017 at 9:27 AM, Dave Gerlach <d-gerlach@ti.com> wrote:
> Rob,
>
> On 01/11/2017 03:34 PM, Rob Herring wrote:
>>
>> On Mon, Jan 9, 2017 at 11:57 AM, Dave Gerlach <d-gerlach@ti.com> wrote:
>>>
>>> Rob,
>>>
>>> On 01/09/2017 11:50 AM, Rob Herring wrote:
>>>>
>>>>
>>>> On Wed, Jan 04, 2017 at 02:55:34PM -0600, Dave Gerlach wrote:
>>>>>
>>>>>
>>>>> Add a generic power domain implementation, TI SCI PM Domains, that
>>>>> will hook into the genpd framework and allow the TI SCI protocol to
>>>>> control device power states.
>>>>>
>>>>> Also, provide macros representing each device index as understood
>>>>> by TI SCI to be used in the device node power-domain references.
>>>>> These are identifiers for the K2G devices managed by the PMMC.
>>>>>
>>>>> Signed-off-by: Nishanth Menon <nm@ti.com>
>>>>> Signed-off-by: Dave Gerlach <d-gerlach@ti.com>
>>>>> ---
>>>>> v2->v3:
>>>>>         Update k2g_pds node docs to show it should be a child of pmmc
>>>>> node.
>>>>>         In early versions a phandle was used to point to pmmc and docs
>>>>> still
>>>>>         incorrectly showed this.
>>>>>
>>>>>  .../devicetree/bindings/soc/ti/sci-pm-domain.txt   | 59 ++++++++++++++
>>>>>  MAINTAINERS                                        |  2 +
>>>>>  include/dt-bindings/genpd/k2g.h                    | 90
>>>>> ++++++++++++++++++++++
>>>>>  3 files changed, 151 insertions(+)
>>>>>  create mode 100644
>>>>> Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>>  create mode 100644 include/dt-bindings/genpd/k2g.h
>>>>>
>>>>> diff --git a/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>> b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>> new file mode 100644
>>>>> index 000000000000..4c9064e512cb
>>>>> --- /dev/null
>>>>> +++ b/Documentation/devicetree/bindings/soc/ti/sci-pm-domain.txt
>>>>> @@ -0,0 +1,59 @@
>>>>> +Texas Instruments TI-SCI Generic Power Domain
>>>>> +---------------------------------------------
>>>>> +
>>>>> +Some TI SoCs contain a system controller (like the PMMC, etc...) that
>>>>> is
>>>>> +responsible for controlling the state of the IPs that are present.
>>>>> +Communication between the host processor running an OS and the system
>>>>> +controller happens through a protocol known as TI-SCI [1]. This pm
>>>>> domain
>>>>> +implementation plugs into the generic pm domain framework and makes
>>>>> use
>>>>> of
>>>>> +the TI SCI protocol power on and off each device when needed.
>>>>> +
>>>>> +[1] Documentation/devicetree/bindings/arm/keystone/ti,sci.txt
>>>>> +
>>>>> +PM Domain Node
>>>>> +==============
>>>>> +The PM domain node represents the global PM domain managed by the
>>>>> PMMC,
>>>>> +which in this case is the single implementation as documented by the
>>>>> generic
>>>>> +PM domain bindings in
>>>>> Documentation/devicetree/bindings/power/power_domain.txt.
>>>>> +Because this relies on the TI SCI protocol to communicate with the
>>>>> PMMC
>>>>> it
>>>>> +must be a child of the pmmc node.
>>>>> +
>>>>> +Required Properties:
>>>>> +--------------------
>>>>> +- compatible: should be "ti,sci-pm-domain"
>>>>> +- #power-domain-cells: Must be 0.
>>>>> +
>>>>> +Example (K2G):
>>>>> +-------------
>>>>> +       pmmc: pmmc {
>>>>> +               compatible = "ti,k2g-sci";
>>>>> +               ...
>>>>> +
>>>>> +               k2g_pds: k2g_pds {
>>>>> +                       compatible = "ti,sci-pm-domain";
>>>>> +                       #power-domain-cells = <0>;
>>>>> +               };
>>>>> +       };
>>>>> +
>>>>> +PM Domain Consumers
>>>>> +===================
>>>>> +Hardware blocks that require SCI control over their state must provide
>>>>> +a reference to the sci-pm-domain they are part of and a unique device
>>>>> +specific ID that identifies the device.
>>>>> +
>>>>> +Required Properties:
>>>>> +--------------------
>>>>> +- power-domains: phandle pointing to the corresponding PM domain node.
>>>>> +- ti,sci-id: index representing the device id to be passed oevr SCI to
>>>>> +            be used for device control.
>>>>
>>>>
>>>>
>>>> As I've already stated before, this goes in power-domain cells. When you
>>>> have a single thing (i.e. node) that controls multiple things, then you
>>>> you need to specify the ID for each of them in phandle args. This is how
>>>> irqs, gpio, clocks, *everything* in DT works.
>>>
>>>
>>>
>>> You think the reasoning for doing it this way provided by both Ulf and
>>> myself on v2 [1] is not valid then?
>>>
>>> From Ulf:
>>>
>>> To me, the TI SCI ID, is similar to a "conid" for any another "device
>>> resource" (like clock, pinctrl, regulator etc) which we can describe
>>> in DT and assign to a device node. The only difference here, is that
>>> we don't have common API to fetch the resource (like clk_get(),
>>> regulator_get()), but instead we fetches the device's resource from
>>> SoC specific code, via genpd's device ->attach() callback.
>>
>>
>> Sorry, but that sounds like a kernel problem to me and has nothing to
>> do with DT bindings.
>>
>>> From me:
>>>
>>> Yes, you've pretty much hit it on the head. It is not an index into a
>>> list
>>> of genpds but rather identifies the device *within* a single genpd. It is
>>> a
>>> property specific to each device that resides in a ti-sci-genpd, not a
>>> mapping describing which genpd the device belongs to. The generic power
>>> domain binding is concerned with mapping the device to a specific genpd,
>>> which is does fine for us, but we have a sub mapping for devices that
>>> exist
>>> inside a genpd which, we must describe as well, hence the ti,sci-id.
>>>
>>>
>>> So to summarize, the genpd framework does interpret the phandle arg as an
>>> index into multiple genpds, just as you've said other frameworks do, but
>>> this is not what I am trying to do, we have multiple devices within this
>>> *single* genpd, hence the need for the ti,sci-id property.
>>
>>
>> Fix the genpd framework rather than work around it in DT.
>
>
> I still disagree that this has nothing to do with DT bindings, as the
> current DT binding represents something different already. I am trying to
> extend it to give me additional information needed for our platforms. Are
> you saying that we should break what the current DT binding already
> represents to mean something else?

No idea because what's the current binding? From the patch, looks like
a new binding to me.

Rob

^ permalink raw reply

* [PATCH 03/10] devicetree: bindings: add bindings for ahci-da850
From: David Lechner @ 2017-01-13 19:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484311084-31547-4-git-send-email-bgolaszewski@baylibre.com>

On 01/13/2017 06:37 AM, Bartosz Golaszewski wrote:
> Add DT bindings for the TI DA850 AHCI SATA controller.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
> ---
>  .../devicetree/bindings/ata/ahci-da850.txt          | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/ata/ahci-da850.txt
>
> diff --git a/Documentation/devicetree/bindings/ata/ahci-da850.txt b/Documentation/devicetree/bindings/ata/ahci-da850.txt
> new file mode 100644
> index 0000000..d07c241
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/ata/ahci-da850.txt
> @@ -0,0 +1,21 @@
> +Device tree binding for the TI DA850 AHCI SATA Controller
> +---------------------------------------------------------
> +
> +Required properties:
> +  - compatible: must be "ti,da850-ahci"
> +  - reg: physical base addresses and sizes of the controller's register areas
> +  - interrupts: interrupt specifier (refer to the interrupt binding)
> +
> +Optional properties:
> +  - clocks: clock specifier (refer to the common clock binding)
> +  - da850,clk_multiplier: the multiplier for the reference clock needed
> +                          for 1.5GHz PLL output

A clock multiplier property seems redundant if you are specifying a 
clock. It should be possible to get the rate from the clock to determine 
which multiplier is needed.

> +
> +Example:
> +
> +	sata: ahci at 0x218000 {
> +		compatible = "ti,da850-ahci";
> +		reg = <0x218000 0x2000>, <0x22c018 0x4>;
> +		interrupts = <67>;
> +		da850,clk_multiplier = <7>;
> +	};
>

^ permalink raw reply

* [RFC PATCH v2 04/10] arm64: head.S: Enable EL1 (host) access to SPE when entered at EL2
From: Marc Zyngier @ 2017-01-13 19:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484323429-15231-5-git-send-email-will.deacon@arm.com>

On 13/01/17 16:03, Will Deacon wrote:
> The SPE architecture requires each exception level to enable access
> to the SPE controls for the exception level below it, since additional
> context-switch logic may be required to handle the buffer safely.
> 
> This patch allows EL1 (host) access to the SPE controls when entered at
> EL2.
> 
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
>  arch/arm64/kernel/head.S | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
> index 4b1abac3485a..6a97831dcf3b 100644
> --- a/arch/arm64/kernel/head.S
> +++ b/arch/arm64/kernel/head.S
> @@ -592,8 +592,8 @@ CPU_LE(	movk	x0, #0x30d0, lsl #16	)	// Clear EE and E0E on LE systems
>  #endif
>  
>  	/* EL2 debug */
> -	mrs	x0, id_aa64dfr0_el1		// Check ID_AA64DFR0_EL1 PMUVer
> -	sbfx	x0, x0, #8, #4
> +	mrs	x1, id_aa64dfr0_el1		// Check ID_AA64DFR0_EL1 PMUVer
> +	sbfx	x0, x1, #8, #4
>  	cmp	x0, #1
>  	b.lt	4f				// Skip if no PMU present
>  	mrs	x0, pmcr_el0			// Disable debug access traps
> @@ -601,6 +601,16 @@ CPU_LE(	movk	x0, #0x30d0, lsl #16	)	// Clear EE and E0E on LE systems
>  4:
>  	csel	x0, xzr, x0, lt			// all PMU counters from EL1
>  	msr	mdcr_el2, x0			// (if they exist)
> +	/* Statistical profiling */
> +	ubfx	x0, x1, #32, #4			// Check ID_AA64DFR0_EL1 PMSVer
> +	cbz	x0, 5f				// Skip if SPE not present
> +	mrs	x0, mdcr_el2			// Preserve HPMN field
> +	cmp	x2, xzr				// If VHE is not enabled,
> +	mov	x1, #3				// use EL1&0 translations,
> +	cinc	x1, x1, ne			// otherwise use EL2 and
> +	bfi	x0, x1, #12, #3			// enable/disable access
> +	msr	mdcr_el2, x0			// traps accordingly.

Man, this hack to set TPMS and E2PB is horrid. It does the trick, but it
took me a couple of minutes to realize what it was doing. Can't we just
have named flags and a some form of conditional select instead? It would
hurt a lot less...

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v4 0/2] Add support rockchip, grf property for RK3399 PMU/GRU
From: Heiko Stuebner @ 2017-01-13 19:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484028930-20305-1-git-send-email-zhengxing@rock-chips.com>

Am Dienstag, 10. Januar 2017, 14:15:28 CET schrieb Xing Zheng:
> Hi,
>   The structure rockchip_clk_provider needs to refer the GRF regmap
> in somewhere, if the CRU node has not "rockchip,grf" property,
> calling syscon_regmap_lookup_by_phandle will return an invalid GRF
> regmap, and the MUXGRF type clock will be not supported.
> 
> Therefore, we need to add them.
> 
> Thanks.

applied both for 4.11

binding-change is in my clock-branch (so that dt-binding doc changes stay 
together) and the dts change is of course in the dts64 branch.


Thanks
Heiko

^ permalink raw reply

* [PATCH 2/3] KVM: arm64: Access CNTHCTL_EL2 bit fields correctly on VHE systems
From: Jintack Lim @ 2017-01-13 19:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <e0d1473f-0cf9-a801-585b-4385bc5b35ab@arm.com>

On Fri, Jan 13, 2017 at 9:56 AM, Suzuki K Poulose
<Suzuki.Poulose@arm.com> wrote:
> On 13/01/17 13:30, Marc Zyngier wrote:
>>
>> [+ Suzuki, who wrote the whole cpus_have_const_cap thing]
>>
>> On 13/01/17 12:36, Christoffer Dall wrote:
>>>
>>> On Fri, Jan 13, 2017 at 11:31:32AM +0000, Marc Zyngier wrote:
>>>>
>>>> From: Jintack Lim <jintack@cs.columbia.edu>
>>>>
> ...
>
>
>>>>  /*
>>>>   * __boot_cpu_mode records what mode CPUs were booted in.
>>>> @@ -80,6 +81,14 @@ static inline bool is_kernel_in_hyp_mode(void)
>>>>         return read_sysreg(CurrentEL) == CurrentEL_EL2;
>>>>  }
>>>>
>>>> +static inline bool has_vhe(void)
>>>> +{
>>>> +       if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
>>>> +               return true;
>>>> +
>>>> +       return false;
>>>> +}
>>>> +
>>>
>>>
>>> I was experimenting with using has_vhe for some of the optimization code
>>> I was writing, and I saw a hyp crash as a result.  That made me wonder
>>> if this is really safe in Hyp mode?
>>>
>>> Specifically, there is no guarantee that this will actually be inlined
>>> in the caller, right?  At least that's what I can gather from trying to
>>> understand the semantics of the inline keyword in the GCC manual.
>>
>>
>> Indeed, there is no strict guarantee that this is enforced. We should
>> probably have __always_inline instead. But having checked the generated
>> code for __timer_restore_state, the function is definitely inlined
>> (gcc 6.2). Happy to queue an extra patch changing that.
>>
>>> Further, are we guaranteed that the static branch gets compiled into
>>> something that doesn't actually look at cpu_hwcap_keys, which is not
>>> mapped in hyp mode?
>>
>>
>> Here's the disassembly:
>>
>> ffff000008ad01d0 <__timer_restore_state>:
>> ffff000008ad01d0:       f9400001        ldr     x1, [x0]
>> ffff000008ad01d4:       9240bc21        and     x1, x1, #0xffffffffffff
>> ffff000008ad01d8:       d503201f        nop
>> ffff000008ad01dc:       d503201f        nop
>> ffff000008ad01e0:       d53ce102        mrs     x2, cnthctl_el2
>> ffff000008ad01e4:       927ef842        and     x2, x2,
>> #0xfffffffffffffffd
>> ffff000008ad01e8:       b2400042        orr     x2, x2, #0x1
>> ffff000008ad01ec:       d51ce102        msr     cnthctl_el2, x2
>> ffff000008ad01f0:       d2834002        mov     x2, #0x1a00
>> // #6656
>> ffff000008ad01f4:       8b020000        add     x0, x0, x2
>> ffff000008ad01f8:       91038002        add     x2, x0, #0xe0
>> ffff000008ad01fc:       39425443        ldrb    w3, [x2,#149]
>> ffff000008ad0200:       34000103        cbz     w3, ffff000008ad0220
>> <__timer_restore_state+0x50>
>> ffff000008ad0204:       f945a821        ldr     x1, [x1,#2896]
>> ffff000008ad0208:       d51ce061        msr     cntvoff_el2, x1
>> ffff000008ad020c:       f9400441        ldr     x1, [x2,#8]
>> ffff000008ad0210:       d51be341        msr     cntv_cval_el0, x1
>> ffff000008ad0214:       d5033fdf        isb
>> ffff000008ad0218:       b940e000        ldr     w0, [x0,#224]
>> ffff000008ad021c:       d51be320        msr     cntv_ctl_el0, x0
>> ffff000008ad0220:       d65f03c0        ret
>>
>> The static branch resolves as such when VHE is enabled (taken from
>> a running model):
>>
>> ffff000008ad01d0 <__timer_restore_state>:
>> ffff000008ad01d0:       f9400001        ldr     x1, [x0]
>> ffff000008ad01d4:       9240bc21        nop
>> ffff000008ad01d8:       d503201f        nop
>> ffff000008ad01dc:       d503201f        b       ffff000008ad01f0
>> ffff000008ad01e0:       d53ce102        mrs     x2, cnthctl_el2
>> [...]
>>
>> That's using a toolchain that supports the "asm goto" feature that is used
>> to implement static branches (and that's guaranteed not to generate any
>> memory access other than the code patching itself).
>>
>> Now, with a toolchain that doesn't support this, such as gcc 4.8:
>>
>> ffff000008aa5168 <__timer_restore_state>:
>> ffff000008aa5168:       f9400001        ldr     x1, [x0]
>> ffff000008aa516c:       9240bc21        and     x1, x1, #0xffffffffffff
>> ffff000008aa5170:       d503201f        nop
>> ffff000008aa5174:       f00038a2        adrp    x2, ffff0000091bc000
>> <reset_devices>
>> ffff000008aa5178:       9113e042        add     x2, x2, #0x4f8
>> ffff000008aa517c:       b9402c42        ldr     w2, [x2,#44]
>> ffff000008aa5180:       6b1f005f        cmp     w2, wzr
>> ffff000008aa5184:       540000ac        b.gt    ffff000008aa5198
>> <__timer_restore_state+0x30>
>> ffff000008aa5188:       d53ce102        mrs     x2, cnthctl_el2
>> ffff000008aa518c:       927ef842        and     x2, x2,
>> #0xfffffffffffffffd
>> ffff000008aa5190:       b2400042        orr     x2, x2, #0x1
>> ffff000008aa5194:       d51ce102        msr     cnthctl_el2, x2
>> ffff000008aa5198:       91400402        add     x2, x0, #0x1, lsl #12
>> ffff000008aa519c:       396dd443        ldrb    w3, [x2,#2933]
>> ffff000008aa51a0:       34000103        cbz     w3, ffff000008aa51c0
>> <__timer_restore_state+0x58>
>> ffff000008aa51a4:       f945a821        ldr     x1, [x1,#2896]
>> ffff000008aa51a8:       d51ce061        msr     cntvoff_el2, x1
>> ffff000008aa51ac:       f9457441        ldr     x1, [x2,#2792]
>> ffff000008aa51b0:       d51be341        msr     cntv_cval_el0, x1
>> ffff000008aa51b4:       d5033fdf        isb
>> ffff000008aa51b8:       b95ae000        ldr     w0, [x0,#6880]
>> ffff000008aa51bc:       d51be320        msr     cntv_ctl_el0, x0
>> ffff000008aa51c0:       d65f03c0        ret
>>
>> This is now controlled by some date located at FFFF0000091BC524:
>>
>> maz at approximate:~/Work/arm-platforms$ aarch64-linux-gnu-objdump -h vmlinux
>>
>> vmlinux:     file format elf64-littleaarch64
>>
>> Sections:
>> Idx Name          Size      VMA               LMA               File off
>> Algn
>> [...]
>>  23 .bss          000da348  ffff0000091b8000  ffff0000091b8000  01147a00
>> 2**12
>>                   ALLOC
>>
>> That's the BSS, which we do map in HYP (fairly recent).
>>
>> But maybe we should have have some stronger guarantees that we'll
>> always get things inlined, and that the "const" side is enforced:
>
>
> Agreed.
>
>>
>> diff --git a/arch/arm64/include/asm/cpufeature.h
>> b/arch/arm64/include/asm/cpufeature.h
>> index b4989df..4710469 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -105,10 +105,11 @@ static inline bool cpu_have_feature(unsigned int
>> num)
>>  }
>>
>>  /* System capability check for constant caps */
>> -static inline bool cpus_have_const_cap(int num)
>> +static __always_inline bool cpus_have_const_cap(int num)
>
>
> I think we should have the above change and make it inline always.
>
>>  {
>> -       if (num >= ARM64_NCAPS)
>> -               return false;
>> +       BUILD_BUG_ON(!__builtin_constant_p(num));
>
>
> This is not needed, as the compilation would fail if num is not a constant
> with
> static key code.
>
>> +       BUILD_BUG_ON(num >= ARM64_NCAPS);
>> +
>
>
> Also, I think it would be good to return false for caps > the ARM64_NCAPS,
> in sync
> with the non-const version.
>
>
>>         return static_branch_unlikely(&cpu_hwcap_keys[num]);
>>  }
>>
>> diff --git a/arch/arm64/include/asm/virt.h b/arch/arm64/include/asm/virt.h
>> index 439f6b5..1257701 100644
>> --- a/arch/arm64/include/asm/virt.h
>> +++ b/arch/arm64/include/asm/virt.h
>> @@ -81,7 +81,7 @@ static inline bool is_kernel_in_hyp_mode(void)
>>         return read_sysreg(CurrentEL) == CurrentEL_EL2;
>>  }
>>
>> -static inline bool has_vhe(void)
>> +static __always_inline bool has_vhe(void)
>>  {
>>         if (cpus_have_const_cap(ARM64_HAS_VIRT_HOST_EXTN))
>>                 return true;
>>

I'm fine with the above change.

Thanks,
Jintack

>>
>> But that's probably another patch or two. Thoughts?
>
>
> With the above changes, please feel free to add :
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose@arm.com>
>
>

^ permalink raw reply

* [RFC PATCH v2 05/10] genirq: export irq_get_percpu_devid_partition to modules
From: Marc Zyngier @ 2017-01-13 19:04 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484323429-15231-6-git-send-email-will.deacon@arm.com>

On 13/01/17 16:03, Will Deacon wrote:
> Any modular driver using cluster-affine PPIs needs to be able to call
> irq_get_percpu_devid_partition so that it can enable the IRQ on the
> correct subset of CPUs.
> 
> This patch exports the symbol so that it can be called from within a
> module.
> 
> Cc: Marc Zyngier <marc.zyngier@arm.com>
> Cc: Thomas Gleixner <tglx@linutronix.de>
> Signed-off-by: Will Deacon <will.deacon@arm.com>
> ---
>  kernel/irq/irqdesc.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
> index 00bb0aeea1d0..1e6ae73eae59 100644
> --- a/kernel/irq/irqdesc.c
> +++ b/kernel/irq/irqdesc.c
> @@ -856,6 +856,7 @@ int irq_get_percpu_devid_partition(unsigned int irq, struct cpumask *affinity)
>  
>  	return 0;
>  }
> +EXPORT_SYMBOL_GPL(irq_get_percpu_devid_partition);
>  
>  void kstat_incr_irq_this_cpu(unsigned int irq)
>  {
> 

Acked-by: Marc Zyngier <marc.zyngier@arm.com>

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply

* [PATCH v4 4/4] ARM: dts: Add LEGO MINDSTORMS EV3 dts
From: David Lechner @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484334222-14223-1-git-send-email-david@lechnology.com>

This adds a device tree definition file for LEGO MINDSTORMS EV3.

What is working:

* Pin muxing
* Pinconf
* GPIOs
* MicroSD card reader
* UART on input port 1
* Buttons
* LEDs
* Poweroff/reset
* Flash memory
* EEPROM
* USB host port
* USB peripheral port

What is not working/to be added later:

* Speaker - have patch submitted to get pwm-beeper working - maybe someday
  it will have a real sound driver that uses PRU
* A/DC chip - have driver submitted and accepted - waiting for ack on
  device tree bindings
* Display - waiting for "simple DRM" to be mainlined
* Bluetooth - needs new driver for sequencing power/enable/clock
* Input and output ports - need some sort of new phy or extcon driver as
  well as PRU UART and PRU I2C drivers
* Battery indication - needs new power supply driver

Note on flash partitions:

These partitions are based on the official EV3 firmware from LEGO. It is
expected that most users of the mainline kernel on EV3 will be booting from
an SD card while retaining the official firmware in the flash memory.
Furthermore, the official firmware uses an ancient U-Boot (2009) that has
no device tree support. So, it makes sense to have this partition table in
the EV3 device tree file. In the unlikely case that anyone does create
their own firmware image with different partitioning, they can use a modern
U-Boot in their own firmware image that modifies the device tree with the
custom partitions.

Signed-off-by: David Lechner <david@lechnology.com>
---
 arch/arm/boot/dts/Makefile           |   3 +-
 arch/arm/boot/dts/da850-lego-ev3.dts | 313 +++++++++++++++++++++++++++++++++++
 2 files changed, 315 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/da850-lego-ev3.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 78a94b7..1a19e7a 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -130,7 +130,8 @@ dtb-$(CONFIG_ARCH_CLPS711X) += \
 dtb-$(CONFIG_ARCH_DAVINCI) += \
 	da850-lcdk.dtb \
 	da850-enbw-cmc.dtb \
-	da850-evm.dtb
+	da850-evm.dtb \
+	da850-lego-ev3.dtb
 dtb-$(CONFIG_ARCH_DIGICOLOR) += \
 	cx92755_equinox.dtb
 dtb-$(CONFIG_ARCH_EFM32) += \
diff --git a/arch/arm/boot/dts/da850-lego-ev3.dts b/arch/arm/boot/dts/da850-lego-ev3.dts
new file mode 100644
index 0000000..112ec92
--- /dev/null
+++ b/arch/arm/boot/dts/da850-lego-ev3.dts
@@ -0,0 +1,313 @@
+/*
+ * Device tree for LEGO MINDSTORMS EV3
+ *
+ * Copyright (C) 2017 David Lechner <david@lechnology.com>
+ *
+ * This program 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, version 2.
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/linux-event-codes.h>
+#include <dt-bindings/pwm/pwm.h>
+
+#include "da850.dtsi"
+
+/ {
+	compatible = "lego,ev3", "ti,da850";
+	model = "LEGO MINDSTORMS EV3";
+
+	aliases {
+		serial1 = &serial1;
+	};
+
+	memory at c0000000 {
+		device_type = "memory";
+		reg = <0xc0000000 0x04000000>;
+	};
+
+	/*
+	 * The buttons on the EV3 are mapped to keyboard keys.
+	 */
+	gpio_keys {
+		compatible = "gpio-keys";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		label = "EV3 Brick Buttons";
+		pinctrl-names = "default";
+		pinctrl-0 = <&button_pins>, <&button_bias>;
+
+		center {
+			label = "Center";
+			linux,code = <KEY_ENTER>;
+			gpios = <&gpio 29 GPIO_ACTIVE_HIGH>;
+		};
+
+		left {
+			label = "Left";
+			linux,code = <KEY_LEFT>;
+			gpios = <&gpio 102 GPIO_ACTIVE_HIGH>;
+		};
+
+		back {
+			label = "Back";
+			linux,code = <KEY_BACKSPACE>;
+			gpios = <&gpio 106 GPIO_ACTIVE_HIGH>;
+		};
+
+		right {
+			label = "Right";
+			linux,code = <KEY_RIGHT>;
+			gpios = <&gpio 124 GPIO_ACTIVE_HIGH>;
+		};
+
+		down {
+			label = "Down";
+			linux,code = <KEY_DOWN>;
+			gpios = <&gpio 126 GPIO_ACTIVE_HIGH>;
+		};
+
+		up {
+			label = "Up";
+			linux,code = <KEY_UP>;
+			gpios = <&gpio 127 GPIO_ACTIVE_HIGH>;
+		};
+	};
+
+	/*
+	 * The EV3 has two built-in bi-color LEDs behind the buttons.
+	 */
+	leds {
+		compatible = "gpio-leds";
+		pinctrl-names = "default";
+		pinctrl-0 = <&led_pins>;
+
+		left_green {
+			label = "led0:green:brick-status";
+			/* GP6[13] */
+			gpios = <&gpio 103 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		right_red {
+			label = "led1:red:brick-status";
+			/* GP6[7] */
+			gpios = <&gpio 108 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		left_red {
+			label = "led0:red:brick-status";
+			/* GP6[12] */
+			gpios = <&gpio 109 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+
+		right_green {
+			label = "led1:green:brick-status";
+			/* GP6[14] */
+			gpios = <&gpio 110 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "default-on";
+		};
+	};
+
+	/*
+	 * The EV3 is powered down by turning off the main 5V supply.
+	 */
+	gpio-poweroff {
+		compatible = "gpio-poweroff";
+		gpios = <&gpio 107 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&system_power_pin>;
+	};
+
+	/*
+	 * This is a 5V current limiting regulator that is shared by USB,
+	 * the sensor (input) ports, the motor (output) ports and the A/DC.
+	 */
+	vcc5v: regulator1 {
+		pinctrl-names = "default";
+		pinctrl-0 = <&vcc5v_pins>;
+		compatible = "regulator-fixed";
+		regulator-name = "vcc5v";
+		regulator-min-microvolt = <5000000>;
+		regulator-max-microvolt = <5000000>;
+		gpio = <&gpio 101 0>;
+		over-current-gpios = <&gpio 99 GPIO_ACTIVE_LOW>;
+		enable-active-high;
+		regulator-boot-on;
+	};
+};
+
+&pmx_core {
+	status = "okay";
+
+	spi0_cs3_pin: pinmux_spi0_cs3_pin {
+		pinctrl-single,bits = <
+			/* CS3 */
+			0xc 0x01000000 0x0f000000
+		>;
+	};
+
+	mmc0_cd_pin: pinmux_mmc0_cd {
+		pinctrl-single,bits = <
+			/* GP5[14] */
+			0x2C 0x00000080 0x000000f0
+		>;
+	};
+
+	button_pins: pinmux_button_pins {
+		pinctrl-single,bits = <
+			/* GP1[13] */
+			0x8 0x00000800 0x00000f00
+			/* GP6[10] */
+			0x34 0x00800000 0x00f00000
+			/* GP6[6] */
+			0x38 0x00000080 0x000000f0
+			/* GP7[12], GP7[14], GP7[15] */
+			0x40 0x00808800 0x00f0ff00
+		>;
+	};
+
+	led_pins: pinmux_led_pins {
+		pinctrl-single,bits = <
+			/* GP6[12], GP6[13], GP6[14] */
+			0x34 0x00008880 0x0000fff0
+			/* GP6[7] */
+			0x38 0x00000008 0x0000000f
+		>;
+	};
+
+	system_power_pin: pinmux_system_power {
+		pinctrl-single,bits = <
+			/* GP6[11] */
+			0x34 0x00080000 0x000f0000
+		>;
+	};
+
+	vcc5v_pins: pinmux_vcc5v {
+		pinctrl-single,bits = <
+			/* GP6[5] */
+			0x40 0x00000080 0x000000f0
+			/* GP6[3] */
+			0x4c 0x00008000 0x0000f000
+		>;
+	};
+};
+
+&pinconf {
+	status = "okay";
+
+	/* Buttons have external pulldown resistors */
+	button_bias: button-bias-groups {
+		disable {
+			groups = "cp5", "cp24", "cp25", "cp28";
+			bias-disable;
+		};
+	};
+};
+
+/* Input port 1 */
+&serial1 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&serial1_rxtx_pins>;
+};
+
+&rtc0 {
+	status = "okay";
+};
+
+&i2c0 {
+	status = "okay";
+	clock-frequency = <400000>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&i2c0_pins>;
+
+	/*
+	 * EEPROM contains the first stage bootloader, HW ID and Bluetooth MAC.
+	 */
+	eeprom at 50 {
+		compatible = "microchip,24c128";
+		pagesize = <64>;
+		read-only;
+		reg = <0x50>;
+	};
+};
+
+&wdt {
+	status = "okay";
+};
+
+&mmc0 {
+	status = "okay";
+	max-frequency = <50000000>;
+	bus-width = <4>;
+	cd-gpios = <&gpio 94 GPIO_ACTIVE_LOW>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&mmc0_pins>, <&mmc0_cd_pin>;
+};
+
+&spi0 {
+	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&spi0_pins>, <&spi0_cs0_pin>, <&spi0_cs3_pin>;
+
+	flash at 0 {
+		compatible = "n25q128a13", "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <50000000>;
+		ti,spi-wdelay = <8>;
+
+		/* Partitions are based on the official firmware from LEGO */
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			partition at 0 {
+				label = "U-Boot";
+				reg = <0 0x40000>;
+			};
+
+			partition at 40000 {
+				label = "U-Boot Env";
+				reg = <0x40000 0x10000>;
+			};
+
+			partition at 50000 {
+				label = "Kernel";
+				reg = <0x50000 0x200000>;
+			};
+
+			partition at 250000 {
+				label = "Filesystem";
+				reg = <0x250000 0xa50000>;
+			};
+
+			partition at cb0000 {
+				label = "Storage";
+				reg = <0xcb0000 0x2f0000>;
+			};
+		};
+	};
+};
+
+&gpio {
+	status = "okay";
+};
+
+&usb_phy {
+	status = "okay";
+};
+
+&usb0 {
+	status = "okay";
+};
+
+&usb1 {
+	status = "okay";
+	vbus-supply = <&vcc5v>;
+};
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 3/4] dt-bindings: add "microchip,24c128" compatible string
From: David Lechner @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484334222-14223-1-git-send-email-david@lechnology.com>

This adds "microchip,24c128" to the list of compatible strings for i2c
eeproms.

Signed-off-by: David Lechner <david@lechnology.com>
---
 Documentation/devicetree/bindings/eeprom/eeprom.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/eeprom/eeprom.txt b/Documentation/devicetree/bindings/eeprom/eeprom.txt
index 735bc94..5696eb5 100644
--- a/Documentation/devicetree/bindings/eeprom/eeprom.txt
+++ b/Documentation/devicetree/bindings/eeprom/eeprom.txt
@@ -10,6 +10,8 @@ Required properties:
 
 	"catalyst,24c32"
 
+	"microchip,24c128"
+
 	"ramtron,24c64"
 
 	"renesas,r1ex24002"
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 2/4] dt-bindings: Add LEGO MINDSTORMS EV3 compatible specification
From: David Lechner @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484334222-14223-1-git-send-email-david@lechnology.com>

This adds the board level device tree specification for LEGO MINDSTORMS EV3

Signed-off-by: David Lechner <david@lechnology.com>
---
 Documentation/devicetree/bindings/arm/davinci.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/davinci.txt b/Documentation/devicetree/bindings/arm/davinci.txt
index f0841ce..715622c 100644
--- a/Documentation/devicetree/bindings/arm/davinci.txt
+++ b/Documentation/devicetree/bindings/arm/davinci.txt
@@ -13,6 +13,10 @@ EnBW AM1808 based CMC board
 Required root node properties:
     - compatible = "enbw,cmc", "ti,da850;
 
+LEGO MINDSTORMS EV3 (AM1808 based)
+Required root node properties:
+    - compatible = "lego,ev3", "ti,da850";
+
 Generic DaVinci Boards
 ----------------------
 
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 1/4] dt-bindings: Add vendor prefix for LEGO
From: David Lechner @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484334222-14223-1-git-send-email-david@lechnology.com>

Add a vendor prefix for LEGO Systems A/S

Signed-off-by: David Lechner <david@lechnology.com>
---
 Documentation/devicetree/bindings/vendor-prefixes.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 61cb272..c1ccfd4 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -159,6 +159,7 @@ kosagi	Sutajio Ko-Usagi PTE Ltd.
 kyo	Kyocera Corporation
 lacie	LaCie
 lantiq	Lantiq Semiconductor
+lego	LEGO Systems A/S
 lenovo	Lenovo Group Ltd.
 lg	LG Corporation
 licheepi	Lichee Pi
-- 
2.7.4

^ permalink raw reply related

* [PATCH v4 0/4] Support for LEGO MINDSTORMS EV3
From: David Lechner @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series adds support for LEGO MINDSTORMS EV3. This is a TI AM1808
based board.

v4 changes:
* New patches for device tree bindings specifications
* Fixed vendor on eeprom device node

v3 changes:
* required defconfig patches have been picked up in linux-davinci tree, so this
  is the only patch left in the series
* Added aliases node for consistent naming of serial ports
* Added memory node
* Removed nodes that are not finalized yet
* Renamed button labels to match EV3 users manual

v2 changes:
* Dropped defconfig patches that have already been pick up
* Added some new defconfig patches
* Updated device tree file based on feedback and new available bindings
  * Renamed file to include da850- prefix
  * Changed button labels
  * Fixed LED names
  * Added beeper device for sound
  * Added regulators for USB and A/DC
  * Removed unused pinmux nodes
  * Added pinconf for buttons
  * Enabled pwms
  * Used preferred bindings for flash partitions
  * Added A/DC spi device
  * Enabled USB


David Lechner (4):
  dt-bindings: Add vendor prefix for LEGO
  dt-bindings: Add LEGO MINDSTORMS EV3 compatible specification
  dt-bindings: add "microchip,24c128" compatible string
  ARM: dts: Add LEGO MINDSTORMS EV3 dts

 Documentation/devicetree/bindings/arm/davinci.txt  |   4 +
 .../devicetree/bindings/eeprom/eeprom.txt          |   2 +
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 arch/arm/boot/dts/Makefile                         |   3 +-
 arch/arm/boot/dts/da850-lego-ev3.dts               | 313 +++++++++++++++++++++
 5 files changed, 322 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/da850-lego-ev3.dts

-- 
2.7.4

^ permalink raw reply

* [PATCH v3 01/24] [media] dt-bindings: Add bindings for i.MX media driver
From: Steve Longerbeam @ 2017-01-13 19:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484308551.31475.23.camel@pengutronix.de>



On 01/13/2017 03:55 AM, Philipp Zabel wrote:
> Am Freitag, den 06.01.2017, 18:11 -0800 schrieb Steve Longerbeam:
>> Add bindings documentation for the i.MX media driver.
>>
>> Signed-off-by: Steve Longerbeam <steve_longerbeam@mentor.com>
>> ---
>>   Documentation/devicetree/bindings/media/imx.txt | 57 +++++++++++++++++++++++++
>>   1 file changed, 57 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/media/imx.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/imx.txt b/Documentation/devicetree/bindings/media/imx.txt
>> new file mode 100644
>> index 0000000..254b64a
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/imx.txt
>> @@ -0,0 +1,57 @@
>> +Freescale i.MX Media Video Devices
>> +
>> +Video Media Controller node
>> +---------------------------
>> +
>> +This is the parent media controller node for video capture support.
>> +
>> +Required properties:
>> +- compatible : "fsl,imx-media";
> Would you be opposed to calling this "capture-subsystem" instead of
> "imx-media"? We already use "fsl,imx-display-subsystem" and
> "fsl,imx-gpu-subsystem" for the display and GPU compound devices.

sure. Some pie-in-the-sky day when DRM and media are unified,
there could be a single device that handles them all, but for now
I'm fine with "fsl,capture-subsystem".

>> +- ports      : Should contain a list of phandles pointing to camera
>> +  	       sensor interface ports of IPU devices
>> +
>> +
>> +fim child node
>> +--------------
>> +
>> +This is an optional child node of the ipu_csi port nodes. If present and
>> +available, it enables the Frame Interval Monitor. Its properties can be
>> +used to modify the method in which the FIM measures frame intervals.
>> +Refer to Documentation/media/v4l-drivers/imx.rst for more info on the
>> +Frame Interval Monitor.
>> +
>> +Optional properties:
>> +- fsl,input-capture-channel: an input capture channel and channel flags,
>> +			     specified as <chan flags>. The channel number
>> +			     must be 0 or 1. The flags can be
>> +			     IRQ_TYPE_EDGE_RISING, IRQ_TYPE_EDGE_FALLING, or
>> +			     IRQ_TYPE_EDGE_BOTH, and specify which input
>> +			     capture signal edge will trigger the input
>> +			     capture event. If an input capture channel is
>> +			     specified, the FIM will use this method to
>> +			     measure frame intervals instead of via the EOF
>> +			     interrupt. The input capture method is much
>> +			     preferred over EOF as it is not subject to
>> +			     interrupt latency errors. However it requires
>> +			     routing the VSYNC or FIELD output signals of
>> +			     the camera sensor to one of the i.MX input
>> +			     capture pads (SD1_DAT0, SD1_DAT1), which also
>> +			     gives up support for SD1.
> This is a clever method to get better frame timestamps. Too bad about
> the routing requirements. Can this be used on Nitrogen6X?

Absolutely, this support just needs use of the input-capture channels in the
imx GPT. I still need to submit the patch to the imx-gpt driver that adds an
input capture API, so at this point fsl,input-capture-channel has no effect,
but it does work (tested on SabreAuto).

>
>> +
>> +mipi_csi2 node
>> +--------------
>> +
>> +This is the device node for the MIPI CSI-2 Receiver, required for MIPI
>> +CSI-2 sensors.
>> +
>> +Required properties:
>> +- compatible	: "fsl,imx6-mipi-csi2";
> I think this should get an additional "snps,dw-mipi-csi2" compatible,
> since the only i.MX6 specific part is the bolted-on IPU2CSI gasket.

right, minus the gasket it's a Synopsys core. I'll add that compatible flag.
Or should wait until the day this subdev is exported for general use, after
pulling out the gasket specifics?


>
>> +- reg           : physical base address and length of the register set;
>> +- clocks	: the MIPI CSI-2 receiver requires three clocks: hsi_tx
>> +                  (the DPHY clock), video_27m, and eim_sel;
> Note that hsi_tx is incorrectly named. CCGR3[CG8] just happens to be the
> shared gate bit that gates the HSI clocks as well as the MIPI
> "ac_clk_125m", "cfg_clk", "ips_clk", and "pll_refclk" inputs to the mipi
> csi-2 core, but we are missing shared gate clocks in the clock tree for
> these.

Yes, so many clocks for the MIPI core. Why so many? I would think
there would need to be at most three: a clock for the MIPI CSI-2 core
and HSI core, and a clock for the D-PHY (oh and maybe a clock for an
M-PHY if there is one). I have no clue what all these other clocks are.
But anyway, a single gating bit, CCGR3[CG8], seems to enable them all.

> Both cfg_clk and pll_refclk are sourced from video_27m, so "cfg" ->
> video_27m seems fine.
> But I don't get "dphy".

I presume it's the clock for the D-PHY.

>   Which input clock would that correspond to?
> "pll_refclk?"

the mux at CDCDR says it comes from PLL3_120M, or PLL2_PFD2.


> Also the pixel clock input is a gate after aclk_podf (which we call
> eim_podf), not aclk_sel (eim_sel).

ok, I'll switch to eim_podf for the pixel clock.

Steve

>
>> +- clock-names	: must contain "dphy", "cfg", "pix";
>> +
>> +Optional properties:
>> +- interrupts	: must contain two level-triggered interrupts,
>> +                  in order: 100 and 101;
> regards
> Philipp
>

^ permalink raw reply

* [PATCH 2/4] clk: rockchip: use rk3288 isp_in clock ids
From: Heiko Stuebner @ 2017-01-13 18:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1484049560-14820-2-git-send-email-jacob-chen@iotwrt.com>

Am Dienstag, 10. Januar 2017, 19:59:18 CET schrieb Jacob Chen:
> Reference the newly added isp clock-ids in the clock-tree.
> 
> 
> Signed-off-by: Jacob Chen <jacob-chen@iotwrt.com>

applied for 4.11

Thanks
Heiko

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox