Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/4] Documentation: devicetree: Add vendor prefix for AsiaRF
From: Andreas Färber @ 2017-01-08 13:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170108133100.10428-1-afaerber@suse.de>

Signed-off-by: Andreas F?rber <afaerber@suse.de>
---
 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 4ec84b7..01d222b 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -34,6 +34,7 @@ armadeus	ARMadeus Systems SARL
 arrow	Arrow Electronics
 artesyn	Artesyn Embedded Technologies Inc.
 asahi-kasei	Asahi Kasei Corp.
+asiarf	AsiaRF Co., Ltd.
 aspeed	ASPEED Technology Inc.
 atlas	Atlas Scientific LLC
 atmel	Atmel Corporation
-- 
2.10.2

^ permalink raw reply related

* [PATCH 0/4] ARM: dts: mt7623: Add initial Geek Force support
From: Andreas Färber @ 2017-01-08 13:30 UTC (permalink / raw)
  To: linux-arm-kernel


Andreas F?rber (4):
  Documentation: devicetree: Add vendor prefix for AsiaRF
  Documentation: devicetree: arm: mediatek: Add Geek Force board
  ARM: dts: mt7623: Add Geek Force config
  MAINTAINERS: Extend ARM/Mediatek SoC support section

 Documentation/devicetree/bindings/arm/mediatek.txt |  3 +
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 MAINTAINERS                                        |  2 +
 arch/arm/boot/dts/Makefile                         |  1 +
 arch/arm/boot/dts/mt7623-geekforce.dts             | 77 ++++++++++++++++++++++
 5 files changed, 84 insertions(+)
 create mode 100644 arch/arm/boot/dts/mt7623-geekforce.dts

-- 
2.10.2

^ permalink raw reply

* mmc: sdhci-of-at91: Internal clock never stabilised
From: Alexandre Belloni @ 2017-01-08 12:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAJP5LRNRSpMjdTFyL4R4ZN1tZAG0A=TKR5LRareg+TEJmnkd2Q@mail.gmail.com>

Hi,

I think Cyrille worked on that a few month ago, maybe he has a comment.

On 08/01/2017 at 14:07:53 +0200, Alex Gershgorin wrote :
> Hi All,
> We have two different HW platforms based on SAMA5D2 SoC (SAMA5D2 Xplained
> Board and our own HW).
> On both of them we are facing stabilization of the internal
> clock problem, it does not happen all the time but quite often.
> Please see below my Kernel boot messages:
> 
> sdhci: Copyright(c) Pierre Ossman
> sdhci-pltfm: SDHCI platform and OF driver helper
> sdhci-at91 a0000000.sdio-host: update clk mul to 39 as gck rate is
> 480000000 Hz
> mmc0: Internal clock never stabilised.
> mmc0: Internal clock never stabilised.
> mmc0: SDHCI controller on a0000000.sdio-host [a0000000.sdio-host] using ADMA
> 
> snip
> 
> snip
> 
> Waiting for root device /dev/mmcblk0p2...
> mmc0: Internal clock never stabilised.
> mmc0: Timeout waiting for hardware cmd interrupt.
> sdhci: =========== REGISTER DUMP (mmc0)===========
> sdhci: Sys addr: 0x00000000 | Version:  0x00001502
> sdhci: Blk size: 0x00000000 | Blk cnt:  0x00000000
> sdhci: Argument: 0x00000000 | Trn mode: 0x00000000
> sdhci: Present: 0x01ff0001 | Host ctl: 0x00000001
> sdhci: Power: 0x0000000f | Blk gap:  0x00000000
> sdhci: Wake-up: 0x00000000 | Clock:    0x0000ffe1
> sdhci: Timeout: 0x00000000 | Int stat: 0x00000000
> sdhci: Int enab: 0x00ff0003 | Sig enab: 0x00ff0003
> sdhci: AC12 err: 0x00000000 | Slot int: 0x00000000
> sdhci: Caps: 0x27ec0c8c | Caps_1: 0x00270f77
> sdhci: Cmd: 0x00000000 | Max curr: 0x00000000
> sdhci: Host ctl2: 0x00000000
> sdhci: ADMA Err: 0x00000000 | ADMA Ptr: 0x00000000
> sdhci: ===========================================
> 
> Any direction to solve this problem?
> 
> Thanks,
> Alex Gershgorin

-- 
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH v7 6/8] IIO: add STM32 timer trigger driver
From: Jonathan Cameron @ 2017-01-08 11:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483608344-9012-7-git-send-email-benjamin.gaignard@st.com>

On 05/01/17 09:25, Benjamin Gaignard wrote:
> Timers IPs can be used to generate triggers for other IPs like
> DAC or ADC.
> Each trigger may result of timer internals signals like counter enable,
> reset or edge, this configuration could be done through "master_mode"
> device attribute.
> 
> Since triggers could be used by DAC or ADC their names are defined
> in include/ nux/iio/timer/stm32-timer-trigger.h and is_stm32_iio_timer_trigger
> function could be used to check if the trigger is valid or not.
> 
> "trgo" trigger have a "sampling_frequency" attribute which allow to configure
> timer sampling frequency.
> 
> version 7:
> - remove all iio_device related code
> - move driver into trigger directory
> 
> version 5:
> - simplify tables of triggers
> - only create an IIO device when needed
> 
> version 4:
> - get triggers configuration from "reg" in DT
> - add tables of triggers
> - sampling frequency is enable/disable when writing in trigger
>   sampling_frequency attribute
> - no more use of interruptions
> 
> version 3:
> - change compatible to "st,stm32-timer-trigger"
> - fix attributes access right
> - use string instead of int for master_mode and slave_mode
> - document device attributes in sysfs-bus-iio-timer-stm32
> 
> version 2:
> - keep only one compatible
> - use st,input-triggers-names and st,output-triggers-names
>   to know which triggers are accepted and/or create by the device
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
One line snuck in that shouldn't be there (the one in iio/Kconfig).
Other than that

Acked-by: Jonathan Cameron <jic23@kernel.org>

I didn't get a chance to look at doing trigger trees unfortunately.
Not sure when I'll next get a window to work on new stuff.

Thanks,

Jonathan

> ---
>  .../ABI/testing/sysfs-bus-iio-timer-stm32          |  29 ++
>  drivers/iio/Kconfig                                |   1 -
>  drivers/iio/trigger/Kconfig                        |  10 +
>  drivers/iio/trigger/Makefile                       |   1 +
>  drivers/iio/trigger/stm32-timer-trigger.c          | 340 +++++++++++++++++++++
>  include/linux/iio/timer/stm32-timer-trigger.h      |  62 ++++
>  6 files changed, 442 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
>  create mode 100644 drivers/iio/trigger/stm32-timer-trigger.c
>  create mode 100644 include/linux/iio/timer/stm32-timer-trigger.h
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
> new file mode 100644
> index 0000000..a7f5177
> --- /dev/null
> +++ b/Documentation/ABI/testing/sysfs-bus-iio-timer-stm32
> @@ -0,0 +1,29 @@
> +What:		/sys/bus/iio/devices/triggerX/master_mode_available
> +KernelVersion:	4.10
> +Contact:	benjamin.gaignard at st.com
> +Description:
> +		Reading returns the list possible master modes which are:
> +		- "reset"     :	The UG bit from the TIMx_EGR register is used as trigger output (TRGO).
> +		- "enable"    : The Counter Enable signal CNT_EN is used as trigger output.
> +		- "update"    : The update event is selected as trigger output.
> +				For instance a master timer can then be used as a prescaler for a slave timer.
> +		- "compare_pulse" : The trigger output send a positive pulse when the CC1IF flag is to be set.
> +		- "OC1REF"    : OC1REF signal is used as trigger output.
> +		- "OC2REF"    : OC2REF signal is used as trigger output.
> +		- "OC3REF"    : OC3REF signal is used as trigger output.
> +		- "OC4REF"    : OC4REF signal is used as trigger output.
> +
> +What:		/sys/bus/iio/devices/triggerX/master_mode
> +KernelVersion:	4.10
> +Contact:	benjamin.gaignard at st.com
> +Description:
> +		Reading returns the current master modes.
> +		Writing set the master mode
> +
> +What:		/sys/bus/iio/devices/triggerX/sampling_frequency
> +KernelVersion:	4.10
> +Contact:	benjamin.gaignard at st.com
> +Description:
> +		Reading returns the current sampling frequency.
> +		Writing an value different of 0 set and start sampling.
> +		Writing 0 stop sampling.
> diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
> index a918270..6b0c427 100644
> --- a/drivers/iio/Kconfig
> +++ b/drivers/iio/Kconfig
> @@ -92,5 +92,4 @@ source "drivers/iio/potentiostat/Kconfig"
>  source "drivers/iio/pressure/Kconfig"
>  source "drivers/iio/proximity/Kconfig"
>  source "drivers/iio/temperature/Kconfig"
> -
Please fix this!!
>  endif # IIO
> diff --git a/drivers/iio/trigger/Kconfig b/drivers/iio/trigger/Kconfig
> index 809b2e7..72d3a32 100644
> --- a/drivers/iio/trigger/Kconfig
> +++ b/drivers/iio/trigger/Kconfig
> @@ -24,6 +24,16 @@ config IIO_INTERRUPT_TRIGGER
>  	  To compile this driver as a module, choose M here: the
>  	  module will be called iio-trig-interrupt.
>  
> +config IIO_STM32_TIMER_TRIGGER
> +	tristate "STM32 Timer Trigger"
> +	depends on (ARCH_STM32 && OF && MFD_STM32_TIMERS) || COMPILE_TEST
> +	help
> +	  Select this option to enable STM32 Timer Trigger
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called stm32-timer-trigger.
> +
> +
>  config IIO_TIGHTLOOP_TRIGGER
>  	tristate "A kthread based hammering loop trigger"
>  	depends on IIO_SW_TRIGGER
> diff --git a/drivers/iio/trigger/Makefile b/drivers/iio/trigger/Makefile
> index aab4dc2..5c4ecd3 100644
> --- a/drivers/iio/trigger/Makefile
> +++ b/drivers/iio/trigger/Makefile
> @@ -6,5 +6,6 @@
>  
>  obj-$(CONFIG_IIO_HRTIMER_TRIGGER) += iio-trig-hrtimer.o
>  obj-$(CONFIG_IIO_INTERRUPT_TRIGGER) += iio-trig-interrupt.o
> +obj-$(CONFIG_IIO_STM32_TIMER_TRIGGER) += stm32-timer-trigger.o
>  obj-$(CONFIG_IIO_SYSFS_TRIGGER) += iio-trig-sysfs.o
>  obj-$(CONFIG_IIO_TIGHTLOOP_TRIGGER) += iio-trig-loop.o
> diff --git a/drivers/iio/trigger/stm32-timer-trigger.c b/drivers/iio/trigger/stm32-timer-trigger.c
> new file mode 100644
> index 0000000..409fb0c
> --- /dev/null
> +++ b/drivers/iio/trigger/stm32-timer-trigger.c
> @@ -0,0 +1,340 @@
> +/*
> + * Copyright (C) STMicroelectronics 2016
> + *
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
> + *
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/iio/iio.h>
> +#include <linux/iio/sysfs.h>
> +#include <linux/iio/timer/stm32-timer-trigger.h>
> +#include <linux/iio/trigger.h>
> +#include <linux/mfd/stm32-timers.h>
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +
> +#define MAX_TRIGGERS 6
> +
> +/* List the triggers created by each timer */
> +static const void *triggers_table[][MAX_TRIGGERS] = {
> +	{ TIM1_TRGO, TIM1_CH1, TIM1_CH2, TIM1_CH3, TIM1_CH4,},
> +	{ TIM2_TRGO, TIM2_CH1, TIM2_CH2, TIM2_CH3, TIM2_CH4,},
> +	{ TIM3_TRGO, TIM3_CH1, TIM3_CH2, TIM3_CH3, TIM3_CH4,},
> +	{ TIM4_TRGO, TIM4_CH1, TIM4_CH2, TIM4_CH3, TIM4_CH4,},
> +	{ TIM5_TRGO, TIM5_CH1, TIM5_CH2, TIM5_CH3, TIM5_CH4,},
> +	{ TIM6_TRGO,},
> +	{ TIM7_TRGO,},
> +	{ TIM8_TRGO, TIM8_CH1, TIM8_CH2, TIM8_CH3, TIM8_CH4,},
> +	{ TIM9_TRGO, TIM9_CH1, TIM9_CH2,},
> +	{ TIM12_TRGO, TIM12_CH1, TIM12_CH2,},
> +};
> +
> +struct stm32_timer_trigger {
> +	struct device *dev;
> +	struct regmap *regmap;
> +	struct clk *clk;
> +	u32 max_arr;
> +	const void *triggers;
> +};
> +
> +static int stm32_timer_start(struct stm32_timer_trigger *priv,
> +			     unsigned int frequency)
> +{
> +	unsigned long long prd, div;
> +	int prescaler = 0;
> +	u32 ccer, cr1;
> +
> +	/* Period and prescaler values depends of clock rate */
> +	div = (unsigned long long)clk_get_rate(priv->clk);
> +
> +	do_div(div, frequency);
> +
> +	prd = div;
> +
> +	/*
> +	 * Increase prescaler value until we get a result that fit
> +	 * with auto reload register maximum value.
> +	 */
> +	while (div > priv->max_arr) {
> +		prescaler++;
> +		div = prd;
> +		do_div(div, (prescaler + 1));
> +	}
> +	prd = div;
> +
> +	if (prescaler > MAX_TIM_PSC) {
> +		dev_err(priv->dev, "prescaler exceeds the maximum value\n");
> +		return -EINVAL;
> +	}
> +
> +	/* Check if nobody else use the timer */
> +	regmap_read(priv->regmap, TIM_CCER, &ccer);
> +	if (ccer & TIM_CCER_CCXE)
> +		return -EBUSY;
> +
> +	regmap_read(priv->regmap, TIM_CR1, &cr1);
> +	if (!(cr1 & TIM_CR1_CEN))
> +		clk_enable(priv->clk);
> +
> +	regmap_write(priv->regmap, TIM_PSC, prescaler);
> +	regmap_write(priv->regmap, TIM_ARR, prd - 1);
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_ARPE, TIM_CR1_ARPE);
> +
> +	/* Force master mode to update mode */
> +	regmap_update_bits(priv->regmap, TIM_CR2, TIM_CR2_MMS, 0x20);
> +
> +	/* Make sure that registers are updated */
> +	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> +
> +	/* Enable controller */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, TIM_CR1_CEN);
> +
> +	return 0;
> +}
> +
> +static void stm32_timer_stop(struct stm32_timer_trigger *priv)
> +{
> +	u32 ccer, cr1;
> +
> +	regmap_read(priv->regmap, TIM_CCER, &ccer);
> +	if (ccer & TIM_CCER_CCXE)
> +		return;
> +
> +	regmap_read(priv->regmap, TIM_CR1, &cr1);
> +	if (cr1 & TIM_CR1_CEN)
> +		clk_disable(priv->clk);
> +
> +	/* Stop timer */
> +	regmap_update_bits(priv->regmap, TIM_CR1, TIM_CR1_CEN, 0);
> +	regmap_write(priv->regmap, TIM_PSC, 0);
> +	regmap_write(priv->regmap, TIM_ARR, 0);
> +
> +	/* Make sure that registers are updated */
> +	regmap_update_bits(priv->regmap, TIM_EGR, TIM_EGR_UG, TIM_EGR_UG);
> +}
> +
> +static ssize_t stm32_tt_store_frequency(struct device *dev,
> +					struct device_attribute *attr,
> +					const char *buf, size_t len)
> +{
> +	struct iio_trigger *trig = to_iio_trigger(dev);
> +	struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig);
> +	unsigned int freq;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 10, &freq);
> +	if (ret)
> +		return ret;
> +
> +	if (freq == 0) {
> +		stm32_timer_stop(priv);
> +	} else {
> +		ret = stm32_timer_start(priv, freq);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return len;
> +}
> +
> +static ssize_t stm32_tt_read_frequency(struct device *dev,
> +				       struct device_attribute *attr, char *buf)
> +{
> +	struct iio_trigger *trig = to_iio_trigger(dev);
> +	struct stm32_timer_trigger *priv = iio_trigger_get_drvdata(trig);
> +	u32 psc, arr, cr1;
> +	unsigned long long freq = 0;
> +
> +	regmap_read(priv->regmap, TIM_CR1, &cr1);
> +	regmap_read(priv->regmap, TIM_PSC, &psc);
> +	regmap_read(priv->regmap, TIM_ARR, &arr);
> +
> +	if (psc && arr && (cr1 & TIM_CR1_CEN)) {
> +		freq = (unsigned long long)clk_get_rate(priv->clk);
> +		do_div(freq, psc);
> +		do_div(freq, arr);
> +	}
> +
> +	return sprintf(buf, "%d\n", (unsigned int)freq);
> +}
> +
> +static IIO_DEV_ATTR_SAMP_FREQ(0660,
> +			      stm32_tt_read_frequency,
> +			      stm32_tt_store_frequency);
> +
> +static char *master_mode_table[] = {
> +	"reset",
> +	"enable",
> +	"update",
> +	"compare_pulse",
> +	"OC1REF",
> +	"OC2REF",
> +	"OC3REF",
> +	"OC4REF"
> +};
> +
> +static ssize_t stm32_tt_show_master_mode(struct device *dev,
> +					 struct device_attribute *attr,
> +					 char *buf)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
> +	u32 cr2;
> +
> +	regmap_read(priv->regmap, TIM_CR2, &cr2);
> +	cr2 = (cr2 & TIM_CR2_MMS) >> TIM_CR2_MMS_SHIFT;
> +
> +	return snprintf(buf, PAGE_SIZE, "%s\n", master_mode_table[cr2]);
> +}
> +
> +static ssize_t stm32_tt_store_master_mode(struct device *dev,
> +					  struct device_attribute *attr,
> +					  const char *buf, size_t len)
> +{
> +	struct iio_dev *indio_dev = dev_to_iio_dev(dev);
> +	struct stm32_timer_trigger *priv = iio_priv(indio_dev);
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(master_mode_table); i++) {
> +		if (!strncmp(master_mode_table[i], buf,
> +			     strlen(master_mode_table[i]))) {
> +			regmap_update_bits(priv->regmap, TIM_CR2,
> +					   TIM_CR2_MMS, i << TIM_CR2_MMS_SHIFT);
> +			/* Make sure that registers are updated */
> +			regmap_update_bits(priv->regmap, TIM_EGR,
> +					   TIM_EGR_UG, TIM_EGR_UG);
> +			return len;
> +		}
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +static IIO_CONST_ATTR(master_mode_available,
> +	"reset enable update compare_pulse OC1REF OC2REF OC3REF OC4REF");
> +
> +static IIO_DEVICE_ATTR(master_mode, 0660,
> +		       stm32_tt_show_master_mode,
> +		       stm32_tt_store_master_mode,
> +		       0);
> +
> +static struct attribute *stm32_trigger_attrs[] = {
> +	&iio_dev_attr_sampling_frequency.dev_attr.attr,
> +	&iio_dev_attr_master_mode.dev_attr.attr,
> +	&iio_const_attr_master_mode_available.dev_attr.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group stm32_trigger_attr_group = {
> +	.attrs = stm32_trigger_attrs,
> +};
> +
> +static const struct attribute_group *stm32_trigger_attr_groups[] = {
> +	&stm32_trigger_attr_group,
> +	NULL,
> +};
> +
> +static const struct iio_trigger_ops timer_trigger_ops = {
> +	.owner = THIS_MODULE,
> +};
> +
> +static int stm32_setup_iio_triggers(struct stm32_timer_trigger *priv)
> +{
> +	int ret;
> +	const char * const *cur = priv->triggers;
> +
> +	while (cur && *cur) {
> +		struct iio_trigger *trig;
> +
> +		trig = devm_iio_trigger_alloc(priv->dev, "%s", *cur);
> +		if  (!trig)
> +			return -ENOMEM;
> +
> +		trig->dev.parent = priv->dev->parent;
> +		trig->ops = &timer_trigger_ops;
> +
> +		/*
> +		 * sampling frequency and master mode attributes
> +		 * should only be available on trgo trigger which
> +		 * is always the first in the list.
> +		 */
> +		if (cur == priv->triggers)
> +			trig->dev.groups = stm32_trigger_attr_groups;
> +
> +		iio_trigger_set_drvdata(trig, priv);
> +
> +		ret = devm_iio_trigger_register(priv->dev, trig);
> +		if (ret)
> +			return ret;
> +		cur++;
> +	}
> +
> +	return 0;
> +}
> +
> +/**
> + * is_stm32_timer_trigger
> + * @trig: trigger to be checked
> + *
> + * return true if the trigger is a valid stm32 iio timer trigger
> + * either return false
> + */
> +bool is_stm32_timer_trigger(struct iio_trigger *trig)
> +{
> +	return (trig->ops == &timer_trigger_ops);
> +}
> +EXPORT_SYMBOL(is_stm32_timer_trigger);
> +
> +static int stm32_timer_trigger_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct stm32_timer_trigger *priv;
> +	struct stm32_timers *ddata = dev_get_drvdata(pdev->dev.parent);
> +	unsigned int index;
> +	int ret;
> +
> +	if (of_property_read_u32(dev->of_node, "reg", &index))
> +		return -EINVAL;
> +
> +	if (index >= ARRAY_SIZE(triggers_table))
> +		return -EINVAL;
> +
> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> +
> +	if (!priv)
> +		return -ENOMEM;
> +
> +	priv->dev = dev;
> +	priv->regmap = ddata->regmap;
> +	priv->clk = ddata->clk;
> +	priv->max_arr = ddata->max_arr;
> +	priv->triggers = triggers_table[index];
> +
> +	ret = stm32_setup_iio_triggers(priv);
> +	if (ret)
> +		return ret;
> +
> +	platform_set_drvdata(pdev, priv);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id stm32_trig_of_match[] = {
> +	{ .compatible = "st,stm32-timer-trigger", },
> +	{ /* end node */ },
> +};
> +MODULE_DEVICE_TABLE(of, stm32_trig_of_match);
> +
> +static struct platform_driver stm32_timer_trigger_driver = {
> +	.probe = stm32_timer_trigger_probe,
> +	.driver = {
> +		.name = "stm32-timer-trigger",
> +		.of_match_table = stm32_trig_of_match,
> +	},
> +};
> +module_platform_driver(stm32_timer_trigger_driver);
> +
> +MODULE_ALIAS("platform: stm32-timer-trigger");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Timer Trigger driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/iio/timer/stm32-timer-trigger.h b/include/linux/iio/timer/stm32-timer-trigger.h
> new file mode 100644
> index 0000000..55535ae
> --- /dev/null
> +++ b/include/linux/iio/timer/stm32-timer-trigger.h
> @@ -0,0 +1,62 @@
> +/*
> + * Copyright (C) STMicroelectronics 2016
> + *
> + * Author: Benjamin Gaignard <benjamin.gaignard@st.com>
> + *
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#ifndef _STM32_TIMER_TRIGGER_H_
> +#define _STM32_TIMER_TRIGGER_H_
> +
> +#define TIM1_TRGO	"tim1_trgo"
> +#define TIM1_CH1	"tim1_ch1"
> +#define TIM1_CH2	"tim1_ch2"
> +#define TIM1_CH3	"tim1_ch3"
> +#define TIM1_CH4	"tim1_ch4"
> +
> +#define TIM2_TRGO	"tim2_trgo"
> +#define TIM2_CH1	"tim2_ch1"
> +#define TIM2_CH2	"tim2_ch2"
> +#define TIM2_CH3	"tim2_ch3"
> +#define TIM2_CH4	"tim2_ch4"
> +
> +#define TIM3_TRGO	"tim3_trgo"
> +#define TIM3_CH1	"tim3_ch1"
> +#define TIM3_CH2	"tim3_ch2"
> +#define TIM3_CH3	"tim3_ch3"
> +#define TIM3_CH4	"tim3_ch4"
> +
> +#define TIM4_TRGO	"tim4_trgo"
> +#define TIM4_CH1	"tim4_ch1"
> +#define TIM4_CH2	"tim4_ch2"
> +#define TIM4_CH3	"tim4_ch3"
> +#define TIM4_CH4	"tim4_ch4"
> +
> +#define TIM5_TRGO	"tim5_trgo"
> +#define TIM5_CH1	"tim5_ch1"
> +#define TIM5_CH2	"tim5_ch2"
> +#define TIM5_CH3	"tim5_ch3"
> +#define TIM5_CH4	"tim5_ch4"
> +
> +#define TIM6_TRGO	"tim6_trgo"
> +
> +#define TIM7_TRGO	"tim7_trgo"
> +
> +#define TIM8_TRGO	"tim8_trgo"
> +#define TIM8_CH1	"tim8_ch1"
> +#define TIM8_CH2	"tim8_ch2"
> +#define TIM8_CH3	"tim8_ch3"
> +#define TIM8_CH4	"tim8_ch4"
> +
> +#define TIM9_TRGO	"tim9_trgo"
> +#define TIM9_CH1	"tim9_ch1"
> +#define TIM9_CH2	"tim9_ch2"
> +
> +#define TIM12_TRGO	"tim12_trgo"
> +#define TIM12_CH1	"tim12_ch1"
> +#define TIM12_CH2	"tim12_ch2"
> +
> +bool is_stm32_timer_trigger(struct iio_trigger *trig);
> +
> +#endif
> 

^ permalink raw reply

* [PATCH v7 5/8] IIO: add bindings for STM32 timer trigger driver
From: Jonathan Cameron @ 2017-01-08 11:23 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483608344-9012-6-git-send-email-benjamin.gaignard@st.com>

On 05/01/17 09:25, Benjamin Gaignard wrote:
> Define bindings for STM32 timer trigger
> 
> version 4:
> - remove triggers enumeration from DT
> - add reg parameter
> 
> version 3:
> - change file name
> - add cross reference with mfd bindings
> 
> version 2:
> - only keep one compatible
> - add DT parameters to set lists of the triggers:
>   one list describe the triggers created by the device
>   another one give the triggers accepted by the device
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@st.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
> ---
>  .../bindings/iio/timer/stm32-timer-trigger.txt     | 23 ++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
> 
> diff --git a/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
> new file mode 100644
> index 0000000..36a6c4a
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/iio/timer/stm32-timer-trigger.txt
> @@ -0,0 +1,23 @@
> +STMicroelectronics STM32 Timers IIO timer bindings
> +
> +Must be a sub-node of an STM32 Timers device tree node.
> +See ../mfd/stm32-timers.txt for details about the parent node.
> +
> +Required parameters:
> +- compatible:	Must be "st,stm32-timer-trigger".
> +- reg:		Define triggers configuration of the hardware IP.
> +
> +Example:
> +	timers at 40010000 {
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		compatible = "st,stm32-timers";
> +		reg = <0x40010000 0x400>;
> +		clocks = <&rcc 0 160>;
> +		clock-names = "clk_int";
> +
> +		timer {
> +			compatible = "st,stm32-timer-trigger";
> +			reg = <0>;
> +		};
> +	};
> 

^ permalink raw reply

* [PATCH v9 3/3] iio: adc: add support for Allwinner SoCs ADC
From: Jonathan Cameron @ 2017-01-08 11:17 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <8132b799-6c6e-fc74-ebac-6959ac4c97a7@kernel.org>

On 30/12/16 14:40, Jonathan Cameron wrote:
> On 13/12/16 14:33, Quentin Schulz wrote:
>> The Allwinner SoCs all have an ADC that can also act as a touchscreen
>> controller and a thermal sensor. This patch adds the ADC driver which is
>> based on the MFD for the same SoCs ADC.
>>
>> This also registers the thermal adc channel in the iio map array so
>> iio_hwmon could use it without modifying the Device Tree. This registers
>> the driver in the thermal framework.
>>
>> The thermal sensor requires the IP to be in touchscreen mode to return
>> correct values. Therefore, if the user is continuously reading the ADC
>> channel(s), the thermal framework in which the thermal sensor is
>> registered will switch the IP in touchscreen mode to get a temperature
>> value and requires a delay of 100ms (because of the mode switching),
>> then the ADC will switch back to ADC mode and requires also a delay of
>> 100ms. If the ADC readings are critical to user and the SoC temperature
>> is not, this driver is capable of not registering the thermal sensor in
>> the thermal framework and thus, "quicken" the ADC readings.
>>
>> This driver probes on three different platform_device_id to take into
>> account slight differences (registers bit and temperature computation)
>> between Allwinner SoCs ADCs.
>>
>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>> Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
>> Acked-by: Jonathan Cameron <jic23@kernel.org>
>> Acked-for-MFD-by: Lee Jones <lee.jones@linaro.org>
> One comment inline but not a blocker.
> 
> I would ideally like an ack from the thermal side.  The relevant code
> is small, but best to be sure and keep them in the loop as well.
> 
> It does feel a little convoluted to have both this directly providing
> a thermal zone and being able to create one indirectly through hwmon as
> well but this solution works for me I think...
> 
> Cc'd Zang and Eduardo.
Nothing seems to have come through on that front.

I need to get a pull request out to Greg and rebase my tree before I have
the precursor patch in place. Give me a bump if you haven't heard anything by
the time next week.

Thanks,

Jonathan
> 
> Jonathan
>> ---
>>
>> v9:
>>  - clarify comment on why we have to use the parent node as node for
>>  registering in thermal framework, (backward compatibility)
>>  - clarify comment on why we can disable CONFIG_THERMAL_OF,
>>  - clarify Kconfig help to say that CONFIG_THERMAL_OF can be disabled
>>  but should not in most cases,
>>  - make return value of devm_thermal_zone_of_sensor_register a local
>>  variable of the condition block,
>>  - correct scale from _PLUS_MICRO to _PLUS_NANO for ADC raw readings
>>  scale,
>>
>> v8:
>>  - remove Kconfig depends on !TOUCHSCREEN_SUN4I (moved to
>> MFD_SUN4I_GPADC),
>>  - fix return values of regmap_irq_get_virq and platform_get_irq_byname
>> stored in an unsigned int and then check if negative,
>>  - fix uninitialized ret value when an error occurs while registering
>> the thermal sensor in the framework,
>>
>> v7:
>>  - add Kconfig depends on !TOUCHSCREEN_SUN4I,
>>  - remove Kconfig selects THERMAL_OF,
>>  - do not register thermal sensor if CONFIG_THERMAL_OF is disabled,
>>  - disable irq in irq_handler rather than in read_raw,
>>  - add delay when switching the IP's mode or channel (delay empirically found),
>>  - quicken thermal sensor interrupt period,
>>  - add masks for channel bits,
>>  - fix deadlock in sun4i_gpadc_read if regmap_read/write fails,
>>  - move some logic from sun4i_gpadc_read to sun4i_prepare_for_irq,
>>  - mark last busy for runtime_pm only on success in sun4i_gpadc_read,
>>  - remove cached values,
>>  - increase wait_for_completion_timeout timeout to 1s to be sure to not miss the
>>  thermal interrupt,
>>  - add voltage scale,
>>  - use devm_iio_device_register,
>>
>> v6:
>>  - remove "-mfd" from filenames and variables inside MFD driver,
>>  - use DEFINE_RES_IRQ_NAMED instead of setting resources manually,
>>  - cosmetic changes,
>>  - use IDs and switch over ID to get cells specific to an architecture, instead
>>  of using cells direclty, in of_device_id.data,
>>  - compute size of mfd_cells array instead of hardcoded one,
>>
>> v5:
>>  - correct mail address,
>>
>> v4:
>>  - rename files and variables from sunxi* to sun4i*,
>>  - rename defines from SUNXI_* to SUN4I_* or SUN6I_*,
>>  - remove TP in defines name,
>>  - rename SUNXI_IRQ_* to SUN4I_GPADC_IRQ_* for consistency,
>>  - use devm functions for regmap_add_irq_chip and mfd_add_devices,
>>  - remove remove functions (now empty thanks to devm functions),
>>
>> v3:
>>  - use defines in regmap_irq instead of hard coded BITs,
>>  - use of_device_id data field to chose which MFD cells to add considering
>>    the compatible responsible of the MFD probe,
>>  - remove useless initializations,
>>  - disable all interrupts before adding them to regmap_irqchip,
>>  - add goto error label in probe,
>>  - correct wrapping in header license,
>>  - move defines from IIO driver to header,
>>  - use GENMASK to limit the size of the variable passed to a macro,
>>  - prefix register BIT defines with the name of the register,
>>  - reorder defines,
>>
>> v2:
>>  - add license headers,
>>  - reorder alphabetically includes,
>>  - add SUNXI_GPADC_ prefixes for defines,
>>
>>  drivers/iio/adc/Kconfig           |  17 ++
>>  drivers/iio/adc/Makefile          |   1 +
>>  drivers/iio/adc/sun4i-gpadc-iio.c | 613 ++++++++++++++++++++++++++++++++++++++
>>  include/linux/mfd/sun4i-gpadc.h   |   2 +
>>  4 files changed, 633 insertions(+)
>>  create mode 100644 drivers/iio/adc/sun4i-gpadc-iio.c
>>
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index 99c0514..6a6d369 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -434,6 +434,23 @@ config STX104
>>  	  The base port addresses for the devices may be configured via the base
>>  	  array module parameter.
>>  
>> +config SUN4I_GPADC
>> +	tristate "Support for the Allwinner SoCs GPADC"
>> +	depends on IIO
>> +	depends on MFD_SUN4I_GPADC
>> +	help
>> +	  Say yes here to build support for Allwinner (A10, A13 and A31) SoCs
>> +	  GPADC. This ADC provides 4 channels which can be used as an ADC or as
>> +	  a touchscreen input and one channel for thermal sensor.
>> +
>> +	  The thermal sensor slows down ADC readings and can be disabled by
>> +	  disabling CONFIG_THERMAL_OF. However, the thermal sensor should be
>> +	  enabled by default since the SoC temperature is usually more critical
>> +	  than ADC readings.
>> +
>> +	  To compile this driver as a module, choose M here: the module will be
>> +	  called sun4i-gpadc-iio.
>> +
>>  config TI_ADC081C
>>  	tristate "Texas Instruments ADC081C/ADC101C/ADC121C family"
>>  	depends on I2C
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 7a40c04..18ce8d6 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -41,6 +41,7 @@ obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
>>  obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
>>  obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
>>  obj-$(CONFIG_STX104) += stx104.o
>> +obj-$(CONFIG_SUN4I_GPADC) += sun4i-gpadc-iio.o
>>  obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
>>  obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
>>  obj-$(CONFIG_TI_ADC12138) += ti-adc12138.o
>> diff --git a/drivers/iio/adc/sun4i-gpadc-iio.c b/drivers/iio/adc/sun4i-gpadc-iio.c
>> new file mode 100644
>> index 0000000..a8e134f
>> --- /dev/null
>> +++ b/drivers/iio/adc/sun4i-gpadc-iio.c
>> @@ -0,0 +1,613 @@
>> +/* ADC driver for sunxi platforms' (A10, A13 and A31) GPADC
>> + *
>> + * Copyright (c) 2016 Quentin Schulz <quentin.schulz@free-electrons.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it under
>> + * the terms of the GNU General Public License version 2 as published by the
>> + * Free Software Foundation.
>> + *
>> + * The Allwinner SoCs all have an ADC that can also act as a touchscreen
>> + * controller and a thermal sensor.
>> + * The thermal sensor works only when the ADC acts as a touchscreen controller
>> + * and is configured to throw an interrupt every fixed periods of time (let say
>> + * every X seconds).
>> + * One would be tempted to disable the IP on the hardware side rather than
>> + * disabling interrupts to save some power but that resets the internal clock of
>> + * the IP, resulting in having to wait X seconds every time we want to read the
>> + * value of the thermal sensor.
>> + * This is also the reason of using autosuspend in pm_runtime. If there was no
>> + * autosuspend, the thermal sensor would need X seconds after every
>> + * pm_runtime_get_sync to get a value from the ADC. The autosuspend allows the
>> + * thermal sensor to be requested again in a certain time span before it gets
>> + * shutdown for not being used.
>> + */
>> +
>> +#include <linux/completion.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/of_device.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <linux/thermal.h>
>> +#include <linux/delay.h>
>> +
>> +#include <linux/iio/iio.h>
>> +#include <linux/iio/driver.h>
>> +#include <linux/iio/machine.h>
>> +#include <linux/mfd/sun4i-gpadc.h>
>> +
>> +static unsigned int sun4i_gpadc_chan_select(unsigned int chan)
>> +{
>> +	return SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
>> +}
>> +
>> +static unsigned int sun6i_gpadc_chan_select(unsigned int chan)
>> +{
>> +	return SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(chan);
>> +}
>> +
>> +struct gpadc_data {
>> +	int		temp_offset;
>> +	int		temp_scale;
>> +	unsigned int	tp_mode_en;
>> +	unsigned int	tp_adc_select;
>> +	unsigned int	(*adc_chan_select)(unsigned int chan);
>> +	unsigned int	adc_chan_mask;
>> +};
>> +
>> +static const struct gpadc_data sun4i_gpadc_data = {
>> +	.temp_offset = -1932,
>> +	.temp_scale = 133,
>> +	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
>> +	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
>> +	.adc_chan_select = &sun4i_gpadc_chan_select,
>> +	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
>> +};
>> +
>> +static const struct gpadc_data sun5i_gpadc_data = {
>> +	.temp_offset = -1447,
>> +	.temp_scale = 100,
>> +	.tp_mode_en = SUN4I_GPADC_CTRL1_TP_MODE_EN,
>> +	.tp_adc_select = SUN4I_GPADC_CTRL1_TP_ADC_SELECT,
>> +	.adc_chan_select = &sun4i_gpadc_chan_select,
>> +	.adc_chan_mask = SUN4I_GPADC_CTRL1_ADC_CHAN_MASK,
>> +};
>> +
>> +static const struct gpadc_data sun6i_gpadc_data = {
>> +	.temp_offset = -1623,
>> +	.temp_scale = 167,
>> +	.tp_mode_en = SUN6I_GPADC_CTRL1_TP_MODE_EN,
>> +	.tp_adc_select = SUN6I_GPADC_CTRL1_TP_ADC_SELECT,
>> +	.adc_chan_select = &sun6i_gpadc_chan_select,
>> +	.adc_chan_mask = SUN6I_GPADC_CTRL1_ADC_CHAN_MASK,
>> +};
>> +
>> +struct sun4i_gpadc_iio {
>> +	struct iio_dev			*indio_dev;
>> +	struct completion		completion;
>> +	int				temp_data;
>> +	u32				adc_data;
>> +	struct regmap			*regmap;
>> +	unsigned int			fifo_data_irq;
>> +	atomic_t			ignore_fifo_data_irq;
>> +	unsigned int			temp_data_irq;
>> +	atomic_t			ignore_temp_data_irq;
>> +	const struct gpadc_data		*data;
>> +	/* prevents concurrent reads of temperature and ADC */
>> +	struct mutex			mutex;
>> +};
>> +
>> +#define SUN4I_GPADC_ADC_CHANNEL(_channel, _name) {		\
>> +	.type = IIO_VOLTAGE,					\
>> +	.indexed = 1,						\
>> +	.channel = _channel,					\
>> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
>> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),	\
>> +	.datasheet_name = _name,				\
>> +}
>> +
>> +static struct iio_map sun4i_gpadc_hwmon_maps[] = {
>> +	{
>> +		.adc_channel_label = "temp_adc",
>> +		.consumer_dev_name = "iio_hwmon.0",
> It's theoretically possible we have another one of these which will make
> life interesting.  Oh well, no easy way around that at the mo...
>> +	},
>> +	{ /* sentinel */ },
>> +};
>> +
>> +static const struct iio_chan_spec sun4i_gpadc_channels[] = {
>> +	SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
>> +	SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
>> +	SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
>> +	SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
>> +	{
>> +		.type = IIO_TEMP,
>> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
>> +				      BIT(IIO_CHAN_INFO_SCALE) |
>> +				      BIT(IIO_CHAN_INFO_OFFSET),
>> +		.datasheet_name = "temp_adc",
>> +	},
>> +};
>> +
>> +static const struct iio_chan_spec sun4i_gpadc_channels_no_temp[] = {
>> +	SUN4I_GPADC_ADC_CHANNEL(0, "adc_chan0"),
>> +	SUN4I_GPADC_ADC_CHANNEL(1, "adc_chan1"),
>> +	SUN4I_GPADC_ADC_CHANNEL(2, "adc_chan2"),
>> +	SUN4I_GPADC_ADC_CHANNEL(3, "adc_chan3"),
>> +};
>> +
>> +static int sun4i_prepare_for_irq(struct iio_dev *indio_dev, int channel,
>> +				 unsigned int irq)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +	int ret;
>> +	u32 reg;
>> +
>> +	pm_runtime_get_sync(indio_dev->dev.parent);
>> +
>> +	reinit_completion(&info->completion);
>> +
>> +	ret = regmap_write(info->regmap, SUN4I_GPADC_INT_FIFOC,
>> +			   SUN4I_GPADC_INT_FIFOC_TP_FIFO_TRIG_LEVEL(1) |
>> +			   SUN4I_GPADC_INT_FIFOC_TP_FIFO_FLUSH);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = regmap_read(info->regmap, SUN4I_GPADC_CTRL1, &reg);
>> +	if (ret)
>> +		return ret;
>> +
>> +	if (irq == info->fifo_data_irq) {
>> +		ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
>> +				   info->data->tp_mode_en |
>> +				   info->data->tp_adc_select |
>> +				   info->data->adc_chan_select(channel));
>> +		/*
>> +		 * When the IP changes channel, it needs a bit of time to get
>> +		 * correct values.
>> +		 */
>> +		if ((reg & info->data->adc_chan_mask) !=
>> +			 info->data->adc_chan_select(channel))
>> +			mdelay(10);
>> +
>> +	} else {
>> +		/*
>> +		 * The temperature sensor returns valid data only when the ADC
>> +		 * operates in touchscreen mode.
>> +		 */
>> +		ret = regmap_write(info->regmap, SUN4I_GPADC_CTRL1,
>> +				   info->data->tp_mode_en);
>> +	}
>> +
>> +	if (ret)
>> +		return ret;
>> +
>> +	/*
>> +	 * When the IP changes mode between ADC or touchscreen, it
>> +	 * needs a bit of time to get correct values.
>> +	 */
>> +	if ((reg & info->data->tp_adc_select) != info->data->tp_adc_select)
>> +		mdelay(100);
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_read(struct iio_dev *indio_dev, int channel, int *val,
>> +			    unsigned int irq)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +	int ret;
>> +
>> +	mutex_lock(&info->mutex);
>> +
>> +	ret = sun4i_prepare_for_irq(indio_dev, channel, irq);
>> +	if (ret)
>> +		goto err;
>> +
>> +	enable_irq(irq);
>> +
>> +	/*
>> +	 * The temperature sensor throws an interruption periodically (currently
>> +	 * set at periods of ~0.6s in sun4i_gpadc_runtime_resume). A 1s delay
>> +	 * makes sure an interruption occurs in normal conditions. If it doesn't
>> +	 * occur, then there is a timeout.
>> +	 */
>> +	if (!wait_for_completion_timeout(&info->completion,
>> +					 msecs_to_jiffies(1000))) {
>> +		ret = -ETIMEDOUT;
>> +		goto err;
>> +	}
>> +
>> +	if (irq == info->fifo_data_irq)
>> +		*val = info->adc_data;
>> +	else
>> +		*val = info->temp_data;
>> +
>> +	ret = 0;
>> +	pm_runtime_mark_last_busy(indio_dev->dev.parent);
>> +
>> +err:
>> +	pm_runtime_put_autosuspend(indio_dev->dev.parent);
>> +	mutex_unlock(&info->mutex);
>> +
>> +	return ret;
>> +}
>> +
>> +static int sun4i_gpadc_adc_read(struct iio_dev *indio_dev, int channel,
>> +				int *val)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +
>> +	return sun4i_gpadc_read(indio_dev, channel, val, info->fifo_data_irq);
>> +}
>> +
>> +static int sun4i_gpadc_temp_read(struct iio_dev *indio_dev, int *val)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +
>> +	return sun4i_gpadc_read(indio_dev, 0, val, info->temp_data_irq);
>> +}
>> +
>> +static int sun4i_gpadc_temp_offset(struct iio_dev *indio_dev, int *val)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +
>> +	*val = info->data->temp_offset;
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_temp_scale(struct iio_dev *indio_dev, int *val)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(indio_dev);
>> +
>> +	*val = info->data->temp_scale;
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_read_raw(struct iio_dev *indio_dev,
>> +				struct iio_chan_spec const *chan, int *val,
>> +				int *val2, long mask)
>> +{
>> +	int ret;
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_OFFSET:
>> +		ret = sun4i_gpadc_temp_offset(indio_dev, val);
>> +		if (ret)
>> +			return ret;
>> +
>> +		return IIO_VAL_INT;
>> +	case IIO_CHAN_INFO_RAW:
>> +		if (chan->type == IIO_VOLTAGE)
>> +			ret = sun4i_gpadc_adc_read(indio_dev, chan->channel,
>> +						   val);
>> +		else
>> +			ret = sun4i_gpadc_temp_read(indio_dev, val);
>> +
>> +		if (ret)
>> +			return ret;
>> +
>> +		return IIO_VAL_INT;
>> +	case IIO_CHAN_INFO_SCALE:
>> +		if (chan->type == IIO_VOLTAGE) {
>> +			/* 3000mV / 4096 * raw */
>> +			*val = 0;
>> +			*val2 = 732421875;
>> +			return IIO_VAL_INT_PLUS_NANO;
>> +		}
>> +
>> +		ret = sun4i_gpadc_temp_scale(indio_dev, val);
>> +		if (ret)
>> +			return ret;
>> +
>> +		return IIO_VAL_INT;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +
>> +	return -EINVAL;
>> +}
>> +
>> +static const struct iio_info sun4i_gpadc_iio_info = {
>> +	.read_raw = sun4i_gpadc_read_raw,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +static irqreturn_t sun4i_gpadc_temp_data_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct sun4i_gpadc_iio *info = dev_id;
>> +
>> +	if (atomic_read(&info->ignore_temp_data_irq))
>> +		goto out;
>> +
>> +	if (!regmap_read(info->regmap, SUN4I_GPADC_TEMP_DATA, &info->temp_data))
>> +		complete(&info->completion);
>> +
>> +out:
>> +	disable_irq_nosync(info->temp_data_irq);
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static irqreturn_t sun4i_gpadc_fifo_data_irq_handler(int irq, void *dev_id)
>> +{
>> +	struct sun4i_gpadc_iio *info = dev_id;
>> +
>> +	if (atomic_read(&info->ignore_fifo_data_irq))
>> +		goto out;
>> +
>> +	if (!regmap_read(info->regmap, SUN4I_GPADC_DATA, &info->adc_data))
>> +		complete(&info->completion);
>> +
>> +out:
>> +	disable_irq_nosync(info->fifo_data_irq);
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static int sun4i_gpadc_runtime_suspend(struct device *dev)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
>> +
>> +	/* Disable the ADC on IP */
>> +	regmap_write(info->regmap, SUN4I_GPADC_CTRL1, 0);
>> +	/* Disable temperature sensor on IP */
>> +	regmap_write(info->regmap, SUN4I_GPADC_TPR, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_runtime_resume(struct device *dev)
>> +{
>> +	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(dev));
>> +
>> +	/* clkin = 6MHz */
>> +	regmap_write(info->regmap, SUN4I_GPADC_CTRL0,
>> +		     SUN4I_GPADC_CTRL0_ADC_CLK_DIVIDER(2) |
>> +		     SUN4I_GPADC_CTRL0_FS_DIV(7) |
>> +		     SUN4I_GPADC_CTRL0_T_ACQ(63));
>> +	regmap_write(info->regmap, SUN4I_GPADC_CTRL1, info->data->tp_mode_en);
>> +	regmap_write(info->regmap, SUN4I_GPADC_CTRL3,
>> +		     SUN4I_GPADC_CTRL3_FILTER_EN |
>> +		     SUN4I_GPADC_CTRL3_FILTER_TYPE(1));
>> +	/* period = SUN4I_GPADC_TPR_TEMP_PERIOD * 256 * 16 / clkin; ~0.6s */
>> +	regmap_write(info->regmap, SUN4I_GPADC_TPR,
>> +		     SUN4I_GPADC_TPR_TEMP_ENABLE |
>> +		     SUN4I_GPADC_TPR_TEMP_PERIOD(800));
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_get_temp(void *data, int *temp)
>> +{
>> +	struct sun4i_gpadc_iio *info = (struct sun4i_gpadc_iio *)data;
>> +	int val, scale, offset;
>> +
>> +	if (sun4i_gpadc_temp_read(info->indio_dev, &val))
>> +		return -ETIMEDOUT;
>> +
>> +	sun4i_gpadc_temp_scale(info->indio_dev, &scale);
>> +	sun4i_gpadc_temp_offset(info->indio_dev, &offset);
>> +
>> +	*temp = (val + offset) * scale;
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
>> +	.get_temp = &sun4i_gpadc_get_temp,
>> +};
>> +
>> +static const struct dev_pm_ops sun4i_gpadc_pm_ops = {
>> +	.runtime_suspend = &sun4i_gpadc_runtime_suspend,
>> +	.runtime_resume = &sun4i_gpadc_runtime_resume,
>> +};
>> +
>> +static int sun4i_irq_init(struct platform_device *pdev, const char *name,
>> +			  irq_handler_t handler, const char *devname,
>> +			  unsigned int *irq, atomic_t *atomic)
>> +{
>> +	int ret;
>> +	struct sun4i_gpadc_dev *mfd_dev = dev_get_drvdata(pdev->dev.parent);
>> +	struct sun4i_gpadc_iio *info = iio_priv(dev_get_drvdata(&pdev->dev));
>> +
>> +	/*
>> +	 * Once the interrupt is activated, the IP continuously performs
>> +	 * conversions thus throws interrupts. The interrupt is activated right
>> +	 * after being requested but we want to control when these interrupts
>> +	 * occur thus we disable it right after being requested. However, an
>> +	 * interrupt might occur between these two instructions and we have to
>> +	 * make sure that does not happen, by using atomic flags. We set the
>> +	 * flag before requesting the interrupt and unset it right after
>> +	 * disabling the interrupt. When an interrupt occurs between these two
>> +	 * instructions, reading the atomic flag will tell us to ignore the
>> +	 * interrupt.
>> +	 */
>> +	atomic_set(atomic, 1);
>> +
>> +	ret = platform_get_irq_byname(pdev, name);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "no %s interrupt registered\n", name);
>> +		return ret;
>> +	}
>> +
>> +	ret = regmap_irq_get_virq(mfd_dev->regmap_irqc, ret);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "failed to get virq for irq %s\n", name);
>> +		return ret;
>> +	}
>> +
>> +	*irq = ret;
>> +	ret = devm_request_any_context_irq(&pdev->dev, *irq, handler, 0,
>> +					   devname, info);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "could not request %s interrupt: %d\n",
>> +			name, ret);
>> +		return ret;
>> +	}
>> +
>> +	disable_irq(*irq);
>> +	atomic_set(atomic, 0);
>> +
>> +	return 0;
>> +}
>> +
>> +static int sun4i_gpadc_probe(struct platform_device *pdev)
>> +{
>> +	struct sun4i_gpadc_iio *info;
>> +	struct iio_dev *indio_dev;
>> +	int ret;
>> +	struct sun4i_gpadc_dev *sun4i_gpadc_dev;
>> +
>> +	sun4i_gpadc_dev = dev_get_drvdata(pdev->dev.parent);
>> +
>> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	info = iio_priv(indio_dev);
>> +	platform_set_drvdata(pdev, indio_dev);
>> +
>> +	mutex_init(&info->mutex);
>> +	info->regmap = sun4i_gpadc_dev->regmap;
>> +	info->indio_dev = indio_dev;
>> +	init_completion(&info->completion);
>> +	indio_dev->name = dev_name(&pdev->dev);
>> +	indio_dev->dev.parent = &pdev->dev;
>> +	indio_dev->dev.of_node = pdev->dev.of_node;
>> +	indio_dev->info = &sun4i_gpadc_iio_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +	indio_dev->num_channels = ARRAY_SIZE(sun4i_gpadc_channels);
>> +	indio_dev->channels = sun4i_gpadc_channels;
>> +
>> +	info->data = (struct gpadc_data *)platform_get_device_id(pdev)->driver_data;
>> +
>> +	/*
>> +	 * Since the controller needs to be in touchscreen mode for its thermal
>> +	 * sensor to operate properly, and that switching between the two modes
>> +	 * needs a delay, always registering in the thermal framework will
>> +	 * significantly slow down the conversion rate of the ADCs.
>> +	 *
>> +	 * Therefore, instead of depending on THERMAL_OF in Kconfig, we only
>> +	 * register the sensor if that option is enabled, eventually leaving
>> +	 * that choice to the user.
>> +	 */
>> +
>> +	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
>> +		/*
>> +		 * This driver is a child of an MFD which has a node in the DT
>> +		 * but not its children, because of DT backward compatibility
>> +		 * for A10, A13 and A31 SoCs. Therefore, the resulting devices
>> +		 * of this driver do not have an of_node variable.
>> +		 * However, its parent (the MFD driver) has an of_node variable
>> +		 * and since devm_thermal_zone_of_sensor_register uses its first
>> +		 * argument to match the phandle defined in the node of the
>> +		 * thermal driver with the of_node of the device passed as first
>> +		 * argument and the third argument to call ops from
>> +		 * thermal_zone_of_device_ops, the solution is to use the parent
>> +		 * device as first argument to match the phandle with its
>> +		 * of_node, and the device from this driver as third argument to
>> +		 * return the temperature.
>> +		 */
>> +		struct thermal_zone_device *tzd;
>> +		tzd = devm_thermal_zone_of_sensor_register(pdev->dev.parent, 0,
>> +							   info,
>> +							   &sun4i_ts_tz_ops);
>> +		if (IS_ERR(tzd)) {
>> +			dev_err(&pdev->dev,
>> +				"could not register thermal sensor: %ld\n",
>> +				PTR_ERR(tzd));
>> +			ret = PTR_ERR(tzd);
>> +			goto err;
>> +		}
>> +	} else {
>> +		indio_dev->num_channels =
>> +			ARRAY_SIZE(sun4i_gpadc_channels_no_temp);
>> +		indio_dev->channels = sun4i_gpadc_channels_no_temp;
>> +	}
>> +
>> +	pm_runtime_set_autosuspend_delay(&pdev->dev,
>> +					 SUN4I_GPADC_AUTOSUSPEND_DELAY);
>> +	pm_runtime_use_autosuspend(&pdev->dev);
>> +	pm_runtime_set_suspended(&pdev->dev);
>> +	pm_runtime_enable(&pdev->dev);
>> +
>> +	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
>> +		ret = sun4i_irq_init(pdev, "TEMP_DATA_PENDING",
>> +				     sun4i_gpadc_temp_data_irq_handler,
>> +				     "temp_data", &info->temp_data_irq,
>> +				     &info->ignore_temp_data_irq);
>> +		if (ret < 0)
>> +			goto err;
>> +	}
>> +
>> +	ret = sun4i_irq_init(pdev, "FIFO_DATA_PENDING",
>> +			     sun4i_gpadc_fifo_data_irq_handler, "fifo_data",
>> +			     &info->fifo_data_irq, &info->ignore_fifo_data_irq);
>> +	if (ret < 0)
>> +		goto err;
>> +
>> +	if (IS_ENABLED(CONFIG_THERMAL_OF)) {
>> +		ret = iio_map_array_register(indio_dev, sun4i_gpadc_hwmon_maps);
>> +		if (ret < 0) {
>> +			dev_err(&pdev->dev,
>> +				"failed to register iio map array\n");
>> +			goto err;
>> +		}
>> +	}
>> +
>> +	ret = devm_iio_device_register(&pdev->dev, indio_dev);
>> +	if (ret < 0) {
>> +		dev_err(&pdev->dev, "could not register the device\n");
>> +		goto err_map;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_map:
>> +	if (IS_ENABLED(CONFIG_THERMAL_OF))
>> +		iio_map_array_unregister(indio_dev);
>> +
>> +err:
>> +	pm_runtime_put(&pdev->dev);
>> +	pm_runtime_disable(&pdev->dev);
>> +
>> +	return ret;
>> +}
>> +
>> +static int sun4i_gpadc_remove(struct platform_device *pdev)
>> +{
>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +	pm_runtime_put(&pdev->dev);
>> +	pm_runtime_disable(&pdev->dev);
>> +	if (IS_ENABLED(CONFIG_THERMAL_OF))
>> +		iio_map_array_unregister(indio_dev);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct platform_device_id sun4i_gpadc_id[] = {
>> +	{ "sun4i-a10-gpadc-iio", (kernel_ulong_t)&sun4i_gpadc_data },
>> +	{ "sun5i-a13-gpadc-iio", (kernel_ulong_t)&sun5i_gpadc_data },
>> +	{ "sun6i-a31-gpadc-iio", (kernel_ulong_t)&sun6i_gpadc_data },
>> +	{ /* sentinel */ },
>> +};
>> +
>> +static struct platform_driver sun4i_gpadc_driver = {
>> +	.driver = {
>> +		.name = "sun4i-gpadc-iio",
>> +		.pm = &sun4i_gpadc_pm_ops,
>> +	},
>> +	.id_table = sun4i_gpadc_id,
>> +	.probe = sun4i_gpadc_probe,
>> +	.remove = sun4i_gpadc_remove,
>> +};
>> +
>> +module_platform_driver(sun4i_gpadc_driver);
>> +
>> +MODULE_DESCRIPTION("ADC driver for sunxi platforms");
>> +MODULE_AUTHOR("Quentin Schulz <quentin.schulz@free-electrons.com>");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/include/linux/mfd/sun4i-gpadc.h b/include/linux/mfd/sun4i-gpadc.h
>> index d7a29f2..509e736 100644
>> --- a/include/linux/mfd/sun4i-gpadc.h
>> +++ b/include/linux/mfd/sun4i-gpadc.h
>> @@ -28,6 +28,7 @@
>>  #define SUN4I_GPADC_CTRL1_TP_MODE_EN			BIT(4)
>>  #define SUN4I_GPADC_CTRL1_TP_ADC_SELECT			BIT(3)
>>  #define SUN4I_GPADC_CTRL1_ADC_CHAN_SELECT(x)		(GENMASK(2, 0) & (x))
>> +#define SUN4I_GPADC_CTRL1_ADC_CHAN_MASK			GENMASK(2, 0)
>>  
>>  /* TP_CTRL1 bits for sun6i SOCs */
>>  #define SUN6I_GPADC_CTRL1_TOUCH_PAN_CALI_EN		BIT(7)
>> @@ -35,6 +36,7 @@
>>  #define SUN6I_GPADC_CTRL1_TP_MODE_EN			BIT(5)
>>  #define SUN6I_GPADC_CTRL1_TP_ADC_SELECT			BIT(4)
>>  #define SUN6I_GPADC_CTRL1_ADC_CHAN_SELECT(x)		(GENMASK(3, 0) & BIT(x))
>> +#define SUN6I_GPADC_CTRL1_ADC_CHAN_MASK			GENMASK(3, 0)
>>  
>>  #define SUN4I_GPADC_CTRL2				0x08
>>  
>>
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-iio" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 

^ permalink raw reply

* [PATCH 14/22] dt-bindings: power: supply: add AXP20X/AXP22X battery DT binding
From: Jonathan Cameron @ 2017-01-08 10:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <4a8456e6-c6e9-73ac-0f5c-29e9faceb13c@free-electrons.com>

On 08/01/17 10:48, Quentin Schulz wrote:
> Hi Jonathan,
> 
> On 07/01/2017 20:33, Jonathan Cameron wrote:
>> On 04/01/17 08:21, Rob Herring wrote:
>>> On Mon, Jan 02, 2017 at 05:37:14PM +0100, Quentin Schulz wrote:
>>>> The X-Powers AXP20X and AXP22X PMICs can have a battery as power supply.
>>>>
>>>> This patch adds the DT binding documentation for the battery power
>>>> supply which gets various data from the PMIC, such as the battery status
>>>> (charging, discharging, full, dead), current max limit, current current,
>>>> battery capacity (in percentage), voltage max and min limits, current
>>>> voltage and battery capacity (in Ah).
>>>>
>>>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>>>> ---
>>>>  .../bindings/power/supply/axp20x_battery.txt       | 27 ++++++++++++++++++++++
>>>>  1 file changed, 27 insertions(+)
>>>>  create mode 100644 Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>>> new file mode 100644
>>>> index 0000000..5489d0d
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>>> @@ -0,0 +1,27 @@
>>>> +AXP20x and AXP22x battery power supply
>>>> +
>>>> +Required Properties:
>>>> + - compatible, one of:
>>>> +			"x-powers,axp209-battery-power-supply"
>>>> +			"x-powers,axp221-battery-power-supply"
>>>> + - io-channels: phandles to battery voltage, charge and discharge
>>>> + currents ADC channels
>>>> + - io-channel-names = "batt_v", "batt_chrg_i", "batt_dischrg_i";
>>>> +
>>>> +This node is a subnode of the axp20x/axp22x PMIC.
>>>> +
>>>> +The AXP20X and AXP22X can read the battery voltage, charge and discharge
>>>> +currents of the battery by reading ADC channels from the AXP20X/AXP22X
>>>> +ADC.
>>>> +
>>>> +Example:
>>>> +
>>>> +&axp209 {
>>>> +	battery_power_supply: battery_power_supply {
>>>
>>> Humm, I guess you power-supply is not sufficient, so 
>>> 'battery-power-supply' and similar for ac.
>>>
>>>> +		compatible = "x-powers,axp209-battery-power-supply";
>>>> +		io-channels = <&axp209_adc 7>, <&axp209_adc 8>,
>>>> +			<&axp209_adc 9>;
>>>> +		io-channel-names = "batt_v", "batt_chrg_i",
>>>> +			"batt_dischrg_i";
>> Is this stuff fixed for the device?
> 
> If we don't mix the IIO channels order, it is. This driver only requires
> batt_v, batt_chrg_i and batt_dischrg_i so we've to keep them at that
> place in the list of IIO channels. Or as suggested by Rob and Chen-Yu, I
> can move all this inside the driver with iio_map and don't care anymore
> about the order.
> 
I'd do that. Makes life easier to represented fixed things as fixed!
> Thanks,
> Quentin
> 

^ permalink raw reply

* [PATCH 14/22] dt-bindings: power: supply: add AXP20X/AXP22X battery DT binding
From: Quentin Schulz @ 2017-01-08 10:48 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <3155ba16-b51a-9306-6be4-0bdf4482a679@kernel.org>

Hi Jonathan,

On 07/01/2017 20:33, Jonathan Cameron wrote:
> On 04/01/17 08:21, Rob Herring wrote:
>> On Mon, Jan 02, 2017 at 05:37:14PM +0100, Quentin Schulz wrote:
>>> The X-Powers AXP20X and AXP22X PMICs can have a battery as power supply.
>>>
>>> This patch adds the DT binding documentation for the battery power
>>> supply which gets various data from the PMIC, such as the battery status
>>> (charging, discharging, full, dead), current max limit, current current,
>>> battery capacity (in percentage), voltage max and min limits, current
>>> voltage and battery capacity (in Ah).
>>>
>>> Signed-off-by: Quentin Schulz <quentin.schulz@free-electrons.com>
>>> ---
>>>  .../bindings/power/supply/axp20x_battery.txt       | 27 ++++++++++++++++++++++
>>>  1 file changed, 27 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>> new file mode 100644
>>> index 0000000..5489d0d
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/power/supply/axp20x_battery.txt
>>> @@ -0,0 +1,27 @@
>>> +AXP20x and AXP22x battery power supply
>>> +
>>> +Required Properties:
>>> + - compatible, one of:
>>> +			"x-powers,axp209-battery-power-supply"
>>> +			"x-powers,axp221-battery-power-supply"
>>> + - io-channels: phandles to battery voltage, charge and discharge
>>> + currents ADC channels
>>> + - io-channel-names = "batt_v", "batt_chrg_i", "batt_dischrg_i";
>>> +
>>> +This node is a subnode of the axp20x/axp22x PMIC.
>>> +
>>> +The AXP20X and AXP22X can read the battery voltage, charge and discharge
>>> +currents of the battery by reading ADC channels from the AXP20X/AXP22X
>>> +ADC.
>>> +
>>> +Example:
>>> +
>>> +&axp209 {
>>> +	battery_power_supply: battery_power_supply {
>>
>> Humm, I guess you power-supply is not sufficient, so 
>> 'battery-power-supply' and similar for ac.
>>
>>> +		compatible = "x-powers,axp209-battery-power-supply";
>>> +		io-channels = <&axp209_adc 7>, <&axp209_adc 8>,
>>> +			<&axp209_adc 9>;
>>> +		io-channel-names = "batt_v", "batt_chrg_i",
>>> +			"batt_dischrg_i";
> Is this stuff fixed for the device?

If we don't mix the IIO channels order, it is. This driver only requires
batt_v, batt_chrg_i and batt_dischrg_i so we've to keep them at that
place in the list of IIO channels. Or as suggested by Rob and Chen-Yu, I
can move all this inside the driver with iio_map and don't care anymore
about the order.

Thanks,
Quentin

-- 
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH 08/22] power: supply: add AC power supply driver for AXP20X and AXP22X PMICs
From: Quentin Schulz @ 2017-01-08 10:41 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <d6661ff6-442c-5535-aec2-35066577f119@kernel.org>

Hi Jonathan,

On 07/01/2017 20:31, Jonathan Cameron wrote:
> On 02/01/17 11:37, Quentin Schulz wrote:
[...]
>> +		/*
>> +		 * IIO framework gives mV but Power Supply framework gives ?V.
>> +		 */
> single line comment syntax throughout or we'll have to face a patch 'fixing' it.

I actually had to make it a multiple lines comment to make checkpatch
happy. Maybe there is something with the encoding of the ? symbol? I'll
retry with a u instead and let you know.

[...]

Thanks,
Quentin

-- 
Quentin Schulz, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com

^ permalink raw reply

* [PATCH] drivers: phy: constify phy_ops structures
From: Bhumika Goyal @ 2017-01-08 10:35 UTC (permalink / raw)
  To: linux-arm-kernel

Declare phy_ops structures as const as they are only passed as an
argument to the function devm_phy_create. This argument is of type const
struct phy_ops *, so phy_ops structures having this property can be
declared as const.
Done using Coccinelle:

@r1 disable optional_qualifier @
identifier i;
position p;
@@
static struct phy_ops i at p = {...};

@ok1@
identifier r1.i;
position p;
@@
devm_phy_create(...,&i at p)

@bad@
position p!={r1.p,ok1.p};
identifier r1.i;
@@
i at p

@depends on !bad disable optional_qualifier@
identifier r1.i;
@@
+const
struct phy_ops i;

File size details:

   text	   data	    bss	    dec	    hex	filename
   1504	    264	      0	   1768	    6e8	phy/phy-bcm-cygnus-pcie.o
   1576	    192	      0	   1768	    6e8	phy/phy-bcm-cygnus-pcie.o

   1083	    264	      0	   1347	    543	phy/phy-hi6220-usb.o
   1155	    192	      0	   1347	    543	phy/phy-hi6220-usb.o

   2767	    264	      0	   3031	    bd7	phy/phy-mt65xx-usb3.o
   2829	    192	      0	   3021	    bcd	phy/phy-mt65xx-usb3.o

   2710	    304	      0	   3014	    bc6	phy/phy-rcar-gen3-usb2.o
   2766	    240	      0	   3006	    bbe	phy/phy-rcar-gen3-usb2.o

Signed-off-by: Bhumika Goyal <bhumirks@gmail.com>
---
 drivers/phy/phy-bcm-cygnus-pcie.c | 2 +-
 drivers/phy/phy-hi6220-usb.c      | 2 +-
 drivers/phy/phy-mt65xx-usb3.c     | 2 +-
 drivers/phy/phy-rcar-gen3-usb2.c  | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/phy/phy-bcm-cygnus-pcie.c b/drivers/phy/phy-bcm-cygnus-pcie.c
index 082c03f..0f4ac5d 100644
--- a/drivers/phy/phy-bcm-cygnus-pcie.c
+++ b/drivers/phy/phy-bcm-cygnus-pcie.c
@@ -114,7 +114,7 @@ static int cygnus_pcie_phy_power_off(struct phy *p)
 	return cygnus_pcie_power_config(phy, false);
 }
 
-static struct phy_ops cygnus_pcie_phy_ops = {
+static const struct phy_ops cygnus_pcie_phy_ops = {
 	.power_on = cygnus_pcie_phy_power_on,
 	.power_off = cygnus_pcie_phy_power_off,
 	.owner = THIS_MODULE,
diff --git a/drivers/phy/phy-hi6220-usb.c b/drivers/phy/phy-hi6220-usb.c
index b2141cb..398c102 100644
--- a/drivers/phy/phy-hi6220-usb.c
+++ b/drivers/phy/phy-hi6220-usb.c
@@ -112,7 +112,7 @@ static int hi6220_phy_exit(struct phy *phy)
 	return hi6220_phy_setup(priv, false);
 }
 
-static struct phy_ops hi6220_phy_ops = {
+static const struct phy_ops hi6220_phy_ops = {
 	.init		= hi6220_phy_start,
 	.exit		= hi6220_phy_exit,
 	.owner		= THIS_MODULE,
diff --git a/drivers/phy/phy-mt65xx-usb3.c b/drivers/phy/phy-mt65xx-usb3.c
index 4d85e73..d972067 100644
--- a/drivers/phy/phy-mt65xx-usb3.c
+++ b/drivers/phy/phy-mt65xx-usb3.c
@@ -506,7 +506,7 @@ static struct phy *mt65xx_phy_xlate(struct device *dev,
 	return instance->phy;
 }
 
-static struct phy_ops mt65xx_u3phy_ops = {
+static const struct phy_ops mt65xx_u3phy_ops = {
 	.init		= mt65xx_phy_init,
 	.exit		= mt65xx_phy_exit,
 	.power_on	= mt65xx_phy_power_on,
diff --git a/drivers/phy/phy-rcar-gen3-usb2.c b/drivers/phy/phy-rcar-gen3-usb2.c
index c63da1b..17be045 100644
--- a/drivers/phy/phy-rcar-gen3-usb2.c
+++ b/drivers/phy/phy-rcar-gen3-usb2.c
@@ -350,7 +350,7 @@ static int rcar_gen3_phy_usb2_power_off(struct phy *p)
 	return ret;
 }
 
-static struct phy_ops rcar_gen3_phy_usb2_ops = {
+static const struct phy_ops rcar_gen3_phy_usb2_ops = {
 	.init		= rcar_gen3_phy_usb2_init,
 	.exit		= rcar_gen3_phy_usb2_exit,
 	.power_on	= rcar_gen3_phy_usb2_power_on,
-- 
1.9.1

^ permalink raw reply related

* [PATCH WIP 4/4] ARM: remove compile time vector base for CP15 case
From: Afzal Mohammed @ 2017-01-08  9:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170107182415.GO14217@n2100.armlinux.org.uk>

Hi,

On Sat, Jan 07, 2017 at 06:24:15PM +0000, Russell King - ARM Linux wrote:

> As I've said, CONFIG_VECTORS_BASE is _always_ 0xffff0000 on MMU, so
> this always displays 0xffff0000 - 0xffff1000 here.

> Older ARM CPUs without the V bit (ARMv3 and early ARMv4) expect the
> vectors to be at virtual address zero.
> 
> Most of these systems place ROM at physical address 0, so when the CPU
> starts from reset (with the MMU off) it starts executing from ROM.  Once
> the MMU is initialised, RAM can be placed there and the ROM vectors
> replaced.  The side effect of this is that NULL pointer dereferences
> are not always caught... of course, it makes sense that the page at
> address 0 is write protected even from the kernel, so a NULL pointer
> write dereference doesn't corrupt the vectors.
> 
> How we handle it in Linux is that we always map the page for the vectors
> at 0xffff0000, and then only map that same page at 0x00000000 if we have
> a CPU that needs it there.

Thanks for the information, i was not aware, seems that simplifies MMU
case handling.

arch/arm/mm/mmu.c:

	if (!vectors_high()) {
		map.virtual = 0;
		map.length = PAGE_SIZE * 2;
		map.type = MT_LOW_VECTORS;
		create_mapping(&map);
	}



arch/arm/include/asm/cp15.h:

#if __LINUX_ARM_ARCH__ >= 4
#define vectors_high()	(get_cr() & CR_V)
#else
#define vectors_high()	(0)
#endif

Deducing from your reply & above code snippets that for
__LINUX_ARM_ARCH__ >= 4, in all practical cases, vector_high() returns
true

Regards
afzal

^ permalink raw reply

* [PATCH] arm64: do not set dma masks that device connection can't handle
From: Sergei Shtylyov @ 2017-01-08  7:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483713911-2079-1-git-send-email-nikita.yoush@cogentembedded.com>

Hello!

On 1/6/2017 5:45 PM, Nikita Yushchenko wrote:

> It is possible that device is capable of 64-bit DMA addresses, and
> device driver tries to set wide DMA mask, but bridge or bus used to
> connect device to the system can't handle wide addresses.
>
> With swiotlb, memory above 4G still can be used by drivers for streaming
> DMA, but *dev->mask and dev->dma_coherent_mask must still keep values
> that hardware handles physically.
>
> This patch enforces that. Based on original version by
> Arnd Bergmann <arnd@arndb.de>, extended with coherent mask hadnling.
>
> Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
> CC: Arnd Bergmann <arnd@arndb.de>
[...]
> diff --git a/arch/arm64/mm/dma-mapping.c b/arch/arm64/mm/dma-mapping.c
> index 290a84f..09c7900 100644
> --- a/arch/arm64/mm/dma-mapping.c
> +++ b/arch/arm64/mm/dma-mapping.c
> @@ -352,6 +352,31 @@ static int __swiotlb_dma_supported(struct device *hwdev, u64 mask)
>  	return 1;
>  }
>
> +static int __swiotlb_set_dma_mask(struct device *dev, u64 mask)
> +{
> +	/* device is not DMA capable */
> +	if (!dev->dma_mask)
> +		return -EIO;
> +
> +	/* mask is below swiotlb bounce buffer, so fail */
> +	if (!swiotlb_dma_supported(dev, mask))
> +		return -EIO;
> +
> +	/*
> +	 * because of the swiotlb, we can return success for
> +	 * larger masks, but need to ensure that bounce buffers
> +	 * are used above parent_dma_mask, so set that as
> +	 * the effective mask.
> +	 */
> +	if (mask > dev->archdata.parent_dma_mask)
> +		mask = dev->archdata.parent_dma_mask;
> +
> +

    One empty line is enough...

> +	*dev->dma_mask = mask;
> +
> +	return 0;
> +}
> +
>  static struct dma_map_ops swiotlb_dma_ops = {
>  	.alloc = __dma_alloc,
>  	.free = __dma_free,
[...]
> @@ -957,6 +997,18 @@ void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
>  	if (!dev->archdata.dma_ops)
>  		dev->archdata.dma_ops = &swiotlb_dma_ops;
>
> +	/*
> +	 * we don't yet support buses that have a non-zero mapping.
> +	 *  Let's hope we won't need it
> +	 */
> +	WARN_ON(dma_base != 0);
> +
> +	/*
> +	 * Whatever the parent bus can set. A device must not set
> +	 * a DMA mask larger than this.
> +	 */
> +	dev->archdata.parent_dma_mask = size;

    Not 'size - 1'?

> +
>  	dev->archdata.dma_coherent = coherent;
>  	__iommu_setup_dma_ops(dev, dma_base, size, iommu);
>  }

MBR, Sergei

^ permalink raw reply

* [PATCH v2 2/4] linux/const.h: move UL() macro to include/linux/const.h
From: Masahiro Yamada @ 2017-01-08  6:27 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <15496.1483699555@warthog.procyon.org.uk>

Hi.

2017-01-06 19:45 GMT+09:00 David Howells <dhowells@redhat.com>:
> Masahiro Yamada <yamada.masahiro@socionext.com> wrote:
>
>> diff --git a/include/uapi/linux/const.h b/include/uapi/linux/const.h
>> index c872bfd..76fb0f9 100644
>> --- a/include/uapi/linux/const.h
>> +++ b/include/uapi/linux/const.h
>> @@ -1,7 +1,7 @@
>>  /* const.h: Macros for dealing with constants.  */
>>
>> -#ifndef _LINUX_CONST_H
>> -#define _LINUX_CONST_H
>> +#ifndef _UAPI_LINUX_CONST_H
>> +#define _UAPI_LINUX_CONST_H
>
> You need to be very careful doing this.  Some userspace stuff depends on the
> guard macro names on the kernel header files.

Oh...

>>  /* Some constant macros are used in both assembler and
>>   * C code.  Therefore we cannot annotate them always with
>> @@ -21,7 +21,10 @@
>>  #define _AT(T,X)     ((T)(X))
>>  #endif
>>
>> +#define _UL(x)               (_AC(x, UL))
>> +#define _ULL(x)              (_AC(x, ULL))
>
> How likely is this to collide with existing userspace code somewhere?  It
> looks like the sort of thing that could collide with a C library.

Sorry, I do not have enough insight to answer your questions.


Andrew,
If this seems dangerous, please feel free to drop the entire series
because it is not adding any value except some cleanups.



-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Andi Shyti @ 2017-01-08  6:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGTfZH1CuMxhaqPJCzxgF8p39OAu+o0GDJEsh5DVGtU-hqfxvQ@mail.gmail.com>

Hi Chanwoo,

> >> >> >>> +       touchkey at 20 {
> >> >> >>> +               compatible = "samsung,tm2-touchkey";
> >> >> >>> +               reg = <0x20>;
> >> >> >>> +               interrupt-parent = <&gpa3>;
> >> >> >>> +               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> >> >> >>> +               vcc-supply = <&ldo32_reg>;
> >> >> >>> +               vdd-supply = <&ldo33_reg>;
> >> >> >>> +       };
> >> >> >>> +};
> >> >> >>> +
> >> >> >>>  &ldo31_reg {
> >> >> >>>         regulator-name = "TSP_VDD_1.85V_AP";
> >> >> >>>         regulator-min-microvolt = <1850000>;
> >> >>
> >> >> I repiled the touchkey driver against compatible name.
> >> >> Usually, when developing the device driver, we use the specific h/w name
> >> >> but in this patch, the touckey dt node uses the h/w board name instead of
> >> >> original touckhey name.
> >> >
> >> > this should be a device specifically done for the tm2 and we are
> >> > not sure who is the manufacturer of the device. In order to not
> >>
> >> As I knew, this touchkey was made by Cypress semiconductor.
> >> But, for more correct information, you may try to find it.
> >
> > The Android Kernel says that this is the cy8cmbr3xxx. I
> > downloaded the datasheets, but it doesn't have any similarity
> > with the device. Which means that on tm2 we don't the
> > cy8cmbr3xxx bot something else that I even doubt comes from
> > cypress, but I strongly believe it's a dedicated hardware.
> 
> Although this device is a dedicated h/w, you should keep the principal.
> Did you check the schematic document of TM2? The schematic document
> might include the specific device name.
> 
> Sometimes, the downloaded datasheet does not include the
> all of information of device because of confidential information.
> But, I?m not sure. Just it is guess as my experience.
> 
> I want to check the manufacturer and name of device with you
> on next Monday.

Yes, I checked everything, but didn't find the exact device name.

Anyway, let's take this discussion offline and find the correct
way.

Andi

^ permalink raw reply

* [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Chanwoo Choi @ 2017-01-08  6:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170108054504.fssqicmeovufar2r@jack.zhora.eu>

Hi Andi,

2017-01-08 14:45 GMT+09:00 Andi Shyti <andi@etezian.org>:
> Hi Chanwoo,
>
>> >> >>> +       touchkey at 20 {
>> >> >>> +               compatible = "samsung,tm2-touchkey";
>> >> >>> +               reg = <0x20>;
>> >> >>> +               interrupt-parent = <&gpa3>;
>> >> >>> +               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
>> >> >>> +               vcc-supply = <&ldo32_reg>;
>> >> >>> +               vdd-supply = <&ldo33_reg>;
>> >> >>> +       };
>> >> >>> +};
>> >> >>> +
>> >> >>>  &ldo31_reg {
>> >> >>>         regulator-name = "TSP_VDD_1.85V_AP";
>> >> >>>         regulator-min-microvolt = <1850000>;
>> >>
>> >> I repiled the touchkey driver against compatible name.
>> >> Usually, when developing the device driver, we use the specific h/w name
>> >> but in this patch, the touckey dt node uses the h/w board name instead of
>> >> original touckhey name.
>> >
>> > this should be a device specifically done for the tm2 and we are
>> > not sure who is the manufacturer of the device. In order to not
>>
>> As I knew, this touchkey was made by Cypress semiconductor.
>> But, for more correct information, you may try to find it.
>
> The Android Kernel says that this is the cy8cmbr3xxx. I
> downloaded the datasheets, but it doesn't have any similarity
> with the device. Which means that on tm2 we don't the
> cy8cmbr3xxx bot something else that I even doubt comes from
> cypress, but I strongly believe it's a dedicated hardware.

Although this device is a dedicated h/w, you should keep the principal.
Did you check the schematic document of TM2? The schematic document
might include the specific device name.

Sometimes, the downloaded datasheet does not include the
all of information of device because of confidential information.
But, I?m not sure. Just it is guess as my experience.

I want to check the manufacturer and name of device with you
on next Monday.

>
> Now we have two choices:
>
> 1. drop support because we are not 100% sure on the device and
> supplier.
>
> 2. call it Samsung and provide support anyway as, at the end, it
> is a samsung hardware.
>
> With Jaechul we chose option 2.
>
>> > assign the device to the wrong manufacturer, we preferred calling
>> > it Samsung as it is in a Samsung device.
>>
>> As you mentioned, Samsung made not this touchkey device. It is
>> certainly wrong manufacturer. I have not seen to use the h/w board
>> name as the peripheral device name.
>>
>> I don't prefer to use the inaccurate manufacturer and device name.
>
> Eventually, Jaechul can assign the device to cypress, but the
> name has to remain tm2-touchkey. Something like this:
>
>         compatible = "cypress,tm2-touchkey";
>
> What do you think?

If we never to find the correct device name, we might use your suggestion.
As I already said, I?d like to check it again with you.

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Andi Shyti @ 2017-01-08  5:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAGTfZH35sx5v-XcxkDG7TVRmW8cLirAXRxA=kGZQDBnpw3vYhg@mail.gmail.com>

Hi Chanwoo,

> >> >>> +       touchkey at 20 {
> >> >>> +               compatible = "samsung,tm2-touchkey";
> >> >>> +               reg = <0x20>;
> >> >>> +               interrupt-parent = <&gpa3>;
> >> >>> +               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
> >> >>> +               vcc-supply = <&ldo32_reg>;
> >> >>> +               vdd-supply = <&ldo33_reg>;
> >> >>> +       };
> >> >>> +};
> >> >>> +
> >> >>>  &ldo31_reg {
> >> >>>         regulator-name = "TSP_VDD_1.85V_AP";
> >> >>>         regulator-min-microvolt = <1850000>;
> >>
> >> I repiled the touchkey driver against compatible name.
> >> Usually, when developing the device driver, we use the specific h/w name
> >> but in this patch, the touckey dt node uses the h/w board name instead of
> >> original touckhey name.
> >
> > this should be a device specifically done for the tm2 and we are
> > not sure who is the manufacturer of the device. In order to not
> 
> As I knew, this touchkey was made by Cypress semiconductor.
> But, for more correct information, you may try to find it.

The Android Kernel says that this is the cy8cmbr3xxx. I
downloaded the datasheets, but it doesn't have any similarity
with the device. Which means that on tm2 we don't the
cy8cmbr3xxx bot something else that I even doubt comes from
cypress, but I strongly believe it's a dedicated hardware.

Now we have two choices:

1. drop support because we are not 100% sure on the device and
supplier.

2. call it Samsung and provide support anyway as, at the end, it
is a samsung hardware.

With Jaechul we chose option 2.

> > assign the device to the wrong manufacturer, we preferred calling
> > it Samsung as it is in a Samsung device.
> 
> As you mentioned, Samsung made not this touchkey device. It is
> certainly wrong manufacturer. I have not seen to use the h/w board
> name as the peripheral device name.
> 
> I don't prefer to use the inaccurate manufacturer and device name.

Eventually, Jaechul can assign the device to cypress, but the
name has to remain tm2-touchkey. Something like this:

	compatible = "cypress,tm2-touchkey";

What do you think?

Andi

^ permalink raw reply

* [PATCH v5 5/5] arm64: dts: exynos: Add tm2 touchkey node
From: Chanwoo Choi @ 2017-01-08  5:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170107124026.gl447hl5bucdflyk@jack.zhora.eu>

Hi Andi,

2017-01-07 21:40 GMT+09:00 Andi Shyti <andi@etezian.org>:
> Hi Chanwoo,
>
>> >>> +       touchkey at 20 {
>> >>> +               compatible = "samsung,tm2-touchkey";
>> >>> +               reg = <0x20>;
>> >>> +               interrupt-parent = <&gpa3>;
>> >>> +               interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
>> >>> +               vcc-supply = <&ldo32_reg>;
>> >>> +               vdd-supply = <&ldo33_reg>;
>> >>> +       };
>> >>> +};
>> >>> +
>> >>>  &ldo31_reg {
>> >>>         regulator-name = "TSP_VDD_1.85V_AP";
>> >>>         regulator-min-microvolt = <1850000>;
>>
>> I repiled the touchkey driver against compatible name.
>> Usually, when developing the device driver, we use the specific h/w name
>> but in this patch, the touckey dt node uses the h/w board name instead of
>> original touckhey name.
>
> this should be a device specifically done for the tm2 and we are
> not sure who is the manufacturer of the device. In order to not

As I knew, this touchkey was made by Cypress semiconductor.
But, for more correct information, you may try to find it.

> assign the device to the wrong manufacturer, we preferred calling
> it Samsung as it is in a Samsung device.

As you mentioned, Samsung made not this touchkey device. It is
certainly wrong manufacturer. I have not seen to use the h/w board
name as the peripheral device name.

I don't prefer to use the inaccurate manufacturer and device name.

-- 
Best Regards,
Chanwoo Choi

^ permalink raw reply

* imx: RS-485 problems during TX, maybe DMA related
From: Fabio Estevam @ 2017-01-08  2:30 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170107230624.GA21729@archie.localdomain>

Hi Clemens,

On Sat, Jan 7, 2017 at 9:06 PM, Clemens Gruber
<clemens.gruber@pqgruber.com> wrote:

> Just remuxed GPIO signals to these pads, applied your two patches and
> used rts-gpios in the DT but I still see the same problem :/
>
> When transmit something, I get doubled characters, then zeros and at the
> end garbled data of previous transmissions, same as described in my
> first post (Logic analyzer: https://pqgruber.com/rs485_results.png)
> The data is always 4096 bytes long, this explains why the echo command
> is blocking for about 4 seconds (<- 4096 bytes@a baudrate of 9600).
> The TE line is also high until all 4096 bytes are sent.
>
> I think this comes from the UART_XMIT_SIZE which is defined to the page
> size.
> Maybe there is something wrong in imx_transmit_buffer and leads to the
> whole circular buffer being sent out all the time, not stopping..
>
> Do these debug logs tell you anything?
> https://gist.github.com/clemensg/1ac5ee8a8ea32acc9145c5aa8407aea5
>
> I am analyzing the signals coming directly from the i.MX6Q, so this must
> be a software problem, but I don't understand why it works for you, if
> we use the same software.
>
> Do you use any other patches on top of mainline and do you use the SDMA
> scripts from the ROM?

No, I use the original 4.9 + the two patches I sent. Yes, I do use the
SDMA scripts from ROM.

Here is the procedure I did to try to reproduce the issue you reported:

(The rs485conf is available at:
https://github.com/mniestroj/rs485conf/blob/master/main.c )

First of all I enable rs485 for ttymxc3 using the rs485conf application:

root at imx6qsabresd:/home# ./rs485conf  /dev/ttymxc3 -e 1
[   27.106517] random: crng init done
= Current configuration:
RS485 enabled:                false
RTS on send:                  high
RTS after send:               low
RTS delay before send:        0
RTS delay after send:         0
Receive during sending data:  true

= New configuration:
RS485 enabled:                true
RTS on send:                  high
RTS after send:               low
RTS delay before send:        0
RTS delay after send:         0
Receive during sending data:  true

= Saved configuration:
RS485 enabled:                true
RTS on send:                  high
RTS after send:               low
RTS delay before send:        0
RTS delay after send:         0
Receive during sending data:  true
root at imx6qsabresd:/ho

Then

root at imx6qsabresd:/home# echo A > /dev/ttymxc3

(wait 10 seconds)

root at imx6qsabresd:/home# echo B > /dev/ttymxc3

(wait 10 seconds)

root at imx6qsabresd:/home# echo C > /dev/ttymxc3

On the serial console at 9600bps only the:
A
B
C

are seen, so not duplicated characters, nor noise is seen on the console.

Regards,

Fabio Estevam

^ permalink raw reply

* [PATCH 0/4] video: ARM CLCD: add support of an optional GPIO to enable panel
From: Vladimir Zapolskiy @ 2017-01-07 23:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170102142228.GI14217@n2100.armlinux.org.uk>

On 01/02/2017 04:22 PM, Russell King - ARM Linux wrote:
> On Fri, Dec 30, 2016 at 09:23:59AM +0100, Linus Walleij wrote:
>> On Wed, Dec 21, 2016 at 4:27 AM, Vladimir Zapolskiy <vz@mleia.com> wrote:
>>
>>> The changeset contains a number of cleanups, changed semantics of
>>> init_panel() callback, which allows to simplify getting of panel
>>> properties from panel device tree node, and a handling of optional
>>> "enable-gpios" panel property, the latter is described in
>>> display/panel/panel-dpi.txt device tree binding documentation, but
>>> it has been unsupported by the ARM CLCD driver.
>>>
>>> Vladimir Zapolskiy (4):
>>>   video: ARM CLCD: sort included headers out alphabetically
>>>   video: ARM CLCD: use panel device node for panel initialization
>>>   video: ARM CLCD: use panel device node for getting backlight and mode
>>>   video: ARM CLCD: add support of an optional GPIO to enable panel
>>
>> As you may have seen Tomi has stepped down as FBDEV maintainer and
>> this subsystem is now orphaned.
>>
>> I guess Andrew Morton merges patches for it in this case, he usually does.
>>
>> But what we should actually do is create a new DRM driver for CLCD
>> in drivers/gpu/drm/arm/clcd*
>>
>> It's maybe not a small undertaking :(
>>
>> But in case you're interested in the job, I will pitch in and test the result
>> on all ARM reference designs plus Nomadik.
> 
> A DRM driver for it would probably be a good idea, but dealing with all
> the weird and wonderful connection arrangements may not be that easy...
> 

Linus, Russell,

I've immediately encountered a problem while porting the driver to DRM,
because LPC18xx/LPC43xx SoCs are powered by Cortex-M3/M4 cores and DRM
framework has build and runtime dependencies on MMU.

That said, in short term I would expect a continuation of support for
the legacy CLCD framebuffer driver, which works fine on MMU-less SoCs.

--
With best wishes,
Vladimir

^ permalink raw reply

* imx: RS-485 problems during TX, maybe DMA related
From: Clemens Gruber @ 2017-01-07 23:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOMZO5D00YFLS=pddAqPo_FUoP6MF-juAef2H71-Wx_NQArdpw@mail.gmail.com>

Hi Fabio,

On Sat, Jan 07, 2017 at 07:43:48PM -0200, Fabio Estevam wrote:
> Hi Clemens,
> 
> On Sat, Jan 7, 2017 at 6:59 PM, Clemens Gruber
> <clemens.gruber@pqgruber.com> wrote:
> 
> > Great!
> >
> > Did you observe the same effect I described, with the doubling of
> > characters in the front and the leftovers from previous transmissions at
> > the end?
> 
> No, I don't observe these errors when I use 'rts-gpios' in the device tree.
> 
> Maybe you could try to use 'rts-gpios' for a quick test by applying
> the patches I have just sent.
> 
> If you run this test, please remove 'uart-has-rtscts' from your dts.
> According to Documentation/devicetree/bindings/serial/serial.txt they
> are mutually-exclusive.

Just remuxed GPIO signals to these pads, applied your two patches and
used rts-gpios in the DT but I still see the same problem :/

When transmit something, I get doubled characters, then zeros and at the
end garbled data of previous transmissions, same as described in my
first post (Logic analyzer: https://pqgruber.com/rs485_results.png)
The data is always 4096 bytes long, this explains why the echo command
is blocking for about 4 seconds (<- 4096 bytes@a baudrate of 9600).
The TE line is also high until all 4096 bytes are sent.

I think this comes from the UART_XMIT_SIZE which is defined to the page
size.
Maybe there is something wrong in imx_transmit_buffer and leads to the
whole circular buffer being sent out all the time, not stopping..

Do these debug logs tell you anything?
https://gist.github.com/clemensg/1ac5ee8a8ea32acc9145c5aa8407aea5

I am analyzing the signals coming directly from the i.MX6Q, so this must
be a software problem, but I don't understand why it works for you, if
we use the same software.

Do you use any other patches on top of mainline and do you use the SDMA
scripts from the ROM?

Thanks,
Clemens

^ permalink raw reply

* imx: RS-485 problems during TX, maybe DMA related
From: Fabio Estevam @ 2017-01-07 21:43 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170107205930.GA12367@archie.localdomain>

Hi Clemens,

On Sat, Jan 7, 2017 at 6:59 PM, Clemens Gruber
<clemens.gruber@pqgruber.com> wrote:

> Great!
>
> Did you observe the same effect I described, with the doubling of
> characters in the front and the leftovers from previous transmissions at
> the end?

No, I don't observe these errors when I use 'rts-gpios' in the device tree.

Maybe you could try to use 'rts-gpios' for a quick test by applying
the patches I have just sent.

If you run this test, please remove 'uart-has-rtscts' from your dts.
According to Documentation/devicetree/bindings/serial/serial.txt they
are mutually-exclusive.

Regards,

Fabio Estevam

^ permalink raw reply

* [PATCH v3 2/2] ARM: dts: imx6q: Add mccmon6 board support
From: Lukasz Majewski @ 2017-01-07 21:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1483440381-24268-2-git-send-email-lukma@denx.de>

Dear All,

> From: Lukasz Majewski <l.majewski@majess.pl>
> 
> This patch provides support for Liebherr's Monitor 6 board
> (abverrated as mccmon6) to Linux kernel.
> 
> Signed-off-by: Lukasz Majewski <lukma@denx.de>
> ---
> Changes for v3:
> - Reorganize the dts file according to Shawn Guo's comments
> 
> Changes for v2:
> - Reorganize the dts file according to Valdimir Zapolskiy's comments

Do you have any more comments for this DTS file?


Best regards,

Lukasz Majewski

--

DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de

^ permalink raw reply

* imx: RS-485 problems during TX, maybe DMA related
From: Clemens Gruber @ 2017-01-07 20:59 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAOMZO5CY3ys6moE133LwSKcS4egv56JdmhPMRG0TmAnfD+ZBAw@mail.gmail.com>

On Sat, Jan 07, 2017 at 02:48:03PM -0200, Fabio Estevam wrote:
> On Sat, Jan 7, 2017 at 1:34 PM, Clemens Gruber
> <clemens.gruber@pqgruber.com> wrote:
> > Hi Fabio,
> >
> > On Sat, Jan 07, 2017 at 12:57:10PM -0200, Fabio Estevam wrote:
> >> The MX6QDL_PAD_CSI0_DAT16__UART4_CTS_B option is only valid in dte mode.
> >
> > Ah, the input select is limited in that way, I see.
> >
> > You wrote that you tried rts-gpios.
> > What about setting cts-gpios to gpio6 2 in the DT?
> >
> > Or can you remux RX and TX to be switched to work in dte mode?
> 
> I managed to get RS485 in half-duplex working with rts-gios. Will send
> a patch shortly.

Great!

Did you observe the same effect I described, with the doubling of
characters in the front and the leftovers from previous transmissions at
the end?

Thanks,
Clemens

^ permalink raw reply

* [PATCH v2 0/9] Use mmio-sram driver for Keystone MSMC RAM
From: santosh.shilimkar at oracle.com @ 2017-01-07 20:36 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170106215733.41637-1-s-anna@ti.com>

On 1/6/17 1:57 PM, Suman Anna wrote:
> Hi,
>
> The Keystone 2 family of SoCs have an on-chip RAM called the
> Multicore Shared Memory (MSM) RAM. This RAM is accessible through
> the Multicore Shared Memory Controller (MSMC). This series represents
> these on-chip RAMs as sram nodes so that the memory allocations
> can be managed by the in-kernel mmio-sram driver.
>
> This is v2 of the previous series [1], and now includes 4 additional
> patches that reserve the portions of the MSMC RAM used by the
> Keystone Boot Monitor. The first 5 patches are essentially the same
> as in v1, with minor commit description updates for using the proper
> SoC names, but no code changes.
>
> Patches baselined on 4.10-rc1.
>
Applied. Should start showing up next soon. thanks !!

Regards,
Santosh

^ permalink raw reply

* [PATCHv2 net-next 11/16] net: mvpp2: handle misc PPv2.1/PPv2.2 differences
From: Russell King - ARM Linux @ 2017-01-07 20:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20170107093834.GJ14217@n2100.armlinux.org.uk>

On Sat, Jan 07, 2017 at 09:38:34AM +0000, Russell King - ARM Linux wrote:
> On Wed, Dec 28, 2016 at 05:46:27PM +0100, Thomas Petazzoni wrote:
> > @@ -6511,7 +6515,9 @@ static int mvpp2_port_probe(struct platform_device *pdev,
> >  		dev_err(&pdev->dev, "failed to init port %d\n", id);
> >  		goto err_free_stats;
> >  	}
> > -	mvpp2_port_power_up(port);
> > +
> > +	if (priv->hw_version == MVPP21)
> > +		mvpp21_port_power_up(port);
> 
> This has the side effect that nothing clears the port reset bit in the
> GMAC, which means there's no hope of the interface working - with the
> reset bit set, the port is well and truely held in "link down" state.
> 
> In any case, the GMAC part is much the same as mvneta, and I think
> that code should be shared rather than writing new versions of it.
> There are some subtle differences between neta, pp2.1 and pp2.2, but
> it's entirely doable (I have an implementation here as I wasn't going
> to duplicate this code for my phylink conversion.)

In addition to comphy configuration and the above, I also need the
following to have working SGMII.  The change of MACMODE is needed
because uboot has configured the port for 10Gbase-R mode (it has a
10G PHY on it, but the PHY switches to SGMII in <10G modes.)  The
GMAC control register 4 is needed to properly configure for SGMII
mode.  I also included RGMII mode as well in there, as I expect you'd
need it to have GMAC properly configured for RGMII.

With this in place (and the other bits mentioned above), I can ping
the clearfog switch on the other end of eth0's cable:

# ping6 -I eth0 fe80::250:43ff:fe02:302
PING fe80::250:43ff:fe02:302(fe80::250:43ff:fe02:302) from fe80::200:ff:fe00:1 eth0: 56 data bytes
64 bytes from fe80::250:43ff:fe02:302: icmp_seq=1 ttl=64 time=0.297 ms

diff --git a/drivers/net/ethernet/marvell/mvpp2.c b/drivers/net/ethernet/marvell/mvpp2.c
index bc97eebf7eee..4b6ec6213e9c 100644
--- a/drivers/net/ethernet/marvell/mvpp2.c
+++ b/drivers/net/ethernet/marvell/mvpp2.c
@@ -345,7 +345,17 @@
 #define      MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK	0x1fc0
 #define      MVPP2_GMAC_TX_FIFO_MIN_TH_MASK(v)	(((v) << 6) & \
 					MVPP2_GMAC_TX_FIFO_MIN_TH_ALL_MASK)
+#define MVPP22_GMAC_CTRL_4_REG			0x90
+#define      MVPP22_CTRL4_EXT_PIN_GMII_SEL	BIT(0)
+#define      MVPP22_CTRL4_DP_CLK_SEL		BIT(5)
+#define      MVPP22_CTRL4_SYNC_BYPASS		BIT(6)
+#define      MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE	BIT(7)
+
+#define MVPP22_XLG_CTRL3_REG			0x11c
+#define      MVPP22_XLG_CTRL3_MACMODESELECT_MASK	(7 << 13)
+#define      MVPP22_XLG_CTRL3_MACMODESELECT_GMAC	(0 << 13)
 
+/* offsets from iface_base */
 #define MVPP22_SMI_MISC_CFG_REG			0x2a204
 #define      MVPP22_SMI_POLLING_EN		BIT(10)
 
@@ -4171,6 +4181,23 @@ static void mvpp2_port_mii_set(struct mvpp2_port *port)
 {
 	u32 val;
 
+	if (port->priv->hw_version == MVPP22) {
+		val = readl(port->base + MVPP22_XLG_CTRL3_REG);
+		val &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;
+		val |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
+		writel(val, port->base + MVPP22_XLG_CTRL3_REG);
+
+		val = readl(port->base + MVPP22_GMAC_CTRL_4_REG);
+		if (port->phy_interface == PHY_INTERFACE_MODE_RGMII)
+			val |= MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+		else
+			val &= ~MVPP22_CTRL4_EXT_PIN_GMII_SEL;
+		val &= ~MVPP22_CTRL4_DP_CLK_SEL;
+		val |= MVPP22_CTRL4_SYNC_BYPASS;
+		val |= MVPP22_CTRL4_QSGMII_BYPASS_ACTIVE;
+		writel(val, port->base + MVPP22_GMAC_CTRL_4_REG);
+	}
+
 	val = readl(port->base + MVPP2_GMAC_CTRL_2_REG);
 
 	switch (port->phy_interface) {


-- 
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.

^ permalink raw reply related


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