Devicetree
 help / color / mirror / Atom feed
* Re: [RFC 1/3] iommu/arm-smmu: Add support to opt-in to stalling
From: Robin Murphy @ 2017-01-05 17:03 UTC (permalink / raw)
  To: Will Deacon
  Cc: Mark Rutland, robh-DgEjT+Ai2ygdnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Jordan Crouse
In-Reply-To: <20170105160755.GN679-5wv7dgnIgG8@public.gmane.org>

On 05/01/17 16:07, Will Deacon wrote:
> On Thu, Jan 05, 2017 at 03:32:50PM +0000, Robin Murphy wrote:
>> On 05/01/17 14:47, Will Deacon wrote:
>>> On Thu, Jan 05, 2017 at 02:07:31PM +0000, Mark Rutland wrote:
>>>> Ok. It would be good to elaborate on what "stalling is useable" means in
>>>> the property description. i.e. what specificallty the implementation and
>>>> integration need to ensure.
>>>
>>> We can describe some of those guarantees in the property description, but
>>> it's difficult to enumerate them exhaustively. For example, you wouldn't
>>> want stalling to lead to data corruption, denial of service, or for the
>>> thing to catch fire, but having those as explicit requirements is a bit
>>> daft. It's also impossible to check that you thought of everything.
>>>
>>> Aside from renaming the option, I'm really after an opinion on whether
>>> it's better to have one property or combine it with the compatible
>>> string, because I can see benefits of both and don't much care either
>>> way.
>>
>> The SMMU implementation side of the decision (i.e. independence of IRQ
>> assertion vs. SS) seems like exactly the sort of stuff the compatible
>> string already has covered. The integration side I'm less confident can
>> be described this way at all - the "this device definitely won't go
>> wrong if stalled for an indefinite length of time" is inherently a
>> per-master thing, so a single property on the SMMU implying that for
>> every device connected to it seems a bit optimistic, and breaks down as
>> soon as you have one device in the system for which that isn't true (a
>> PCI root complex, say), even if that guy's traffic never crosses paths
>> with whichever few devices you actually care about using stalls with.
>>
>> I think this needs to be some kind of "arm,smmu-stall-safe" property
>> placed on individual master device nodes (mad idea: or even an extra
>> cell of flags in the IOMMU specifier) to encapsulate both that the given
>> device itself is OK with being stalled, and that it's integrated in such
>> a way that its stalled transactions cannot disrupt any *other* device
>> (e.g. it has a TBU all to itself). Then upon initialising a context bank
>> on a suitable SMMU implementation, we set CFCFG based on whatever device
>> is being attached to the corresponding domain, and refuse any subsequent
>> attempts to attach a non-stallable device to a stalling domain (and
>> possibly even vice-versa).
> 
> If we're going to add per-master properties, I'd *really* like them to be
> independent of the IOMMU in use. That is, we should be able to re-use this
> property as part of supporting SVM for platform devices in future.

I'd argue that they are still fairly separate things despite the
overlap: stalling is a specific ARM SMMU architecture thing (in both
architectures) which may be used for purposes unrelated to SVM;
conversely SVM implemented via PRI or similar mechanisms should be
pretty much oblivious to the transaction fault model.

> But I think we agree that we need:
> 
>   1. A compatible string for the SMMU that can be used to infer the SS
>      behaviour in the driver
> 
>   2. A property on the SMMU to say that it's been integrated in such a
>      way that stalling is safe (doesn't deadlock)

That's still got to be a per-master property, not a SMMU property, I
think. To illustrate:

  [A]         [B]   [C]
   |           |_____|
 __|______________|___
| TBU |        | TBU |
|_____|  SMMU  |_____|
|__|______________|__|
   |              |

Say A and B are instances of some device happy to be stalled, and C is a
PCIe RC, and each is attached to their own context bank - enabling
stalls for A is definitely fine. However even though B and C are using
different context banks, enabling stalls for B might deadlock C if it
results in more total outstanding transactions than the TBU's slave port
supports. Therefore A can happily claim to be stall-safe, but B cannot
due to its integration with respect to C.

And yes, I can point you at some existing hardware which really does
posess a topology like that.

>   3. A generic master property that says that the device can DMA to
>      unpinned memory

That sounds a bit *too* generic to me, given that there are multiple
incompatible ways that could be implemented. I'm not the biggest fan of
properties with heavily context-specific interpretations, especially
when there's more than a hint of software implementation details in the mix.

Robin.

> 
> Anything else?
> 
> Will
> 

^ permalink raw reply

* Re: [PATCH v2 4/4] ARM: dts: keystone: Add "ti, da830-uart" compatible string
From: Santosh Shilimkar @ 2017-01-05 17:10 UTC (permalink / raw)
  To: Sekhar Nori, David Lechner, Greg Kroah-Hartman, Santosh Shilimkar
  Cc: Mark Rutland, devicetree, Axel Haslam, Kevin Hilman, linux-kernel,
	Bartosz Golaszewski, Rob Herring, Alexandre Bailon, linux-serial,
	Jiri Slaby, Franklin S Cooper Jr, linux-arm-kernel
In-Reply-To: <824238e0-b710-7146-b67b-b2135c2a8bd2@ti.com>

On 1/5/2017 1:04 AM, Sekhar Nori wrote:
> Hi Santosh,
>
> On Thursday 05 January 2017 03:30 AM, Santosh Shilimkar wrote:
>> On 1/4/2017 12:30 PM, David Lechner wrote:
>>> The TI Keystone SoCs have extra UART registers beyond the standard 8250
>>> registers, so we need a new compatible string to indicate this. Also, at
>>> least one of these registers uses the full 32 bits, so we need to specify
>>> reg-io-width in addition to reg-shift.
>>>
>>> "ns16550a" is left in the compatible specification since it does work as
>>> long as the bootloader configures the SoC UART power management
>>> registers.
>>>
>> NAK!!
>> We can't break the booting boards with existing boot loaders.
>
> Sorry, but it not clear to me how this breaks booting with older
> bootloaders? If older DTB is ROM'ed, it will continue to work because of
> match with ns16550a.
>
> I just verified boot on K2E with these patches applied and using 2016.05
> based U-Boot from a TI release.
>
> http://pastebin.ubuntu.com/23744719/
>
Thanks for test. As long as it doesn't break the boot, am fine
with it.

>> I suggest you to first get the driver updated to take care of
>> the UART PM register and then enable the support for it.
>
> Isn't that what patch 2/4 is doing?
>
I see that now. Thanks for clarifying.

Serial patch needs to go via Greg's tree. I will pick up the
DTS bits.

Regards,
Santosh

^ permalink raw reply

* Re: [PATCH 2/2] media: rc: add driver for IR remote receiver on MT7623 SoC
From: Sean Young @ 2017-01-05 17:12 UTC (permalink / raw)
  To: sean.wang
  Cc: mark.rutland, devicetree, ivo.g.dimitrov.75, keyhaede, mchehab,
	linux-kernel, andi.shyti, hverkuil, hdegoede, robh+dt,
	linux-mediatek, matthias.bgg, linux-media, linux-arm-kernel,
	hkallweit1
In-Reply-To: <1483632384-8107-3-git-send-email-sean.wang@mediatek.com>

Hi Sean,

Some review comments.

On Fri, Jan 06, 2017 at 12:06:24AM +0800, sean.wang@mediatek.com wrote:
> From: Sean Wang <sean.wang@mediatek.com>
> 
> This patch adds driver for IR controller on
> Mediatek MT7623 SoC. Currently testing successfully
> on NEC and SONY remote controller only but it should
> work on others (lirc, rc-5 and rc-6).
> 
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> ---
>  drivers/media/rc/Kconfig   |  10 ++
>  drivers/media/rc/Makefile  |   1 +
>  drivers/media/rc/mtk-cir.c | 319 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 330 insertions(+)
>  create mode 100644 linux-4.8.rc1_p0/drivers/media/rc/mtk-cir.c
> 
> diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
> index 370e16e..626c500 100644
> --- a/drivers/media/rc/Kconfig
> +++ b/drivers/media/rc/Kconfig
> @@ -389,4 +389,14 @@ config IR_SUNXI
>  	   To compile this driver as a module, choose M here: the module will
>  	   be called sunxi-ir.
>  
> +config IR_MTK
> +	tristate "Mediatek IR remote control"
> +	depends on RC_CORE
> +	depends on ARCH_MEDIATEK || COMPILE_TEST
> +	---help---
> +	   Say Y if you want to use Mediatek internal IR Controller
> +
> +	   To compile this driver as a module, choose M here: the module will
> +	   be called mtk-cir.
> +
>  endif #RC_DEVICES
> diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
> index 379a5c0..505908d 100644
> --- a/drivers/media/rc/Makefile
> +++ b/drivers/media/rc/Makefile
> @@ -37,3 +37,4 @@ obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
>  obj-$(CONFIG_RC_ST) += st_rc.o
>  obj-$(CONFIG_IR_SUNXI) += sunxi-cir.o
>  obj-$(CONFIG_IR_IMG) += img-ir/
> +obj-$(CONFIG_IR_MTK) += mtk-cir.o
> diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
> new file mode 100644
> index 0000000..4fa4cab
> --- /dev/null
> +++ b/drivers/media/rc/mtk-cir.c
> @@ -0,0 +1,319 @@
> +/*
> + * Driver for Mediatek MT7623 IR Receiver Controller
> + *
> + * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation; either version 2 of
> + * the License, or (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/module.h>
> +#include <linux/of_platform.h>
> +#include <linux/reset.h>
> +#include <media/rc-core.h>
> +
> +#define MTK_IR_DEV "mtk-ir"

KBUILD_MODNAME could be used instead. Currently the module is called
mtk-cir but the rc device will have driver name mtk-ir.

> +
> +/* Register to enable PWM and IR */
> +#define MTK_CONFIG_HIGH_REG       0x0c
> +/* Enable IR pulse width detection */
> +#define MTK_PWM_EN		  BIT(13)
> +/* Enable IR hardware function */
> +#define MTK_IR_EN		  BIT(0)
> +
> +/* Register to setting sample period */
> +#define MTK_CONFIG_LOW_REG        0x10
> +/* Field to set sample period */
> +#define CHK_PERIOD		  0xC00
> +#define MTK_CHK_PERIOD            (((CHK_PERIOD) << 8) & (GENMASK(20, 8)))
> +#define MTK_CHK_PERIOD_MASK	  (GENMASK(20, 8))
> +
> +/* Register to clear state of state machine */
> +#define MTK_IRCLR_REG             0x20
> +/* Bit to restart IR receiving */
> +#define MTK_IRCLR		  BIT(0)
> +
> +/* Register containing pulse width data */
> +#define MTK_CHKDATA_REG(i)        (0x88 + 4 * i)
> +
> +/* Register to enable IR interrupt */
> +#define MTK_IRINT_EN_REG          0xcc
> +/* Bit to enable interrupt */
> +#define MTK_IRINT_EN		  BIT(0)
> +
> +/* Register to ack IR interrupt */
> +#define MTK_IRINT_CLR_REG         0xd0
> +/* Bit to clear interrupt status */
> +#define MTK_IRINT_CLR		  BIT(0)
> +
> +/* Number of registers to record the pulse width */
> +#define MTK_CHKDATA_SZ		  17
> +/* Required frequency */
> +#define MTK_IR_BASE_CLK		  273000000
> +/* Frequency after IR internal divider */
> +#define MTK_IR_CLK		  (MTK_IR_BASE_CLK / 4)
> +/* Sample period in ns */
> +#define MTK_IR_SAMPLE		  (((1000000000ul / MTK_IR_CLK) * CHK_PERIOD))
> +/* Indicate the end of IR data*/
> +#define MTK_IR_END(v)		  (v == 0xff)
> +
> +/* struct mtk_ir -	This is the main datasructure for holding the state
> + *			of the driver
> + * @dev:		The device pointer
> + * @ir_lock:		Make sure that synchronization between remove and ISR
> + * @rc:			The rc instrance
> + * @base:		The mapped register i/o base
> + * @irq:		The IRQ that we are using
> + * @clk:		The clock that we are using
> + * @map_name:		The name for keymap lookup
> + */
> +struct mtk_ir {
> +	struct device   *dev;
> +	/*Protect concurrency between driver removal and ISR*/
> +	spinlock_t      ir_lock;
> +	struct rc_dev   *rc;
> +	void __iomem    *base;
> +	int             irq;
> +	struct clk      *clk;
> +	const char      *map_name;

irq and map_name don't need to be stored here, they're only used in 
mtk_ir_probe.

> +};
> +
> +static void mtk_w32_mask(struct mtk_ir *ir, u32 val, u32 mask, unsigned int reg)
> +{
> +	u32 tmp;
> +
> +	tmp = __raw_readl(ir->base + reg);
> +	tmp = (tmp & ~mask) | val;
> +	__raw_writel(tmp, ir->base + reg);
> +}
> +
> +static void mtk_w32(struct mtk_ir *ir, u32 val, unsigned int reg)
> +{
> +	__raw_writel(val, ir->base + reg);
> +}
> +
> +static u32 mtk_r32(struct mtk_ir *ir, unsigned int reg)
> +{
> +	return __raw_readl(ir->base + reg);
> +}
> +
> +static inline void mtk_irq_disable(struct mtk_ir *ir, u32 mask)
> +{
> +	u32 val;
> +
> +	val = mtk_r32(ir, MTK_IRINT_EN_REG);
> +	mtk_w32(ir, val & ~mask, MTK_IRINT_EN_REG);
> +}
> +
> +static inline void mtk_irq_enable(struct mtk_ir *ir, u32 mask)
> +{
> +	u32 val;
> +
> +	val = mtk_r32(ir, MTK_IRINT_EN_REG);
> +	mtk_w32(ir, val | mask, MTK_IRINT_EN_REG);
> +}
> +
> +static irqreturn_t mtk_ir_irq(int irqno, void *dev_id)
> +{
> +	struct mtk_ir *ir = dev_id;
> +	u8  wid = 0;
> +	u32 i, j, val;
> +	DEFINE_IR_RAW_EVENT(rawir);
> +
> +	spin_lock(&ir->ir_lock);
> +
> +	mtk_irq_disable(ir, MTK_IRINT_EN);
> +
> +	/* Reset decoder state machine */
> +	ir_raw_event_reset(ir->rc);
> +
> +	/* First message must be pulse */
> +	rawir.pulse = false;
> +
> +	/* Handle pulse and space until end of message */
> +	for (i = 0 ; i < MTK_CHKDATA_SZ ; i++) {
> +		val = mtk_r32(ir, MTK_CHKDATA_REG(i));
> +		dev_dbg(ir->dev, "@reg%d=0x%08x\n", i, val);
> +
> +		for (j = 0 ; j < 4 ; j++) {
> +			wid = (val & (0xff << j * 8)) >> j * 8;
> +			rawir.pulse = !rawir.pulse;
> +			rawir.duration = wid * (MTK_IR_SAMPLE + 1);
> +			ir_raw_event_store_with_filter(ir->rc, &rawir);
> +
> +			if (MTK_IR_END(wid))
> +				goto end_msg;
> +		}
> +	}

If I read this correctly, there is a maximum of 17 * 4 = 68 edges per
IR message. The rc6 mce key 0 (scancode 0x800f0400) is 69 edges, so that
won't work.

> +end_msg:
> +	/* Restart the next receive */
> +	mtk_w32_mask(ir, 0x1, MTK_IRCLR, MTK_IRCLR_REG);
> +
> +	ir_raw_event_set_idle(ir->rc, true);
> +	ir_raw_event_handle(ir->rc);
> +
> +	/* Clear interrupt status */
> +	mtk_w32_mask(ir, 0x1, MTK_IRINT_CLR, MTK_IRINT_CLR_REG);
> +
> +	/* Enable interrupt */
> +	mtk_irq_enable(ir, MTK_IRINT_EN);
> +
> +	spin_unlock(&ir->ir_lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static int mtk_ir_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct device_node *dn = dev->of_node;
> +	struct resource *res;
> +	struct mtk_ir *ir;
> +	u32 val;
> +	int ret = 0;
> +
> +	ir = devm_kzalloc(dev, sizeof(struct mtk_ir), GFP_KERNEL);
> +	if (!ir)
> +		return -ENOMEM;
> +
> +	spin_lock_init(&ir->ir_lock);
> +
> +	ir->dev = dev;
> +
> +	if (!of_device_is_compatible(dn, "mediatek,mt7623-ir"))
> +		return -ENODEV;
> +
> +	ir->clk = devm_clk_get(dev, "clk");
> +	if (IS_ERR(ir->clk)) {
> +		dev_err(dev, "failed to get a ir clock.\n");
> +		return PTR_ERR(ir->clk);
> +	}
> +
> +	if (clk_prepare_enable(ir->clk)) {
> +		dev_err(dev, "try to enable ir_clk failed\n");
> +		ret = -EINVAL;
> +		goto exit_clkdisable_clk;
> +	}
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	ir->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(ir->base)) {
> +		dev_err(dev, "failed to map registers\n");
> +		ret = PTR_ERR(ir->base);
> +		goto exit_clkdisable_clk;
> +	}
> +
> +	ir->rc = rc_allocate_device();
> +	if (!ir->rc) {
> +		dev_err(dev, "failed to allocate device\n");
> +		ret = -ENOMEM;
> +		goto exit_clkdisable_clk;
> +	}
> +
> +	ir->rc->priv = ir;
> +	ir->rc->input_name = MTK_IR_DEV;
> +	ir->rc->input_phys = "mtk-ir/input0";
> +	ir->rc->input_id.bustype = BUS_HOST;
> +	ir->rc->input_id.vendor = 0x0001;
> +	ir->rc->input_id.product = 0x0001;
> +	ir->rc->input_id.version = 0x0001;
> +	ir->map_name = of_get_property(dn, "linux,rc-map-name", NULL);
> +	ir->rc->map_name = ir->map_name ?: RC_MAP_EMPTY;
> +	ir->rc->dev.parent = dev;
> +	ir->rc->driver_type = RC_DRIVER_IR_RAW;
> +	ir->rc->driver_name = MTK_IR_DEV;
> +	ir->rc->allowed_protocols = RC_BIT_ALL;
> +	ir->rc->rx_resolution = MTK_IR_SAMPLE;
> +
> +	ret = rc_register_device(ir->rc);
> +	if (ret) {
> +		dev_err(dev, "failed to register rc device\n");
> +		goto exit_free_dev;
> +	}
> +
> +	platform_set_drvdata(pdev, ir);
> +
> +	ir->irq = platform_get_irq(pdev, 0);
> +	if (ir->irq < 0) {
> +		dev_err(dev, "no irq resource\n");
> +		ret = ir->irq;

>From here on onwards the errors paths should call rc_unregister_device(),
and no longer call rc_free_device(). Note that current master has
devm_rc_allocate_device() and devm_rc_register_device() which would
simplify this code.

> +		goto exit_free_dev;
> +	}
> +
> +	ret = devm_request_irq(dev, ir->irq, mtk_ir_irq, 0, MTK_IR_DEV, ir);
> +	if (ret) {
> +		dev_err(dev, "failed request irq\n");
> +		goto exit_free_dev;
> +	}
> +
> +	mtk_irq_disable(ir, MTK_IRINT_EN);
> +
> +	val = mtk_r32(ir, MTK_CONFIG_HIGH_REG);
> +	val |= MTK_PWM_EN | MTK_IR_EN;
> +	mtk_w32(ir, val, MTK_CONFIG_HIGH_REG);
> +
> +	/* Setting sample period */
> +	mtk_w32_mask(ir, MTK_CHK_PERIOD, MTK_CHK_PERIOD_MASK,
> +		     MTK_CONFIG_LOW_REG);
> +
> +	mtk_irq_enable(ir, MTK_IRINT_EN);
> +
> +	dev_info(dev, "initialized MT7623 IR driver\n");
> +	return 0;
> +
> +exit_free_dev:
> +	rc_free_device(ir->rc);
> +exit_clkdisable_clk:
> +	clk_disable_unprepare(ir->clk);
> +
> +	return ret;
> +}
> +
> +static int mtk_ir_remove(struct platform_device *pdev)
> +{
> +	unsigned long flags;
> +
> +	struct mtk_ir *ir = platform_get_drvdata(pdev);
> +
> +	spin_lock_irqsave(&ir->ir_lock, flags);
> +
> +	mtk_irq_disable(ir, MTK_IRINT_EN);
> +
> +	clk_disable_unprepare(ir->clk);
> +
> +	spin_unlock_irqrestore(&ir->ir_lock, flags);

I'm not convinced the ir_lock is helping to prevent any race condition. An
irq might still already have occurred which will now try to use ir->rc 
which is freed. You can remove the spinlock completely and call 
sychronize_irq() after disabling the mtk interrupt. That way you're sure
the remove is safe to complete.

> +
> +	rc_unregister_device(ir->rc);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id mtk_ir_match[] = {
> +	{ .compatible = "mediatek,mt7623-ir" },
> +	{},
> +};
> +MODULE_DEVICE_TABLE(of, mtk_ir_match);
> +
> +static struct platform_driver mtk_ir_driver = {
> +	.probe          = mtk_ir_probe,
> +	.remove         = mtk_ir_remove,
> +	.driver = {
> +		.name = MTK_IR_DEV,
> +		.of_match_table = mtk_ir_match,
> +	},
> +};
> +
> +module_platform_driver(mtk_ir_driver);
> +
> +MODULE_DESCRIPTION("Mediatek MT7623 IR Receiver Controller Driver");
> +MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
> +MODULE_LICENSE("GPL");
> -- 
> 1.9.1
> 

^ permalink raw reply

* Re: [PATCH] ARM: dts: sunxi: Use axp209.dtsi for Olinuxino Lime2
From: Maxime Ripard @ 2017-01-05 17:14 UTC (permalink / raw)
  To: Emmanuel Vadot
  Cc: mark.rutland, devicetree, linux, linux-kernel, wens, robh+dt,
	linux-arm-kernel
In-Reply-To: <20161227102238.20110-1-manu@bidouilliste.com>


[-- Attachment #1.1: Type: text/plain, Size: 736 bytes --]

On Tue, Dec 27, 2016 at 11:22:38AM +0100, Emmanuel Vadot wrote:
> Use axp209.dtsi in sun7i-a20-olinuxino-lime2.dts and correct
> some regulators.
> 
> DCDC2 is used for vdd-cpu so it should never be bellow 1V and above 1.4V
> DCDC3 is used for VDD_INT so same as above.
> LD01 is used for the RTC, and should have a typical value of 1.3V
> LD02 is used for AVCC and should have a typical value of 3.0V
> LD03/4 are used for Port-E/Port-G Power pin, and the schematics recommands
> to set them to 2.8V as they can be used for CSI0/1.
> 
> Signed-off-by: Emmanuel Vadot <manu@bidouilliste.com>

Applied, thanks!
Maxime

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH v3] ARM: dts: sunxi: Add num-cs for A20 spi nodes
From: Maxime Ripard @ 2017-01-05 17:14 UTC (permalink / raw)
  To: Emmanuel Vadot
  Cc: mark.rutland, devicetree, linux, linux-kernel, wens, robh+dt,
	linux-arm-kernel
In-Reply-To: <20161227102807.20244-1-manu@bidouilliste.com>


[-- Attachment #1.1: Type: text/plain, Size: 523 bytes --]

On Tue, Dec 27, 2016 at 11:28:07AM +0100, Emmanuel Vadot wrote:
> The spi0 controller on the A20 have up to 4 CS (Chip Select) while the
> others three only have 1.
> Add the num-cs property to each node.
> The current driver doesn't read this property but this is useful for
> downstream user of DTS (FreeBSD for example).
> 
> Signed-off-by: Emmanuel Vadot <manu@bidouilliste.com>

Applied, thanks!
Maxime

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] ARM: dts: sunxi: Enable spi1 and spi2 for Olimex A20 SOM EVB
From: Maxime Ripard @ 2017-01-05 17:16 UTC (permalink / raw)
  To: Emmanuel Vadot
  Cc: mark.rutland, devicetree, linux, linux-kernel, wens, robh+dt,
	linux-arm-kernel
In-Reply-To: <20161226175349.17712-1-manu@bidouilliste.com>


[-- Attachment #1.1: Type: text/plain, Size: 1084 bytes --]

Hi,

On Mon, Dec 26, 2016 at 06:53:49PM +0100, Emmanuel Vadot wrote:
> Enable the spi1 and spi2 node since the pins are exposed on the UEXT
> connectors.
> 
> Signed-off-by: Emmanuel Vadot <manu@bidouilliste.com>
> ---
>  arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> index 669a1c338c76..fa8c6f60552b 100644
> --- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> +++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> @@ -300,12 +300,14 @@
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&spi1_pins_a>,
>  		    <&spi1_cs0_pins_a>;
> +	status = "okay";
>  };
>  
>  &spi2 {
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&spi2_pins_a>,
>  		    <&spi2_cs0_pins_a>;
> +	status = "okay";
>  };

Those nodes don't exist unfortunately. Maybe you forgot to send one
patch?

Thanks!
Maxime

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

[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 801 bytes --]

[-- Attachment #2: Type: text/plain, Size: 176 bytes --]

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/6] ARM: dts: am335x-phycore-som: Update NAND partition table
From: Tony Lindgren @ 2017-01-05 17:18 UTC (permalink / raw)
  To: Teresa Remmet
  Cc: Mark Rutland, devicetree, Brian Norris, Rob Herring,
	Benoît Cousson, linux-omap, Adam Ford, linux-arm-kernel
In-Reply-To: <20170105153637.GA4310@atomide.com>

* Tony Lindgren <tony@atomide.com> [170105 07:37]:
> * Teresa Remmet <t.remmet@phytec.de> [170105 06:57]:
> > To improve NAND safety we updated the partition layout.
> > Added barebox backup partition and removed kernel and oftree
> > partition. They are kept in ubi now.
> 
> What about the users with earlier partition tables?
> 
> Please read about "flag day" changes, typically they are not
> acceptable.

Adding Brian and Adam to Cc. Can you guys come up with some
solution on this?

I'm suggesting we leave the kernel nodes empty and let u-boot
populate them, so maybe you guys can discuss this on the related
lists.

The rest of the series looks fine to me so applying it into
omap-for-v4.11/dt.

Cheers,

Tony

^ permalink raw reply

* [PATCH] i2c: core: helper function to detect slave mode
From: Luis Oliveira @ 2017-01-05 17:24 UTC (permalink / raw)
  To: wsa-z923LK4zBo2bacvFa/9K2g, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, jarkko.nikula-VuQAYsv1563Yd54FQh9/CA,
	andriy.shevchenko-VuQAYsv1563Yd54FQh9/CA,
	mika.westerberg-VuQAYsv1563Yd54FQh9/CA,
	linux-i2c-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
  Cc: Luis.Oliveira-HKixBCOQz3hWk0Htik3J/w,
	Ramiro.Oliveira-HKixBCOQz3hWk0Htik3J/w,
	Joao.Pinto-HKixBCOQz3hWk0Htik3J/w,
	CARLOS.PALMINHA-HKixBCOQz3hWk0Htik3J/w

This function has the purpose of mode detection by checking the
device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag.
Currently only checks using OF functions (ACPI slave not supported yet).

Signed-off-by: Luis Oliveira <lolivei-HKixBCOQz3hWk0Htik3J/w@public.gmane.org>
---
Due to the need of checking if the I2C slave address is our own (in 
other words: if we are the I2C slave) I created a helper function 
(proposed to me by @Andy) to enable that check. 
Currently (because I am not able to test it using ACPI) it only 
supports devicetree declarations.

 drivers/i2c/i2c-core.c | 19 +++++++++++++++++++
 include/linux/i2c.h    |  1 +
 2 files changed, 20 insertions(+)

diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 3de95a29024c..48e705b23c59 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -3691,6 +3691,25 @@ int i2c_slave_unregister(struct i2c_client *client)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(i2c_slave_unregister);
+
+int i2c_slave_mode_detect(struct device *dev)
+{
+	struct device_node *child;
+	u32 reg;
+
+	if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
+		for_each_child_of_node(dev->of_node, child) {
+			of_property_read_u32(child, "reg", &reg);
+			if (reg & I2C_OWN_SLAVE_ADDRESS)
+				return 1;
+		}
+	} else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
+		dev_dbg(dev, "ACPI slave is not supported yet\n");
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(i2c_slave_mode_detect);
+
 #endif
 
 MODULE_AUTHOR("Simon G. Vogl <simon-nD9nYVNVf00W+b/DJNNodF6hYfS7NtTn@public.gmane.org>");
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index b2109c522dec..53cf99569af5 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -282,6 +282,7 @@ enum i2c_slave_event {
 
 extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
 extern int i2c_slave_unregister(struct i2c_client *client);
+extern int i2c_slave_mode_detect(struct device *dev);
 
 static inline int i2c_slave_event(struct i2c_client *client,
 				  enum i2c_slave_event event, u8 *val)
-- 
2.11.0


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* [PATCH v2] iio:temperature: Add support for TI TMP007 sensor
From: Mani Sadhasivam @ 2017-01-05 17:24 UTC (permalink / raw)
  To: jic23-DgEjT+Ai2ygdnm+yROfE0A, pmeerw-jW+XmwGofnusTnJN9+BGXg
  Cc: linux-iio-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

This patch adds support for TI TMP007 - 16 bit IR thermopile sensor with integrated Math engine.
Sensor takes care of calculating the object temperature with the help of calibrated constants stored in non-volatile memory,
reducing the calculation overhead.

Signed-off-by: Mani Sadhasivam <manivannanece23-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
---
 .../devicetree/bindings/iio/temperature/tmp007.txt |  16 +
 drivers/iio/temperature/Kconfig                    |  10 +
 drivers/iio/temperature/Makefile                   |   1 +
 drivers/iio/temperature/tmp007.c                   | 338 +++++++++++++++++++++
 4 files changed, 365 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/temperature/tmp007.txt
 create mode 100644 drivers/iio/temperature/tmp007.c

diff --git a/Documentation/devicetree/bindings/iio/temperature/tmp007.txt b/Documentation/devicetree/bindings/iio/temperature/tmp007.txt
new file mode 100644
index 0000000..9ae0519
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/temperature/tmp007.txt
@@ -0,0 +1,16 @@
+* TI TMP007 - IR thermopile sensor with integrated math engine
+
+Link to datasheet: http://www.ti.com/lit/ds/symlink/tmp007.pdf
+
+Required properties:
+
+  - compatible: should be "ti,tmp007"
+  - reg: the I2C address of the sensor (changeable via ADR pins)
+
+Example:
+
+tmp007@40 {
+        compatible = "ti,tmp007";
+        reg = <0x40>;
+};
+
diff --git a/drivers/iio/temperature/Kconfig b/drivers/iio/temperature/Kconfig
index c4664e5..538ce9e 100644
--- a/drivers/iio/temperature/Kconfig
+++ b/drivers/iio/temperature/Kconfig
@@ -23,6 +23,16 @@ config TMP006
 	  This driver can also be built as a module. If so, the module will
 	  be called tmp006.
 
+config TMP007
+        tristate "TMP007 infrared thermopile sensor with Integrated Math Engine"
+        depends on I2C
+        help
+          If you say yes here you get support for the Texas Instruments
+          TMP007 infrared thermopile sensor with Integrated Math Engine.
+
+          This driver can also be built as a module. If so, the module will
+          be called tmp007.
+
 config TSYS01
 	tristate "Measurement Specialties TSYS01 temperature sensor using I2C bus connection"
 	depends on I2C
diff --git a/drivers/iio/temperature/Makefile b/drivers/iio/temperature/Makefile
index 02bc79d..f0cf5c5 100644
--- a/drivers/iio/temperature/Makefile
+++ b/drivers/iio/temperature/Makefile
@@ -4,5 +4,6 @@
 
 obj-$(CONFIG_MLX90614) += mlx90614.o
 obj-$(CONFIG_TMP006) += tmp006.o
+obj-$(CONFIG_TMP007) += tmp007.o
 obj-$(CONFIG_TSYS01) += tsys01.o
 obj-$(CONFIG_TSYS02D) += tsys02d.o
diff --git a/drivers/iio/temperature/tmp007.c b/drivers/iio/temperature/tmp007.c
new file mode 100644
index 0000000..b76fecc
--- /dev/null
+++ b/drivers/iio/temperature/tmp007.c
@@ -0,0 +1,338 @@
+/*
+ * tmp007.c - Support for TI TMP007 IR thermopile sensor with integrated math engine
+ *
+ * Copyright (c) 2017 Manivannan Sadhasivam <manivannanece23-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License.  See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * Driver for the Texas Instruments I2C 16-bit IR thermopile sensor
+ *
+ * (7-bit I2C slave address (0x40 - 0x47), changeable via ADR pins)
+ *
+ * Note: This driver assumes that the sensor has been calibrated beforehand
+ *
+ * TODO: ALERT irq, limit threshold events
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/of.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+#define TMP007_TDIE 0x01
+#define TMP007_CONFIG 0x02
+#define TMP007_TOBJECT 0x03
+#define TMP007_STATUS 0x04
+#define TMP007_STATUS_MASK 0x05
+#define TMP007_MANUFACTURER_ID 0x1e
+#define TMP007_DEVICE_ID 0x1f
+
+#define TMP007_CONFIG_CONV_EN BIT(12)
+#define TMP007_CONFIG_COMP_EN BIT(5)
+#define TMP007_CONFIG_TC_EN BIT(6)
+#define TMP007_CONFIG_CR_MASK GENMASK(11, 9)
+#define TMP007_CONFIG_CR_SHIFT 9
+
+#define TMP007_STATUS_CONV_READY BIT(14)
+#define TMP007_STATUS_DATA_VALID BIT(9)
+
+#define TMP007_MANUFACTURER_MAGIC 0x5449
+#define TMP007_DEVICE_MAGIC 0x0078
+
+#define TMP007_TEMP_SHIFT 2
+
+struct tmp007_data {
+	struct i2c_client *client;
+	u16 config;
+	u16 status_mask;
+};
+
+static const int tmp007_avgs[5][2] = { {4, 0}, {2, 0}, {1, 0},
+					{0, 500000}, {0, 250000} };
+
+static int tmp007_read_temperature(struct tmp007_data *data, u8 reg)
+{
+	s32 ret;
+	int tries = 50;
+
+	while (tries-- > 0) {
+		ret = i2c_smbus_read_word_swapped(data->client,
+			TMP007_STATUS);
+		if (ret < 0)
+			return ret;
+		if ((ret & TMP007_STATUS_CONV_READY) &&
+			!(ret & TMP007_STATUS_DATA_VALID))
+				break;
+		msleep(100);
+	}
+
+	if (tries < 0)
+		return -EIO;
+
+	return i2c_smbus_read_word_swapped(data->client, reg);
+}
+
+static int tmp007_powerdown(struct tmp007_data *data)
+{
+	return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+			data->config & ~TMP007_CONFIG_CONV_EN);
+}
+
+static int tmp007_read_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *channel, int *val,
+		int *val2, long mask)
+{
+	struct tmp007_data *data = iio_priv(indio_dev);
+	s32 ret;
+	int conv_rate;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		switch (channel->channel2) {
+		case IIO_MOD_TEMP_AMBIENT: /* LSB: 0.03125 degree Celsius */
+			ret = i2c_smbus_read_word_swapped(data->client, TMP007_TDIE);
+			if (ret < 0)
+				return ret;
+			break;
+		case IIO_MOD_TEMP_OBJECT:
+			ret = tmp007_read_temperature(data, TMP007_TOBJECT);
+			if (ret < 0)
+				return ret;
+			break;
+		default:
+			return -EINVAL;
+		}
+
+		*val = sign_extend32(ret, 15) >> TMP007_TEMP_SHIFT;
+
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 31;
+		*val2 = 250000;
+
+		return IIO_VAL_INT_PLUS_MICRO;
+	case IIO_CHAN_INFO_SAMP_FREQ:
+		conv_rate = (data->config & TMP007_CONFIG_CR_MASK)
+				>> TMP007_CONFIG_CR_SHIFT;
+		*val = tmp007_avgs[conv_rate][0];
+		*val2 = tmp007_avgs[conv_rate][1];
+
+		return IIO_VAL_INT_PLUS_MICRO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int tmp007_write_raw(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *channel, int val,
+		int val2, long mask)
+{
+	struct tmp007_data *data = iio_priv(indio_dev);
+	int i;
+	u16 tmp;
+
+	if (mask == IIO_CHAN_INFO_SAMP_FREQ) {
+		for (i = 0; i < ARRAY_SIZE(tmp007_avgs); i++) {
+			if ((val == tmp007_avgs[i][0]) &&
+			(val2 == tmp007_avgs[i][1])) {
+				tmp = data->config & ~TMP007_CONFIG_CR_MASK;
+				tmp |= (i << TMP007_CONFIG_CR_SHIFT);
+
+				return i2c_smbus_write_word_swapped(data->client,
+								TMP007_CONFIG,
+								data->config = tmp);
+			}
+		}
+	}
+
+	return -EINVAL;
+}
+
+static IIO_CONST_ATTR(sampling_frequency_available, "4 2 1 0.5 0.25");
+
+static struct attribute *tmp007_attributes[] = {
+	&iio_const_attr_sampling_frequency_available.dev_attr.attr,
+	NULL
+};
+
+static const struct attribute_group tmp007_attribute_group = {
+	.attrs = tmp007_attributes,
+};
+
+static const struct iio_chan_spec tmp007_channels[] = {
+	{
+		.type = IIO_TEMP,
+		.modified = 1,
+		.channel2 = IIO_MOD_TEMP_AMBIENT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	},
+	{
+		.type = IIO_TEMP,
+		.modified = 1,
+		.channel2 = IIO_MOD_TEMP_OBJECT,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				BIT(IIO_CHAN_INFO_SCALE),
+		.info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+	}
+};
+
+static const struct iio_info tmp007_info = {
+	.read_raw = tmp007_read_raw,
+	.write_raw = tmp007_write_raw,
+	.attrs = &tmp007_attribute_group,
+	.driver_module = THIS_MODULE,
+};
+
+static bool tmp007_identify(struct i2c_client *client)
+{
+	int manf_id, dev_id;
+
+	manf_id = i2c_smbus_read_word_swapped(client, TMP007_MANUFACTURER_ID);
+	if (manf_id < 0)
+		return false;
+
+	dev_id = i2c_smbus_read_word_swapped(client, TMP007_DEVICE_ID);
+	if (dev_id < 0)
+		return false;
+
+	return (manf_id == TMP007_MANUFACTURER_MAGIC && dev_id == TMP007_DEVICE_MAGIC);
+}
+
+static int tmp007_probe(struct i2c_client *client,
+			const struct i2c_device_id *tmp007_id)
+{
+	struct tmp007_data *data;
+	struct iio_dev *indio_dev;
+	int ret;
+
+	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WORD_DATA))
+		return -EOPNOTSUPP;
+
+	if (!tmp007_identify(client)) {
+		dev_err(&client->dev, "TMP007 not found\n");
+		return -ENODEV;
+	}
+
+	indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+	if (!indio_dev)
+		return -ENOMEM;
+
+	data = iio_priv(indio_dev);
+	i2c_set_clientdata(client, indio_dev);
+	data->client = client;
+
+	indio_dev->dev.parent = &client->dev;
+	indio_dev->name = dev_name(&client->dev);
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->info = &tmp007_info;
+
+	indio_dev->channels = tmp007_channels;
+	indio_dev->num_channels = ARRAY_SIZE(tmp007_channels);
+
+	/* Set Configuration register:
+	 * 1. Conversion ON
+	 * 2. Comparator mode
+	 * 3. Transient correction enable
+	 */
+
+	ret = i2c_smbus_read_word_swapped(data->client, TMP007_CONFIG);
+	if (ret < 0)
+		return ret;
+
+	data->config = ret;
+	data->config |= (TMP007_CONFIG_CONV_EN | TMP007_CONFIG_COMP_EN | TMP007_CONFIG_TC_EN);
+
+	ret = i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+					data->config);
+	if (ret < 0)
+		return ret;
+
+	/* Set Status Mask register:
+	 * 1. Conversion ready enable
+	 */
+
+	ret = i2c_smbus_read_word_swapped(data->client, TMP007_STATUS_MASK);
+	if (ret < 0)
+		return tmp007_powerdown(data);
+
+	data->status_mask = ret;
+	data->status_mask |= TMP007_STATUS_CONV_READY;
+
+	ret = i2c_smbus_write_word_swapped(data->client, TMP007_STATUS_MASK,
+					data->status_mask);
+	if (ret < 0)
+		return tmp007_powerdown(data);
+
+	return iio_device_register(indio_dev);
+}
+
+static int tmp007_remove(struct i2c_client *client)
+{
+	struct iio_dev *indio_dev = i2c_get_clientdata(client);
+	struct tmp007_data *data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+	tmp007_powerdown(data);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int tmp007_suspend(struct device *dev)
+{
+	struct tmp007_data *data = iio_priv(i2c_get_clientdata(
+			to_i2c_client(dev)));
+
+	return tmp007_powerdown(data);
+}
+
+static int tmp007_resume(struct device *dev)
+{
+	struct tmp007_data *data = iio_priv(i2c_get_clientdata(
+			to_i2c_client(dev)));
+
+	return i2c_smbus_write_word_swapped(data->client, TMP007_CONFIG,
+			data->config | TMP007_CONFIG_CONV_EN);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(tmp007_pm_ops, tmp007_suspend, tmp007_resume);
+
+static const struct of_device_id tmp007_of_match[] = {
+	{ .compatible = "ti,tmp007", },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, tmp007_of_match);
+
+static const struct i2c_device_id tmp007_id[] = {
+	{ "tmp007", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, tmp007_id);
+
+static struct i2c_driver tmp007_driver = {
+	.driver = {
+		.name	= "tmp007",
+		.of_match_table = of_match_ptr(tmp007_of_match),
+		.pm	= &tmp007_pm_ops,
+	},
+	.probe		= tmp007_probe,
+	.remove		= tmp007_remove,
+	.id_table	= tmp007_id,
+};
+module_i2c_driver(tmp007_driver);
+
+MODULE_AUTHOR("Manivannan Sadhasivam <manivannanece23-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>");
+MODULE_DESCRIPTION("TI TMP007 IR thermopile sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.7.4

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related

* Re: [RFC 1/3] iommu/arm-smmu: Add support to opt-in to stalling
From: Will Deacon @ 2017-01-05 17:25 UTC (permalink / raw)
  To: Robin Murphy
  Cc: Mark Rutland, robh-DgEjT+Ai2ygdnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Jordan Crouse
In-Reply-To: <611575f4-3e37-1f4d-ef29-94e6f65baf66-5wv7dgnIgG8@public.gmane.org>

On Thu, Jan 05, 2017 at 05:03:30PM +0000, Robin Murphy wrote:
> On 05/01/17 16:07, Will Deacon wrote:
> > On Thu, Jan 05, 2017 at 03:32:50PM +0000, Robin Murphy wrote:
> >> I think this needs to be some kind of "arm,smmu-stall-safe" property
> >> placed on individual master device nodes (mad idea: or even an extra
> >> cell of flags in the IOMMU specifier) to encapsulate both that the given
> >> device itself is OK with being stalled, and that it's integrated in such
> >> a way that its stalled transactions cannot disrupt any *other* device
> >> (e.g. it has a TBU all to itself). Then upon initialising a context bank
> >> on a suitable SMMU implementation, we set CFCFG based on whatever device
> >> is being attached to the corresponding domain, and refuse any subsequent
> >> attempts to attach a non-stallable device to a stalling domain (and
> >> possibly even vice-versa).
> > 
> > If we're going to add per-master properties, I'd *really* like them to be
> > independent of the IOMMU in use. That is, we should be able to re-use this
> > property as part of supporting SVM for platform devices in future.
> 
> I'd argue that they are still fairly separate things despite the
> overlap: stalling is a specific ARM SMMU architecture thing (in both
> architectures) which may be used for purposes unrelated to SVM;
> conversely SVM implemented via PRI or similar mechanisms should be
> pretty much oblivious to the transaction fault model.

But SVM for a platform device is likely to require working stalls, so
they're highly related concepts. Having the former be a generic property
but the second tied to the SMMU means we have to duplicate information
(that is, we end up with a generic "SVM-capable" property that implies
that stalling works). I don't think we want that at all.

> > But I think we agree that we need:
> > 
> >   1. A compatible string for the SMMU that can be used to infer the SS
> >      behaviour in the driver
> > 
> >   2. A property on the SMMU to say that it's been integrated in such a
> >      way that stalling is safe (doesn't deadlock)
> 
> That's still got to be a per-master property, not a SMMU property, I
> think. To illustrate:
> 
>   [A]         [B]   [C]
>    |           |_____|
>  __|______________|___
> | TBU |        | TBU |
> |_____|  SMMU  |_____|
> |__|______________|__|
>    |              |
> 
> Say A and B are instances of some device happy to be stalled, and C is a
> PCIe RC, and each is attached to their own context bank - enabling
> stalls for A is definitely fine. However even though B and C are using
> different context banks, enabling stalls for B might deadlock C if it
> results in more total outstanding transactions than the TBU's slave port
> supports. Therefore A can happily claim to be stall-safe, but B cannot
> due to its integration with respect to C.

So in this case, don't say that B and C can DMA to unpinned memory. You
need the third property. This property (property 2) is concerned with the
SMMU itself because, e.g. the way the walker has been integrated can
cause a deadlock.

> And yes, I can point you at some existing hardware which really does
> posess a topology like that.
> 
> >   3. A generic master property that says that the device can DMA to
> >      unpinned memory
> 
> That sounds a bit *too* generic to me, given that there are multiple
> incompatible ways that could be implemented. I'm not the biggest fan of
> properties with heavily context-specific interpretations, especially
> when there's more than a hint of software implementation details in the mix.

So what would you propose for SVM? I really want that to be opt-in, so a
per-master flag seems like the right way forward to me.

Will

^ permalink raw reply

* Re: [PATCH 1/3] ARM64: dts: exynos5433: add DECON_TV node
From: Krzysztof Kozlowski @ 2017-01-05 17:26 UTC (permalink / raw)
  To: Andrzej Hajda
  Cc: linux-samsung-soc, Krzysztof Kozlowski, Bartlomiej Zolnierkiewicz,
	Marek Szyprowski, Inki Dae, Rob Herring, Mark Rutland,
	Javier Martinez Canillas, devicetree
In-Reply-To: <1483629943-31183-1-git-send-email-a.hajda@samsung.com>

On Thu, Jan 05, 2017 at 04:25:41PM +0100, Andrzej Hajda wrote:
> DECON_TV is 2nd display controller on Exynos5433, used in HDMI path
> or 2nd DSI path.
> 
> Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
> ---
>  arch/arm64/boot/dts/exynos/exynos5433.dtsi | 44 ++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/exynos/exynos5433.dtsi b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> index 8cbfd1d..b47951b 100644
> --- a/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> +++ b/arch/arm64/boot/dts/exynos/exynos5433.dtsi
> @@ -821,6 +821,28 @@
>  			};
>  		};
>  
> +		decon_tv: decon@13880000 {
> +			compatible = "samsung,exynos5433-decon-tv";
> +			reg = <0x13880000 0x20B8>;
> +			clocks = <&cmu_disp CLK_PCLK_DECON_TV>,
> +				 <&cmu_disp CLK_ACLK_DECON_TV>,
> +				 <&cmu_disp CLK_ACLK_SMMU_TV0X>,
> +				 <&cmu_disp CLK_ACLK_XIU_TV0X>,
> +				 <&cmu_disp CLK_PCLK_SMMU_TV0X>,
> +				 <&cmu_disp CLK_SCLK_DECON_TV_VCLK>,
> +				 <&cmu_disp CLK_SCLK_DECON_TV_ECLK>;
> +			clock-names = "pclk", "aclk_decon", "aclk_smmu_decon0x",
> +				      "aclk_xiu_decon0x", "pclk_smmu_decon0x",
> +				      "sclk_decon_vclk", "sclk_decon_eclk";
> +			samsung,disp-sysreg = <&syscon_disp>;
> +			interrupt-names = "fifo", "vsync", "lcd_sys";
> +			interrupts = <0 210 0>, <0 211 0>, <0 212 0>;
> +			power-domains = <&pd_disp>;
> +			status = "disabled";
> +			iommus = <&sysmmu_tv0x>, <&sysmmu_tv1x>;
> +			iommu-names = "m0", "m1";
> +		};
> +
>  		syscon_disp: syscon@13b80000 {
>  			compatible = "syscon";
>  			reg = <0x13b80000 0x1010>;
> @@ -926,6 +948,28 @@
>  			power-domains = <&pd_disp>;
>  		};
>  
> +		sysmmu_tv0x: sysmmu@0x13a20000 {

Without the '0x' in the address, please. I see that you copied it from
existing nodes, so maybe you could fix them as well in following patch.

Beside that (and Javier's comments) looks okay, but please choose
suitable subject prefix matching recent commits. I think it is the third
time I am mentioning this recently (to different Samsung folks,
though)... 

Best regards,
Krzysztof

^ permalink raw reply

* Re: [PATCH] ARM: dts: am335x-icev2: Remove the duplicated pinmux setting
From: Tony Lindgren @ 2017-01-05 17:31 UTC (permalink / raw)
  To: Lokesh Vutla
  Cc: Linux OMAP Mailing List, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Tero Kristo, Sekhar Nori,
	Linux ARM Mailing List
In-Reply-To: <20170104050940.25698-1-lokeshvutla-l0cyMroinI0@public.gmane.org>

* Lokesh Vutla <lokeshvutla-l0cyMroinI0@public.gmane.org> [170103 21:12]:
> There is no mmc sd card detect on am335x-ice board. But the spi0_cs1
> pin being configured as mmcsd_cd. Removing it fixes the below warning
> during boot.

Applying into omap-for-v4.11/fixes thanks.

Tony
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCHv3 3/8] rtc: add STM32 RTC driver
From: Mathieu Poirier @ 2017-01-05 17:33 UTC (permalink / raw)
  To: Amelie Delaunay
  Cc: Alessandro Zummo, Alexandre Belloni, Rob Herring, Mark Rutland,
	Maxime Coquelin, Alexandre Torgue, Russell King,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	rtc-linux-/JYPxA39Uh5TLH3MbocFFw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA, Gabriel Fernandez,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <1483623809-29937-4-git-send-email-amelie.delaunay-qxv4g6HH51o@public.gmane.org>

On Thu, Jan 05, 2017 at 02:43:24PM +0100, Amelie Delaunay wrote:
> This patch adds support for the STM32 RTC.
> 
> Signed-off-by: Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
> ---
>  drivers/rtc/Kconfig     |  11 +
>  drivers/rtc/Makefile    |   1 +
>  drivers/rtc/rtc-stm32.c | 776 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 788 insertions(+)
>  create mode 100644 drivers/rtc/rtc-stm32.c
> 
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index e859d14..11eb28a 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -1706,6 +1706,17 @@ config RTC_DRV_PIC32
>  	   This driver can also be built as a module. If so, the module
>  	   will be called rtc-pic32
>  
> +config RTC_DRV_STM32
> +	tristate "STM32 RTC"
> +	select REGMAP_MMIO
> +	depends on ARCH_STM32 || COMPILE_TEST
> +	help
> +	   If you say yes here you get support for the STM32 On-Chip
> +	   Real Time Clock.
> +
> +	   This driver can also be built as a module, if so, the module
> +	   will be called "rtc-stm32".
> +
>  comment "HID Sensor RTC drivers"
>  
>  config RTC_DRV_HID_SENSOR_TIME
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index 1ac694a..87bd9cc 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -144,6 +144,7 @@ obj-$(CONFIG_RTC_DRV_SNVS)	+= rtc-snvs.o
>  obj-$(CONFIG_RTC_DRV_SPEAR)	+= rtc-spear.o
>  obj-$(CONFIG_RTC_DRV_STARFIRE)	+= rtc-starfire.o
>  obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o
> +obj-$(CONFIG_RTC_DRV_STM32) 	+= rtc-stm32.o
>  obj-$(CONFIG_RTC_DRV_STMP)	+= rtc-stmp3xxx.o
>  obj-$(CONFIG_RTC_DRV_ST_LPC)	+= rtc-st-lpc.o
>  obj-$(CONFIG_RTC_DRV_SUN4V)	+= rtc-sun4v.o
> diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
> new file mode 100644
> index 0000000..fdd3a31
> --- /dev/null
> +++ b/drivers/rtc/rtc-stm32.c
> @@ -0,0 +1,776 @@
> +/*
> + * Copyright (C) Amelie Delaunay 2016
> + * Author:  Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>
> + * License terms:  GNU General Public License (GPL), version 2
> + */
> +
> +#include <linux/bcd.h>
> +#include <linux/clk.h>
> +#include <linux/iopoll.h>
> +#include <linux/ioport.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/regmap.h>
> +#include <linux/rtc.h>
> +#include <linux/spinlock.h>
> +
> +#define DRIVER_NAME "stm32_rtc"
> +
> +/* STM32 RTC registers */
> +#define STM32_RTC_TR		0x00
> +#define STM32_RTC_DR		0x04
> +#define STM32_RTC_CR		0x08
> +#define STM32_RTC_ISR		0x0C
> +#define STM32_RTC_PRER		0x10
> +#define STM32_RTC_ALRMAR	0x1C
> +#define STM32_RTC_WPR		0x24
> +
> +/* STM32_RTC_TR bit fields  */
> +#define STM32_RTC_TR_SEC_SHIFT		0
> +#define STM32_RTC_TR_SEC		GENMASK(6, 0)
> +#define STM32_RTC_TR_MIN_SHIFT		8
> +#define STM32_RTC_TR_MIN		GENMASK(14, 8)
> +#define STM32_RTC_TR_HOUR_SHIFT		16
> +#define STM32_RTC_TR_HOUR		GENMASK(21, 16)
> +
> +/* STM32_RTC_DR bit fields */
> +#define STM32_RTC_DR_DATE_SHIFT		0
> +#define STM32_RTC_DR_DATE		GENMASK(5, 0)
> +#define STM32_RTC_DR_MONTH_SHIFT	8
> +#define STM32_RTC_DR_MONTH		GENMASK(12, 8)
> +#define STM32_RTC_DR_WDAY_SHIFT		13
> +#define STM32_RTC_DR_WDAY		GENMASK(15, 13)
> +#define STM32_RTC_DR_YEAR_SHIFT		16
> +#define STM32_RTC_DR_YEAR		GENMASK(23, 16)
> +
> +/* STM32_RTC_CR bit fields */
> +#define STM32_RTC_CR_FMT		BIT(6)
> +#define STM32_RTC_CR_ALRAE		BIT(8)
> +#define STM32_RTC_CR_ALRAIE		BIT(12)
> +
> +/* STM32_RTC_ISR bit fields */
> +#define STM32_RTC_ISR_ALRAWF		BIT(0)
> +#define STM32_RTC_ISR_INITS		BIT(4)
> +#define STM32_RTC_ISR_RSF		BIT(5)
> +#define STM32_RTC_ISR_INITF		BIT(6)
> +#define STM32_RTC_ISR_INIT		BIT(7)
> +#define STM32_RTC_ISR_ALRAF		BIT(8)
> +
> +/* STM32_RTC_PRER bit fields */
> +#define STM32_RTC_PRER_PRED_S_SHIFT	0
> +#define STM32_RTC_PRER_PRED_S		GENMASK(14, 0)
> +#define STM32_RTC_PRER_PRED_A_SHIFT	16
> +#define STM32_RTC_PRER_PRED_A		GENMASK(22, 16)
> +
> +/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
> +#define STM32_RTC_ALRMXR_SEC_SHIFT	0
> +#define STM32_RTC_ALRMXR_SEC		GENMASK(6, 0)
> +#define STM32_RTC_ALRMXR_SEC_MASK	BIT(7)
> +#define STM32_RTC_ALRMXR_MIN_SHIFT	8
> +#define STM32_RTC_ALRMXR_MIN		GENMASK(14, 8)
> +#define STM32_RTC_ALRMXR_MIN_MASK	BIT(15)
> +#define STM32_RTC_ALRMXR_HOUR_SHIFT	16
> +#define STM32_RTC_ALRMXR_HOUR		GENMASK(21, 16)
> +#define STM32_RTC_ALRMXR_PM		BIT(22)
> +#define STM32_RTC_ALRMXR_HOUR_MASK	BIT(23)
> +#define STM32_RTC_ALRMXR_DATE_SHIFT	24
> +#define STM32_RTC_ALRMXR_DATE		GENMASK(29, 24)
> +#define STM32_RTC_ALRMXR_WDSEL		BIT(30)
> +#define STM32_RTC_ALRMXR_WDAY_SHIFT	24
> +#define STM32_RTC_ALRMXR_WDAY		GENMASK(27, 24)
> +#define STM32_RTC_ALRMXR_DATE_MASK	BIT(31)
> +
> +/* STM32_RTC_WPR key constants */
> +#define RTC_WPR_1ST_KEY			0xCA
> +#define RTC_WPR_2ND_KEY			0x53
> +#define RTC_WPR_WRONG_KEY		0xFF
> +
> +/*
> + * RTC registers are protected agains parasitic write access.
> + * PWR_CR_DBP bit must be set to enable write access to RTC registers.
> + */
> +/* STM32_PWR_CR */
> +#define PWR_CR				0x00
> +/* STM32_PWR_CR bit field */
> +#define PWR_CR_DBP			BIT(8)
> +
> +static struct regmap *dbp;
> +
> +struct stm32_rtc {
> +	struct rtc_device *rtc_dev;
> +	void __iomem *base;
> +	struct clk *ck_rtc;
> +	spinlock_t lock; /* Protects registers accesses */
> +	int irq_alarm;
> +};
> +
> +static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
> +{
> +	writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
> +	writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
> +}
> +
> +static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
> +{
> +	writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
> +}
> +
> +static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +
> +	if (!(isr & STM32_RTC_ISR_INITF)) {
> +		isr |= STM32_RTC_ISR_INIT;
> +		writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
> +
> +		/*
> +		 * It takes around 2 ck_rtc clock cycles to enter in
> +		 * initialization phase mode (and have INITF flag set). As
> +		 * slowest ck_rtc frequency may be 32kHz and highest should be
> +		 * 1MHz, we poll every 10 us with a timeout of 100ms.
> +		 */
> +		return readl_relaxed_poll_timeout_atomic(
> +					rtc->base + STM32_RTC_ISR,
> +					isr, (isr & STM32_RTC_ISR_INITF),
> +					10, 100000);
> +	}
> +
> +	return 0;
> +}
> +
> +static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_INIT;
> +	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
> +}
> +
> +static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
> +{
> +	unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +
> +	isr &= ~STM32_RTC_ISR_RSF;
> +	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
> +
> +	/*
> +	 * Wait for RSF to be set to ensure the calendar registers are
> +	 * synchronised, it takes around 2 ck_rtc clock cycles
> +	 */
> +	return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> +						 isr,
> +						 (isr & STM32_RTC_ISR_RSF),
> +						 10, 100000);
> +}
> +
> +static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
> +{
> +	struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
> +	unsigned int isr, cr;
> +
> +	mutex_lock(&rtc->rtc_dev->ops_lock);
> +
> +	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +
> +	if ((isr & STM32_RTC_ISR_ALRAF) &&
> +	    (cr & STM32_RTC_CR_ALRAIE)) {
> +		/* Alarm A flag - Alarm interrupt */
> +		dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
> +
> +		/* Pass event to the kernel */
> +		rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
> +
> +		/* Clear event flag, otherwise new events won't be received */
> +		writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
> +			       rtc->base + STM32_RTC_ISR);
> +	}
> +
> +	mutex_unlock(&rtc->rtc_dev->ops_lock);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/* Convert rtc_time structure from bin to bcd format */
> +static void tm2bcd(struct rtc_time *tm)
> +{
> +	tm->tm_sec = bin2bcd(tm->tm_sec);
> +	tm->tm_min = bin2bcd(tm->tm_min);
> +	tm->tm_hour = bin2bcd(tm->tm_hour);
> +
> +	tm->tm_mday = bin2bcd(tm->tm_mday);
> +	tm->tm_mon = bin2bcd(tm->tm_mon + 1);
> +	tm->tm_year = bin2bcd(tm->tm_year - 100);
> +	/*
> +	 * Number of days since Sunday
> +	 * - on kernel side, 0=Sunday...6=Saturday
> +	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
> +	 */
> +	tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
> +}
> +
> +/* Convert rtc_time structure from bcd to bin format */
> +static void bcd2tm(struct rtc_time *tm)
> +{
> +	tm->tm_sec = bcd2bin(tm->tm_sec);
> +	tm->tm_min = bcd2bin(tm->tm_min);
> +	tm->tm_hour = bcd2bin(tm->tm_hour);
> +
> +	tm->tm_mday = bcd2bin(tm->tm_mday);
> +	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
> +	tm->tm_year = bcd2bin(tm->tm_year) + 100;
> +	/*
> +	 * Number of days since Sunday
> +	 * - on kernel side, 0=Sunday...6=Saturday
> +	 * - on rtc side, 0=invalid,1=Monday...7=Sunday
> +	 */
> +	tm->tm_wday %= 7;
> +}
> +
> +static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	unsigned int tr, dr;
> +	unsigned long irqflags;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	/* Time and Date in BCD format */
> +	tr = readl_relaxed(rtc->base + STM32_RTC_TR);
> +	dr = readl_relaxed(rtc->base + STM32_RTC_DR);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
> +	tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
> +	tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
> +
> +	tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
> +	tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
> +	tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
> +	tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
> +
> +	/* We don't report tm_yday and tm_isdst */
> +
> +	bcd2tm(tm);
> +
> +	if (rtc_valid_tm(tm) < 0) {
> +		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	unsigned int tr, dr;
> +	unsigned long irqflags;
> +	int ret = 0;
> +
> +	if (rtc_valid_tm(tm) < 0) {
> +		dev_err(dev, "%s: rtc_time is not valid.\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	tm2bcd(tm);
> +
> +	/* Time in BCD format */
> +	tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
> +	     ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
> +	     ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
> +
> +	/* Date in BCD format */
> +	dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
> +	     ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
> +	     ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
> +	     ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	ret = stm32_rtc_enter_init_mode(rtc);
> +	if (ret) {
> +		dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
> +		goto end;
> +	}
> +
> +	writel_relaxed(tr, rtc->base + STM32_RTC_TR);
> +	writel_relaxed(dr, rtc->base + STM32_RTC_DR);
> +
> +	stm32_rtc_exit_init_mode(rtc);
> +
> +	ret = stm32_rtc_wait_sync(rtc);
> +end:
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return ret;
> +}
> +
> +static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	struct rtc_time *tm = &alrm->time;
> +	unsigned int alrmar, cr, isr;
> +	unsigned long irqflags;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
> +		/*
> +		 * Date/day doesn't matter in Alarm comparison so alarm
> +		 * triggers every day
> +		 */
> +		tm->tm_mday = -1;
> +		tm->tm_wday = -1;
> +	} else {
> +		if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
> +			/* Alarm is set to a day of week */
> +			tm->tm_mday = -1;
> +			tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
> +				      STM32_RTC_ALRMXR_WDAY_SHIFT;
> +			tm->tm_wday %= 7;
> +		} else {
> +			/* Alarm is set to a day of month */
> +			tm->tm_wday = -1;
> +			tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
> +				       STM32_RTC_ALRMXR_DATE_SHIFT;
> +		}
> +	}
> +
> +	if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
> +		/* Hours don't matter in Alarm comparison */
> +		tm->tm_hour = -1;
> +	} else {
> +		tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
> +			       STM32_RTC_ALRMXR_HOUR_SHIFT;
> +		if (alrmar & STM32_RTC_ALRMXR_PM)
> +			tm->tm_hour += 12;
> +	}
> +
> +	if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
> +		/* Minutes don't matter in Alarm comparison */
> +		tm->tm_min = -1;
> +	} else {
> +		tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
> +			      STM32_RTC_ALRMXR_MIN_SHIFT;
> +	}
> +
> +	if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
> +		/* Seconds don't matter in Alarm comparison */
> +		tm->tm_sec = -1;
> +	} else {
> +		tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
> +			      STM32_RTC_ALRMXR_SEC_SHIFT;
> +	}
> +
> +	bcd2tm(tm);
> +
> +	alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
> +	alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
> +
> +	return 0;
> +}
> +
> +static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	unsigned long irqflags;
> +	unsigned int isr, cr;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	/* We expose Alarm A to the kernel */
> +	if (enabled)
> +		cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> +	else
> +		cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
> +	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
> +
> +	/* Clear event irqflags, otherwise new events won't be received */
> +	isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
> +	isr &= ~STM32_RTC_ISR_ALRAF;
> +	writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
> +
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return 0;
> +}
> +
> +static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
> +{
> +	unsigned int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
> +	unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
> +	unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
> +
> +	cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
> +	cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
> +	cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
> +	cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
> +	cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
> +	cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
> +
> +	/*
> +	 * Assuming current date is M-D-Y H:M:S.
> +	 * RTC alarm can't be set on a specific month and year.
> +	 * So the valid alarm range is:
> +	 *	M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
> +	 * with a specific case for December...
> +	 */
> +	if ((((tm->tm_year > cur_year) &&
> +	      (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
> +	     ((tm->tm_year == cur_year) &&
> +	      (tm->tm_mon <= cur_mon + 1))) &&
> +	    ((tm->tm_mday < cur_day) ||
> +	     ((tm->tm_mday == cur_day) &&
> +	     ((tm->tm_hour < cur_hour) ||
> +	      ((tm->tm_hour == cur_hour) && (tm->tm_min < cur_min)) ||
> +	      ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
> +	       (tm->tm_sec <= cur_sec))))))
> +		return 0;
> +
> +	return -EINVAL;
> +}
> +
> +static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	struct rtc_time *tm = &alrm->time;
> +	unsigned long irqflags;
> +	unsigned int cr, isr, alrmar;
> +	int ret = 0;
> +
> +	if (rtc_valid_tm(tm)) {
> +		dev_err(dev, "Alarm time not valid.\n");
> +		return -EINVAL;
> +	}
> +
> +	tm2bcd(tm);
> +
> +	/*
> +	 * RTC alarm can't be set on a specific date, unless this date is
> +	 * up to the same day of month next month.
> +	 */
> +	if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
> +		dev_err(dev, "Alarm can be set only on upcoming month.\n");
> +		return -EINVAL;
> +	}
> +
> +	alrmar = 0;
> +	/* tm_year and tm_mon are not used because not supported by RTC */
> +	alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
> +		  STM32_RTC_ALRMXR_DATE;
> +	/* 24-hour format */
> +	alrmar &= ~STM32_RTC_ALRMXR_PM;
> +	alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
> +		  STM32_RTC_ALRMXR_HOUR;
> +	alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
> +		  STM32_RTC_ALRMXR_MIN;
> +	alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
> +		  STM32_RTC_ALRMXR_SEC;
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	/* Disable Alarm */
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAE;
> +	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
> +
> +	/*
> +	 * Poll Alarm write flag to be sure that Alarm update is allowed: it
> +	 * takes around 2 ck_rtc clock cycles
> +	 */
> +	ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
> +						isr,
> +						(isr & STM32_RTC_ISR_ALRAWF),
> +						10, 100000);
> +
> +	if (ret) {
> +		dev_err(dev, "Alarm update not allowed\n");
> +		goto end;
> +	}
> +
> +	/* Write to Alarm register */
> +	writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR);
> +
> +	if (alrm->enabled)
> +		stm32_rtc_alarm_irq_enable(dev, 1);
> +	else
> +		stm32_rtc_alarm_irq_enable(dev, 0);
> +
> +end:
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return ret;
> +}
> +
> +static const struct rtc_class_ops stm32_rtc_ops = {
> +	.read_time	= stm32_rtc_read_time,
> +	.set_time	= stm32_rtc_set_time,
> +	.read_alarm	= stm32_rtc_read_alarm,
> +	.set_alarm	= stm32_rtc_set_alarm,
> +	.alarm_irq_enable = stm32_rtc_alarm_irq_enable,
> +};
> +
> +#ifdef CONFIG_OF
> +static const struct of_device_id stm32_rtc_of_match[] = {
> +	{ .compatible = "st,stm32-rtc" },
> +	{}
> +};
> +MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
> +#endif
> +
> +static int stm32_rtc_init(struct platform_device *pdev,
> +			  struct stm32_rtc *rtc)
> +{
> +	unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
> +	unsigned int rate;
> +	unsigned long irqflags;
> +	int ret = 0;
> +
> +	rate = clk_get_rate(rtc->ck_rtc);
> +
> +	/* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
> +	pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
> +	pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
> +
> +	for (pred_a = pred_a_max; pred_a >= 0; pred_a--) {
> +		pred_s = (rate / (pred_a + 1)) - 1;
> +
> +		if (((pred_s + 1) * (pred_a + 1)) == rate)
> +			break;
> +	}
> +
> +	/*
> +	 * Can't find a 1Hz, so give priority to RTC power consumption
> +	 * by choosing the higher possible value for prediv_a
> +	 */
> +	if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
> +		pred_a = pred_a_max;
> +		pred_s = (rate / (pred_a + 1)) - 1;
> +
> +		dev_warn(&pdev->dev, "ck_rtc is %s\n",
> +			 (rate - ((pred_a + 1) * (pred_s + 1)) < 0) ?
> +			 "fast" : "slow");
> +	}
> +
> +	spin_lock_irqsave(&rtc->lock, irqflags);
> +
> +	stm32_rtc_wpr_unlock(rtc);
> +
> +	ret = stm32_rtc_enter_init_mode(rtc);
> +	if (ret) {
> +		dev_err(&pdev->dev,
> +			"Can't enter in init mode. Prescaler config failed.\n");
> +		goto end;
> +	}
> +
> +	prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
> +	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
> +	prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
> +	writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
> +
> +	/* Force 24h time format */
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_FMT;
> +	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
> +
> +	stm32_rtc_exit_init_mode(rtc);
> +
> +	ret = stm32_rtc_wait_sync(rtc);
> +end:
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	spin_unlock_irqrestore(&rtc->lock, irqflags);
> +
> +	return ret;
> +}
> +
> +static int stm32_rtc_probe(struct platform_device *pdev)
> +{
> +	struct stm32_rtc *rtc;
> +	struct resource *res;
> +	int ret;
> +
> +	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
> +	if (!rtc)
> +		return -ENOMEM;
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	rtc->base = devm_ioremap_resource(&pdev->dev, res);
> +	if (IS_ERR(rtc->base))
> +		return PTR_ERR(rtc->base);
> +
> +	dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "st,syscfg");
> +	if (IS_ERR(dbp)) {
> +		dev_err(&pdev->dev, "no st,syscfg\n");
> +		return PTR_ERR(dbp);
> +	}
> +
> +	spin_lock_init(&rtc->lock);
> +
> +	rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
> +	if (IS_ERR(rtc->ck_rtc)) {
> +		dev_err(&pdev->dev, "no ck_rtc clock");
> +		return PTR_ERR(rtc->ck_rtc);
> +	}
> +
> +	ret = clk_prepare_enable(rtc->ck_rtc);
> +	if (ret)
> +		return ret;
> +
> +	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
> +
> +	/*
> +	 * After a system reset, RTC_ISR.INITS flag can be read to check if
> +	 * the calendar has been initalized or not. INITS flag is reset by a
> +	 * power-on reset (no vbat, no power-supply). It is not reset if
> +	 * ck_rtc parent clock has changed (so RTC prescalers need to be
> +	 * changed). That's why we cannot rely on this flag to know if RTC
> +	 * init has to be done.
> +	 */
> +	ret = stm32_rtc_init(pdev, rtc);
> +	if (ret)
> +		goto err;
> +
> +	rtc->irq_alarm = platform_get_irq(pdev, 0);
> +	if (rtc->irq_alarm <= 0) {
> +		dev_err(&pdev->dev, "no alarm irq\n");
> +		ret = rtc->irq_alarm;
> +		goto err;
> +	}
> +
> +	platform_set_drvdata(pdev, rtc);
> +
> +	ret = device_init_wakeup(&pdev->dev, true);
> +	if (ret)
> +		dev_warn(&pdev->dev,
> +			 "alarm won't be able to wake up the system");
> +
> +	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
> +			&stm32_rtc_ops, THIS_MODULE);
> +	if (IS_ERR(rtc->rtc_dev)) {
> +		ret = PTR_ERR(rtc->rtc_dev);
> +		dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
> +			ret);
> +		goto err;
> +	}
> +
> +	/* Handle RTC alarm interrupts */
> +	ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
> +					stm32_rtc_alarm_irq,
> +					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
> +					pdev->name, rtc);
> +	if (ret) {
> +		dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
> +			rtc->irq_alarm);
> +		goto err;
> +	}
> +
> +	/*
> +	 * If INITS flag is reset (calendar year field set to 0x00), calendar
> +	 * must be initialized
> +	 */
> +	if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
> +		dev_warn(&pdev->dev, "Date/Time must be initialized\n");
> +
> +	return 0;
> +err:
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return ret;
> +}
> +
> +static int __exit stm32_rtc_remove(struct platform_device *pdev)
> +{
> +	struct stm32_rtc *rtc = platform_get_drvdata(pdev);
> +	unsigned int cr;
> +
> +	/* Disable interrupts */
> +	stm32_rtc_wpr_unlock(rtc);
> +	cr = readl_relaxed(rtc->base + STM32_RTC_CR);
> +	cr &= ~STM32_RTC_CR_ALRAIE;
> +	writel_relaxed(cr, rtc->base + STM32_RTC_CR);
> +	stm32_rtc_wpr_lock(rtc);
> +
> +	clk_disable_unprepare(rtc->ck_rtc);
> +
> +	/* Enable backup domain write protection */
> +	regmap_update_bits(dbp, PWR_CR, PWR_CR_DBP, ~PWR_CR_DBP);
> +
> +	device_init_wakeup(&pdev->dev, false);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_PM_SLEEP
> +static int stm32_rtc_suspend(struct device *dev)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +
> +	if (device_may_wakeup(dev))
> +		return enable_irq_wake(rtc->irq_alarm);
> +
> +	return 0;
> +}
> +
> +static int stm32_rtc_resume(struct device *dev)
> +{
> +	struct stm32_rtc *rtc = dev_get_drvdata(dev);
> +	int ret = 0;
> +
> +	ret = stm32_rtc_wait_sync(rtc);
> +	if (ret < 0)
> +		return ret;
> +
> +	if (device_may_wakeup(dev))
> +		return disable_irq_wake(rtc->irq_alarm);
> +
> +	return ret;
> +}
> +#endif
> +
> +static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
> +			 stm32_rtc_suspend, stm32_rtc_resume);
> +
> +static struct platform_driver stm32_rtc_driver = {
> +	.probe		= stm32_rtc_probe,
> +	.remove		= stm32_rtc_remove,
> +	.driver		= {
> +		.name	= DRIVER_NAME,
> +		.pm	= &stm32_rtc_pm_ops,
> +		.of_match_table = stm32_rtc_of_match,
> +	},
> +};
> +
> +module_platform_driver(stm32_rtc_driver);
> +
> +MODULE_ALIAS("platform:" DRIVER_NAME);
> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay-qxv4g6HH51o@public.gmane.org>");
> +MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
> +MODULE_LICENSE("GPL v2");

Looks much better now.

Reviewed-by: Mathieu Poirier <mathieu.poirier-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>

> -- 
> 1.9.1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH 17/22] power: supply: add battery driver for AXP20X and AXP22X PMICs
From: Ezequiel Garcia @ 2017-01-05 17:34 UTC (permalink / raw)
  To: Quentin Schulz
  Cc: Mark Rutland, Thomas Petazzoni, lars, devicetree@vger.kernel.org,
	linux-iio, linux-kernel@vger.kernel.org, linux-pm, sre, linux,
	Chen-Yu Tsai, Rob Herring, icenowy, pmeerw, knaack.h,
	Maxime Ripard, bonbons, Lee Jones, jic23, linux-arm-kernel
In-Reply-To: <20170102163723.7939-18-quentin.schulz@free-electrons.com>

On 2 January 2017 at 13:37, Quentin Schulz
<quentin.schulz@free-electrons.com> wrote:
[...]
> +
> +#define AXP20X_PWR_STATUS_BAT_CHARGING BIT(2)
> +
> +#define AXP20X_PWR_OP_BATT_PRESENT     BIT(5)
> +#define AXP20X_PWR_OP_BATT_ACTIVATED   BIT(3)
> +
> +#define AXP209_FG_PERCENT              GENMASK(6, 0)
> +#define AXP22X_FG_VALID                        BIT(7)
> +
> +#define AXP20X_CHRG_CTRL1_TGT_VOLT     GENMASK(6, 5)
> +#define AXP20X_CHRG_CTRL1_TGT_4_1V     (0 << 5)
> +#define AXP20X_CHRG_CTRL1_TGT_4_15V    BIT(5)

This is just a silly nit, but I would put (1 << 5) here
for readability.

> +#define AXP20X_CHRG_CTRL1_TGT_4_2V     (2 << 5)
> +#define AXP20X_CHRG_CTRL1_TGT_4_36V    (3 << 5)
> +#define AXP20X_CHRG_CTRL1_TGT_CURR     GENMASK(3, 0)
> +
> +#define AXP22X_CHRG_CTRL1_TGT_4_22V    BIT(5)

Ditto.

> +#define AXP22X_CHRG_CTRL1_TGT_4_24V    (3 << 5)
> +
> +#define AXP20X_V_OFF_MASK              GENMASK(2, 0)
> +
> +struct axp20x_batt_ps {
> +       struct regmap *regmap;
> +       struct power_supply *batt;
> +       struct axp20x_dev *axp20x;
> +       struct iio_channel *batt_chrg_i;
> +       struct iio_channel *batt_dischrg_i;
> +       struct iio_channel *batt_v;
> +       u8 axp_id;
> +};
> +
[..]
> +static int axp20x_power_probe(struct platform_device *pdev)
> +{
> +       struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
> +       struct axp20x_batt_ps *axp20x_batt;
> +       struct power_supply_config psy_cfg = {};
> +

To be consistent with the AC power supply and USB power supply,
you might want to call of_device_is_available() here.
Otherwise, the device probes even if "disabled" in the DTS.

> +       axp20x_batt = devm_kzalloc(&pdev->dev, sizeof(*axp20x_batt),
> +                                  GFP_KERNEL);
> +       if (!axp20x_batt)
> +               return -ENOMEM;
> +

Thanks for the good work,
-- 
Ezequiel García, VanguardiaSur
www.vanguardiasur.com.ar

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 5/5] arm64: dts: add BananaPi-M64 support
From: Maxime Ripard @ 2017-01-05 17:36 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Ulf Hansson, Chen-Yu Tsai, Hans De Goede, Icenowy Zheng,
	Mark Rutland, Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1483398226-29321-6-git-send-email-andre.przywara-5wv7dgnIgG8@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 6319 bytes --]

On Mon, Jan 02, 2017 at 11:03:46PM +0000, Andre Przywara wrote:
> The Banana Pi M64 board is a typical single board computer based on the
> Allwinner A64 SoC. Aside from the usual peripherals it features eMMC
> storage, which is connected to the 8-bit capable SDHC2 controller.
> Also it has a soldered WiFi/Bluetooth chip, so we enable UART1 and SDHC1
> as those two interfaces are connected to it.
> 
> Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>
> ---
>  arch/arm64/boot/dts/allwinner/Makefile             |   1 +
>  .../boot/dts/allwinner/sun50i-a64-bananapi-m64.dts | 125 +++++++++++++++++++++
>  arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi      |  10 ++
>  3 files changed, 136 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
> 
> diff --git a/arch/arm64/boot/dts/allwinner/Makefile b/arch/arm64/boot/dts/allwinner/Makefile
> index 1e29a5a..51ecb04 100644
> --- a/arch/arm64/boot/dts/allwinner/Makefile
> +++ b/arch/arm64/boot/dts/allwinner/Makefile
> @@ -1,4 +1,5 @@
>  dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-pine64-plus.dtb sun50i-a64-pine64.dtb
> +dtb-$(CONFIG_ARCH_SUNXI) += sun50i-a64-bananapi-m64.dtb

Please sort it by alphabetical order.

>  
>  always		:= $(dtb-y)
>  subdir-y	:= $(dts-dirs)
> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
> new file mode 100644
> index 0000000..941ea07
> --- /dev/null
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64-bananapi-m64.dts
> @@ -0,0 +1,125 @@
> +/*
> + * Copyright (c) 2016 ARM Ltd.
> + *
> + * This file is dual-licensed: you can use it either under the terms
> + * of the GPL or the X11 license, at your option. Note that this dual
> + * licensing only applies to this file, and not this project as a
> + * whole.
> + *
> + *  a) This library is free software; you can redistribute it and/or
> + *     modify it under the terms of the GNU General Public License as
> + *     published by the Free Software Foundation; either version 2 of the
> + *     License, or (at your option) any later version.
> + *
> + *     This library is distributed in the hope that it will be useful,
> + *     but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *     GNU General Public License for more details.
> + *
> + * Or, alternatively,
> + *
> + *  b) Permission is hereby granted, free of charge, to any person
> + *     obtaining a copy of this software and associated documentation
> + *     files (the "Software"), to deal in the Software without
> + *     restriction, including without limitation the rights to use,
> + *     copy, modify, merge, publish, distribute, sublicense, and/or
> + *     sell copies of the Software, and to permit persons to whom the
> + *     Software is furnished to do so, subject to the following
> + *     conditions:
> + *
> + *     The above copyright notice and this permission notice shall be
> + *     included in all copies or substantial portions of the Software.
> + *
> + *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> + *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
> + *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
> + *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
> + *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
> + *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
> + *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + *     OTHER DEALINGS IN THE SOFTWARE.
> + */
> +
> +/dts-v1/;
> +
> +#include "sun50i-a64.dtsi"
> +
> +/ {
> +	model = "BananaPi-M64";
> +	compatible = "sinovoip,bananapi-m64", "allwinner,sun50i-a64";
> +
> +	aliases {
> +		serial0 = &uart0;
> +		serial1 = &uart1;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial0:115200n8";
> +	};
> +
> +	reg_vcc3v3: vcc3v3 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "vcc3v3";
> +		regulator-min-microvolt = <3300000>;
> +		regulator-max-microvolt = <3300000>;
> +	};
> +};
> +
> +&uart0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart0_pins_a>;
> +	status = "okay";
> +};
> +
> +&uart1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&uart1_pins_4>;
> +	status = "okay";
> +};
> +
> +&i2c1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&i2c1_pins>;
> +	status = "okay";
> +};

And the nodes too.

> +
> +&i2c1_pins {
> +	bias-pull-up;
> +};
> +
> +&mmc0 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&mmc0_pins>, <&mmc0_default_cd_pin>;
> +	vmmc-supply = <&reg_vcc3v3>;
> +	cd-gpios = <&pio 5 6 0>;

Please use a define here.

> +	cd-inverted;
> +	disable-wp;
> +	bus-width = <4>;
> +	status = "okay";
> +};
> +
> +&mmc1 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&mmc1_pins>;
> +	vmmc-supply = <&reg_vcc3v3>;
> +	bus-width = <4>;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&mmc2 {
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&mmc2_pins>;
> +	vmmc-supply = <&reg_vcc3v3>;
> +	bus-width = <8>;
> +	non-removable;
> +	cap-mmc-hw-reset;
> +	status = "okay";
> +};
> +
> +&mmc2_pins {
> +	/* Increase drive strength for DDR modes */
> +	drive-strength = <40>;

Allwinner recommends to use 30mA, have you tested it?

> +	/* eMMC is missing pull-ups */
> +	bias-pull-up;

This is the default now.

> +};
> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> index c680566..9de96ba 100644
> --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> @@ -151,6 +151,16 @@
>  				function = "uart0";
>  			};
>  
> +			uart1_pins: uart1@0 {
> +				pins = "PG6", "PG7";
> +				function = "uart1";
> +			};
> +
> +			uart1_pins_4: uart1_4@0 {
> +				pins = "PG6", "PG7", "PG8", "PG9";

For other nodes, we've been creating another node for the cts and rts
signals, and reference both nodes in the pinctrl properties. It allows
to avoid duplication.

> +				function = "uart1";
> +			};
> +
>  			mmc0_pins: mmc0@0 {

Please sort it by alphabetical order. And it should be in a separate
patch.

Thanks!
Maxime

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

^ permalink raw reply

* Re: [PATCH] ARM: dts: sunxi: Enable spi1 and spi2 for Olimex A20 SOM EVB
From: Emmanuel Vadot @ 2017-01-05 17:37 UTC (permalink / raw)
  To: Maxime Ripard
  Cc: mark.rutland, devicetree, linux, linux-kernel, wens, robh+dt,
	linux-arm-kernel
In-Reply-To: <20170105171601.us4wffupptilvvqp@lukather>


 Hi,

On Thu, 5 Jan 2017 18:16:01 +0100
Maxime Ripard <maxime.ripard@free-electrons.com> wrote:

> Hi,
> 
> On Mon, Dec 26, 2016 at 06:53:49PM +0100, Emmanuel Vadot wrote:
> > Enable the spi1 and spi2 node since the pins are exposed on the UEXT
> > connectors.
> > 
> > Signed-off-by: Emmanuel Vadot <manu@bidouilliste.com>
> > ---
> >  arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> > index 669a1c338c76..fa8c6f60552b 100644
> > --- a/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> > +++ b/arch/arm/boot/dts/sun7i-a20-olimex-som-evb.dts
> > @@ -300,12 +300,14 @@
> >  	pinctrl-names = "default";
> >  	pinctrl-0 = <&spi1_pins_a>,
> >  		    <&spi1_cs0_pins_a>;
> > +	status = "okay";
> >  };
> >  
> >  &spi2 {
> >  	pinctrl-names = "default";
> >  	pinctrl-0 = <&spi2_pins_a>,
> >  		    <&spi2_cs0_pins_a>;
> > +	status = "okay";
> >  };
> 
> Those nodes don't exist unfortunately. Maybe you forgot to send one
> patch?
> 
> Thanks!
> Maxime
> 
> -- 
> Maxime Ripard, Free Electrons
> Embedded Linux and Kernel engineering
> http://free-electrons.com

 It's based on a previous sent patch :
http://lists.infradead.org/pipermail/linux-arm-kernel/2016-November/469288.html

 You said you'll squash the two commits.

-- 
Emmanuel Vadot <manu@bidouilliste.com> <manu@freebsd.org>

^ permalink raw reply

* Re: [RFC 1/1] Changes to support the driver for platform device registration
From: Florian Fainelli @ 2017-01-05 17:43 UTC (permalink / raw)
  To: Raviteja Garimella, Rob Herring, Mark Rutland, Greg Kroah-Hartman,
	Felipe Balbi
  Cc: devicetree, linux-kernel, bcm-kernel-feedback-list, linux-usb
In-Reply-To: <1483604597-26160-2-git-send-email-raviteja.garimella@broadcom.com>

On 01/05/2017 12:23 AM, Raviteja Garimella wrote:
> -- Add OF based platform device registration
> -- Modify debug prints to be compatible with both pci and platform devices
> -- Add members to 'struct udc' for extcon and phy support
> -- Add checks to not process repeated calls to udc connect and
>    disconnect routines
> -- Kconfig changes

What you are doing in this patch is all well and good, but since you are
listing these changes, that means we should see 4/5 patches submitted to
this driver each one doing what you have as a bullet point.

Since you are adding Device Tree probing support to the driver, you also
need to create a proper binding document which describes the properties
and nodes.

Thank you
-- 
Florian

^ permalink raw reply

* Re: [PATCH 1/5] drivers: mmc: sunxi: fix A64 calibration routine
From: Maxime Ripard @ 2017-01-05 17:47 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Ulf Hansson, Chen-Yu Tsai, Hans De Goede, Icenowy Zheng,
	Mark Rutland, Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1483398226-29321-2-git-send-email-andre.przywara-5wv7dgnIgG8@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 1258 bytes --]

Hi,

On Mon, Jan 02, 2017 at 11:03:42PM +0000, Andre Przywara wrote:
> The calibration facility in the A64 MMC block seems to have been
> misunderstood: the result value is not the value to program into the
> delay bits, but is the number of delay cells that result in a full clock
> cycle delay. So this value has to be scaled by the desired phase, which
> we still have to know and program.
> Change the calibration routine to take a phase parameter and scale the
> calibration value accordingly.
> Also introduce sun50i-a64 delay parameters to store the required phase.
> Looking at the BSP kernel the sample delay for anything below HS200 is
> 0, so we go with that value.
> Once the driver supports HS200 and faster modes, we can enter confirmed
> working values in there.
> 
> Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>

Exactly how that works hasn't been confirmed, and the only thing that
this patch actually do is... nothing, since the delay is always 0. If
and when we get HS400 to work and we know for a fact how the
calibration works, then we'll be able to use it. Until then, we can
just clear those bits.

Maxime

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

^ permalink raw reply

* Re: [PATCH 3/5] arm64: dts: sun50i: add MMC nodes
From: Maxime Ripard @ 2017-01-05 17:50 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Ulf Hansson, Chen-Yu Tsai, Hans De Goede, Icenowy Zheng,
	Mark Rutland, Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1483398226-29321-4-git-send-email-andre.przywara-5wv7dgnIgG8@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 1909 bytes --]

On Mon, Jan 02, 2017 at 11:03:44PM +0000, Andre Przywara wrote:
> Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>
> ---
>  arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi | 67 +++++++++++++++++++++++++++
>  1 file changed, 67 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> index e0dcab8..c680566 100644
> --- a/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> +++ b/arch/arm64/boot/dts/allwinner/sun50i-a64.dtsi
> @@ -150,6 +150,32 @@
>  				pins = "PB8", "PB9";
>  				function = "uart0";
>  			};
> +
> +			mmc0_pins: mmc0@0 {
> +				pins = "PF0", "PF1", "PF2", "PF3", "PF4", "PF5";
> +				function = "mmc0";
> +				drive-strength = <30>;
> +			};
> +
> +			mmc0_default_cd_pin: mmc0_cd_pin@0 {
> +				pins = "PF6";
> +				function = "gpio_in";
> +				bias-pull-up;
> +			};
> +
> +			mmc1_pins: mmc1@0 {
> +				pins = "PG0", "PG1", "PG2", "PG3", "PG4", "PG5";
> +				function = "mmc1";
> +				drive-strength = <30>;
> +			};
> +
> +			mmc2_pins: mmc2@0 {
> +				pins = "PC1", "PC5", "PC6", "PC8", "PC9",
> +				       "PC10", "PC11", "PC12", "PC13", "PC14",
> +				       "PC15", "PC16";
> +				function = "mmc2";
> +				drive-strength = <30>;
> +			};
>  		};
>  
>  		uart0: serial@1c28000 {
> @@ -240,6 +266,47 @@
>  			#size-cells = <0>;
>  		};
>  
> +		mmc0: mmc@1c0f000 {
> +			compatible = "allwinner,sun50i-a64-mmc",
> +				     "allwinner,sun5i-a13-mmc";

That's not correct. There's a bunch of features that are broken
without A64-specific (or at least not present on the A13)
quirks. Those features include for example the SDIO aggregation that
are currently broken for all modes supported so far.

I was in holidays and send those patches tomorrow, but you were a bit
too quick :)

Maxime

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

^ permalink raw reply

* [PATCH v5 0/2] iio: adc: hx711: Add IIO driver for AVIA HX711 ADC
From: Andreas Klinger @ 2017-01-05 17:51 UTC (permalink / raw)
  To: devicetree, linux-iio
  Cc: linux-kernel, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, jic23, knaack.h, lars, pmeerw, ak

This series adds IIO driver support for the AVIA HX711 ADC which is 
mostly used in weighting cells.

The first patch adds the new DT binding for which a new vendor avia
was also added.

The second patch is the simple IIO driver implemented as ADC.
The protocol is specific to this device and implemented using GPIOs.

Documentation of the chip can be found here:

https://cdn.sparkfun.com/datasheets/Sensors/ForceFlex/hx711_english.pdf

Changes in v5:
The reviews of Peter and Jonathan induced some improvements and lined out
at least one bug

* Patch 1: "iio: adc: hx711: Add DT binding for avia,hx711"
  - put Acked-By once again on the patch

* Patch 2: "iio: adc: hx711: Add IIO driver for AVIA HX711"
  - improved ugly locking
  - replace devm_iio_device_register() by iio_device_register() because of
    regulator_disable() in remove()
  - added ...scale_available() functions for both channels
  - name channels directly 0 and 1 instead of #define HX711_CHAN_A...
  - added hx711_wait_for_ready() function which is called after every dummy
    read to get sure the DOUT line signals that the device is ready
  - without this check there are cases in which the clock cycle of the next
    read gets interpreted by the device as gain pulses!

Changes in v4:
Thanks to the thorough reviews and suggestions of Jonathan and Lars-Peter
the driver was reworked to better meet the standard ABI of IIO. 

* Patch 1: "iio: adc: hx711: Add DT binding for avia,hx711"
  - added attribute for regulator

* Patch 2: "iio: adc: hx711: Add IIO driver for AVIA HX711"
  - two read channels for physical channels A and B
  - remove gain attribute and use scale as read raw
  - offer scale_available attribute
  - introduced regulator as analog supply; mainly needed for calculating
    the scale
  - simplyfied use of GPIOs
  - measuring input and output with oszilloscope and revised timing behavior
  - many minor changes

Changes in v3:
moved gain from devicetree to sysfs, according to comment of Lars-Peter
Thanks for reviewing and giving suggestions

* Patch 1: "iio: adc: hx711: Add DT binding for avia,hx711"
  - removed property gain

* Patch 2: "iio: adc: hx711: Add IIO driver for AVIA HX711"
  - removed property gain from devicetree
  - added device attribute (rw) for gain
  - support reading from both channels now

Changes in v2:
Lots of updates thanks to Peters review.

* Patch 1: "iio: adc: hx711: Add DT binding for avia,hx711"
  - typo
  - removed unneded section

* Patch 2: "iio: adc: hx711: Add IIO driver for AVIA HX711"
  - updated help text in Kconfig
  - removed dead code
  - removed unused power management
  - reduced channel spec to what is actually used
  - added error handling in case reset of chip not possible

Andreas Klinger (2):
  iio: adc: hx711: Add DT binding for avia,hx711
  iio: adc: hx711: Add IIO driver for AVIA HX711

 .../devicetree/bindings/iio/adc/avia-hx711.txt     |  18 +
 .../devicetree/bindings/vendor-prefixes.txt        |   1 +
 drivers/iio/adc/Kconfig                            |  19 +
 drivers/iio/adc/Makefile                           |   1 +
 drivers/iio/adc/hx711.c                            | 531 +++++++++++++++++++++
 5 files changed, 570 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
 create mode 100644 drivers/iio/adc/hx711.c

-- 
2.1.4

^ permalink raw reply

* [PATCH v5 1/2] iio: adc: hx711: Add DT binding for avia,hx711
From: Andreas Klinger @ 2017-01-05 17:51 UTC (permalink / raw)
  To: devicetree, linux-iio
  Cc: linux-kernel, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, jic23, knaack.h, lars, pmeerw, ak

Add DT bindings for avia,hx711
Add vendor avia to vendor list

Signed-off-by: Andreas Klinger <ak@it-klinger.de>
Acked-by: Rob Herring <robh@kernel.org>
---
[PATCH v3 1/2] of this patch was Acked-by: Rob Herring <robh@kernel.org>
In v4 the regulator (avdd-supply) was added

 .../devicetree/bindings/iio/adc/avia-hx711.txt         | 18 ++++++++++++++++++
 Documentation/devicetree/bindings/vendor-prefixes.txt  |  1 +
 2 files changed, 19 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/avia-hx711.txt

diff --git a/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt b/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
new file mode 100644
index 000000000000..b3629405f568
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/avia-hx711.txt
@@ -0,0 +1,18 @@
+* AVIA HX711 ADC chip for weight cells
+  Bit-banging driver
+
+Required properties:
+ - compatible:	Should be "avia,hx711"
+ - sck-gpios:	Definition of the GPIO for the clock
+ - dout-gpios:	Definition of the GPIO for data-out
+		See Documentation/devicetree/bindings/gpio/gpio.txt
+ - avdd-supply:	Definition of the regulator used as analog supply
+
+Example:
+weight@0 {
+	compatible = "avia,hx711";
+	sck-gpios = <&gpio3 10 GPIO_ACTIVE_HIGH>;
+	dout-gpios = <&gpio0 7 GPIO_ACTIVE_HIGH>;
+	avdd-suppy = <&avdd>;
+};
+
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index 44ddc980b085..4696bb5c2198 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -32,6 +32,7 @@ atlas	Atlas Scientific LLC
 atmel	Atmel Corporation
 auo	AU Optronics Corporation
 avago	Avago Technologies
+avia	avia semiconductor
 avic	Shanghai AVIC Optoelectronics Co., Ltd.
 axis	Axis Communications AB
 boe	BOE Technology Group Co., Ltd.
-- 
2.1.4

^ permalink raw reply related

* [PATCH v5 2/2] iio: adc: hx711: Add IIO driver for AVIA HX711
From: Andreas Klinger @ 2017-01-05 17:51 UTC (permalink / raw)
  To: devicetree, linux-iio
  Cc: linux-kernel, robh+dt, pawel.moll, mark.rutland, ijc+devicetree,
	galak, jic23, knaack.h, lars, pmeerw, ak

This is the IIO driver for AVIA HX711 ADC which is mostly used in weighting
cells.

The protocol is quite simple and using GPIOs:
One GPIO is used as clock (SCK) while another GPIO is read (DOUT)

The raw value read from the chip is delivered. 
To get a weight one needs to subtract the zero offset and scale it.

Signed-off-by: Andreas Klinger <ak@it-klinger.de>
---
 drivers/iio/adc/Kconfig  |  19 ++
 drivers/iio/adc/Makefile |   1 +
 drivers/iio/adc/hx711.c  | 531 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 551 insertions(+)
 create mode 100644 drivers/iio/adc/hx711.c

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 932de1f9d1e7..1dcf2ace1697 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -205,6 +205,25 @@ config HI8435
 	  This driver can also be built as a module. If so, the module will be
 	  called hi8435.
 
+config HX711
+	tristate "AVIA HX711 ADC for weight cells"
+	depends on GPIOLIB
+	help
+	  If you say yes here you get support for AVIA HX711 ADC which is used
+	  for weigh cells
+
+	  This driver uses two GPIOs, one acts as the clock and controls the
+	  channel selection and gain, the other one is used for the measurement
+          data
+
+	  Currently the raw value is read from the chip and delivered.
+	  To get an actual weight one needs to subtract the
+	  zero offset and multiply by a scale factor.
+	  This should be done in userspace.
+
+	  This driver can also be built as a module. If so, the module will be
+	  called hx711.
+
 config INA2XX_ADC
 	tristate "Texas Instruments INA2xx Power Monitors IIO driver"
 	depends on I2C && !SENSORS_INA2XX
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index b1aa456e6af3..d46e289900ef 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CC10001_ADC) += cc10001_adc.o
 obj-$(CONFIG_DA9150_GPADC) += da9150-gpadc.o
 obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
 obj-$(CONFIG_HI8435) += hi8435.o
+obj-$(CONFIG_HX711) += hx711.o
 obj-$(CONFIG_IMX7D_ADC) += imx7d_adc.o
 obj-$(CONFIG_INA2XX_ADC) += ina2xx-adc.o
 obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
diff --git a/drivers/iio/adc/hx711.c b/drivers/iio/adc/hx711.c
new file mode 100644
index 000000000000..e41414556158
--- /dev/null
+++ b/drivers/iio/adc/hx711.c
@@ -0,0 +1,531 @@
+/*
+ * HX711: analog to digital converter for weight sensor module
+ *
+ * Copyright (c) 2016 Andreas Klinger <ak@it-klinger.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+/* gain to pulse and scale conversion */
+#define HX711_GAIN_MAX		3
+
+struct hx711_gain_to_scale {
+	int			gain;
+	int			gain_pulse;
+	int			scale;
+	int			channel;
+};
+
+/*
+ * .scale depends on AVDD which in turn is known as soon as the regulator
+ * is available
+ * therefore we set .scale in hx711_probe()
+ *
+ * channel A in documentation is channel 0 in source code
+ * channel B in documentation is channel 1 in source code
+ */
+static struct hx711_gain_to_scale hx711_gain_to_scale[HX711_GAIN_MAX] = {
+	{ 128, 1, 0, 0 },
+	{  32, 2, 0, 1 },
+	{  64, 3, 0, 0 }
+};
+
+static int hx711_get_gain_to_pulse(int gain)
+{
+	int i;
+
+	for (i = 0; i < HX711_GAIN_MAX; i++)
+		if (hx711_gain_to_scale[i].gain == gain)
+			return hx711_gain_to_scale[i].gain_pulse;
+	return 1;
+}
+
+static int hx711_get_gain_to_scale(int gain)
+{
+	int i;
+
+	for (i = 0; i < HX711_GAIN_MAX; i++)
+		if (hx711_gain_to_scale[i].gain == gain)
+			return hx711_gain_to_scale[i].scale;
+	return 0;
+}
+
+static int hx711_get_scale_to_gain(int scale)
+{
+	int i;
+
+	for (i = 0; i < HX711_GAIN_MAX; i++)
+		if (hx711_gain_to_scale[i].scale == scale)
+			return hx711_gain_to_scale[i].gain;
+	return -EINVAL;
+}
+
+struct hx711_data {
+	struct device		*dev;
+	struct gpio_desc	*gpiod_pd_sck;
+	struct gpio_desc	*gpiod_dout;
+	struct regulator	*reg_avdd;
+	int			gain_set;	/* gain set on device */
+	int			gain_chan_a;	/* gain for channel A */
+	struct mutex		lock;
+};
+
+static int hx711_cycle(struct hx711_data *hx711_data)
+{
+	int val;
+
+	/*
+	 * if preempted for more then 60us while PD_SCK is high:
+	 * hx711 is going in reset
+	 * ==> measuring is false
+	 */
+	preempt_disable();
+	gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
+	val = gpiod_get_value(hx711_data->gpiod_dout);
+	/*
+	 * here we are not waiting for 0.2 us as suggested by the datasheet,
+	 * because the oszilloscope showed in a test scenario
+	 * at least 1.15 us for PD_SCK high (T3 in datasheet)
+	 * and 0.56 us for PD_SCK low on TI Sitara with 800 MHz
+	 */
+	gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
+	preempt_enable();
+
+	return val;
+}
+
+static int hx711_read(struct hx711_data *hx711_data)
+{
+	int i, ret;
+	int value = 0;
+	int val = gpiod_get_value(hx711_data->gpiod_dout);
+
+	/* we double check if it's really down */
+	if (val)
+		return -EIO;
+
+	for (i = 0; i < 24; i++) {
+		value <<= 1;
+		ret = hx711_cycle(hx711_data);
+		if (ret)
+			value++;
+	}
+
+	value ^= 0x800000;
+
+	for (i = 0; i < hx711_get_gain_to_pulse(hx711_data->gain_set); i++)
+		hx711_cycle(hx711_data);
+
+	return value;
+}
+
+static int hx711_wait_for_ready(struct hx711_data *hx711_data)
+{
+	int i, val;
+
+	/*
+	 * a maximum reset cycle time of 56 ms was measured.
+	 * we round it up to 100 ms
+	 */
+	for (i = 0; i < 100; i++) {
+		val = gpiod_get_value(hx711_data->gpiod_dout);
+		if (!val)
+			break;
+		/* sleep at least 1 ms */
+		msleep(1);
+	}
+	if (val)
+		return -EIO;
+
+	return 0;
+}
+
+static int hx711_reset(struct hx711_data *hx711_data)
+{
+	int ret;
+	int val = gpiod_get_value(hx711_data->gpiod_dout);
+
+	if (val) {
+		/*
+		 * an examination with the oszilloscope indicated
+		 * that the first value read after the reset is not stable
+		 * if we reset too short;
+		 * the shorter the reset cycle
+		 * the less reliable the first value after reset is;
+		 * there were no problems encountered with a value
+		 * of 10 ms or higher
+		 */
+		gpiod_set_value(hx711_data->gpiod_pd_sck, 1);
+		msleep(10);
+		gpiod_set_value(hx711_data->gpiod_pd_sck, 0);
+
+		ret = hx711_wait_for_ready(hx711_data);
+		if (ret)
+			return ret;
+		/*
+		 * after a reset the gain is 128 so we do a dummy read
+		 * to set the gain for the next read
+		 */
+		ret = hx711_read(hx711_data);
+		if (ret < 0)
+			return ret;
+
+		/*
+		 * after a dummy read we need to wait vor readiness
+		 * for not mixing gain pulses with the clock
+		 */
+		ret = hx711_wait_for_ready(hx711_data);
+		if (ret)
+			return ret;
+	}
+
+	return val;
+}
+
+static int hx711_set_gain_for_channel(struct hx711_data *hx711_data, int chan)
+{
+	int ret;
+
+	if (chan == 0) {
+		if (hx711_data->gain_set == 32) {
+			hx711_data->gain_set = hx711_data->gain_chan_a;
+
+			ret = hx711_read(hx711_data);
+			if (ret < 0)
+				return ret;
+
+			ret = hx711_wait_for_ready(hx711_data);
+			if (ret)
+				return ret;
+		}
+	} else {
+		if (hx711_data->gain_set != 32) {
+			hx711_data->gain_set = 32;
+
+			ret = hx711_read(hx711_data);
+			if (ret < 0)
+				return ret;
+
+			ret = hx711_wait_for_ready(hx711_data);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int hx711_read_raw(struct iio_dev *indio_dev,
+				const struct iio_chan_spec *chan,
+				int *val, int *val2, long mask)
+{
+	struct hx711_data *hx711_data = iio_priv(indio_dev);
+	int ret;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		mutex_lock(&hx711_data->lock);
+
+		/*
+		 * hx711_reset() must be called from here
+		 * because it could be calling hx711_read() by itself
+		 */
+		if (hx711_reset(hx711_data)) {
+			dev_err(hx711_data->dev, "reset failed!");
+			return -EIO;
+		}
+
+		ret = hx711_set_gain_for_channel(hx711_data, chan->channel);
+		if (ret < 0) {
+			mutex_unlock(&hx711_data->lock);
+			return ret;
+		}
+
+		*val = hx711_read(hx711_data);
+
+		mutex_unlock(&hx711_data->lock);
+
+		if (*val < 0)
+			return *val;
+		return IIO_VAL_INT;
+	case IIO_CHAN_INFO_SCALE:
+		*val = 0;
+		mutex_lock(&hx711_data->lock);
+
+		*val2 = hx711_get_gain_to_scale(hx711_data->gain_set);
+
+		mutex_unlock(&hx711_data->lock);
+
+		return IIO_VAL_INT_PLUS_NANO;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int hx711_write_raw(struct iio_dev *indio_dev,
+				struct iio_chan_spec const *chan,
+				int val,
+				int val2,
+				long mask)
+{
+	struct hx711_data *hx711_data = iio_priv(indio_dev);
+	int ret;
+	int gain;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_SCALE:
+		/*
+		 * a scale greater than 1 mV per LSB is not possible
+		 * with the HX711, therefore val must be 0
+		 */
+		if (val != 0)
+			return -EINVAL;
+
+		mutex_lock(&hx711_data->lock);
+
+		gain = hx711_get_scale_to_gain(val2);
+		if (gain < 0) {
+			mutex_unlock(&hx711_data->lock);
+			return gain;
+		}
+
+		if (gain != hx711_data->gain_set) {
+			hx711_data->gain_set = gain;
+			if (gain != 32)
+				hx711_data->gain_chan_a = gain;
+
+			ret = hx711_read(hx711_data);
+			if (ret < 0) {
+				mutex_unlock(&hx711_data->lock);
+				return ret;
+			}
+		}
+
+		mutex_unlock(&hx711_data->lock);
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int hx711_write_raw_get_fmt(struct iio_dev *indio_dev,
+		struct iio_chan_spec const *chan,
+		long mask)
+{
+	return IIO_VAL_INT_PLUS_NANO;
+}
+
+static ssize_t hx711_scale_available_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct iio_dev_attr *iio_attr = to_iio_dev_attr(attr);
+	int channel = iio_attr->address;
+	int i, len = 0;
+
+	for (i = 0; i < HX711_GAIN_MAX; i++)
+		if (hx711_gain_to_scale[i].channel == channel)
+			len += sprintf(buf + len, "0.%09d ",
+					hx711_gain_to_scale[i].scale);
+
+	len += sprintf(buf + len, "\n");
+
+	return len;
+}
+
+static IIO_DEVICE_ATTR(in_voltage0_scale_available, S_IRUGO,
+	hx711_scale_available_show, NULL, 0);
+
+static IIO_DEVICE_ATTR(in_voltage1_scale_available, S_IRUGO,
+	hx711_scale_available_show, NULL, 1);
+
+static struct attribute *hx711_attributes[] = {
+	&iio_dev_attr_in_voltage0_scale_available.dev_attr.attr,
+	&iio_dev_attr_in_voltage1_scale_available.dev_attr.attr,
+	NULL,
+};
+
+static struct attribute_group hx711_attribute_group = {
+	.attrs = hx711_attributes,
+};
+
+static const struct iio_info hx711_iio_info = {
+	.driver_module		= THIS_MODULE,
+	.read_raw		= hx711_read_raw,
+	.write_raw		= hx711_write_raw,
+	.write_raw_get_fmt	= hx711_write_raw_get_fmt,
+	.attrs			= &hx711_attribute_group,
+};
+
+static const struct iio_chan_spec hx711_chan_spec[] = {
+	{
+		.type = IIO_VOLTAGE,
+		.channel = 0,
+		.indexed = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+	},
+	{
+		.type = IIO_VOLTAGE,
+		.channel = 1,
+		.indexed = 1,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+		.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE),
+	},
+};
+
+static int hx711_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct hx711_data *hx711_data;
+	struct iio_dev *indio_dev;
+	int ret;
+	int i;
+
+	indio_dev = devm_iio_device_alloc(dev, sizeof(struct hx711_data));
+	if (!indio_dev) {
+		dev_err(dev, "failed to allocate IIO device\n");
+		return -ENOMEM;
+	}
+
+	hx711_data = iio_priv(indio_dev);
+	hx711_data->dev = dev;
+
+	mutex_init(&hx711_data->lock);
+
+	/*
+	 * PD_SCK stands for power down and serial clock input of HX711
+	 * in the driver it is an output
+	 */
+	hx711_data->gpiod_pd_sck = devm_gpiod_get(dev, "sck", GPIOD_OUT_LOW);
+	if (IS_ERR(hx711_data->gpiod_pd_sck)) {
+		dev_err(dev, "failed to get sck-gpiod: err=%ld\n",
+					PTR_ERR(hx711_data->gpiod_pd_sck));
+		return PTR_ERR(hx711_data->gpiod_pd_sck);
+	}
+
+	/*
+	 * DOUT stands for serial data output of HX711
+	 * for the driver it is an input
+	 */
+	hx711_data->gpiod_dout = devm_gpiod_get(dev, "dout", GPIOD_IN);
+	if (IS_ERR(hx711_data->gpiod_dout)) {
+		dev_err(dev, "failed to get dout-gpiod: err=%ld\n",
+					PTR_ERR(hx711_data->gpiod_dout));
+		return PTR_ERR(hx711_data->gpiod_dout);
+	}
+
+	hx711_data->reg_avdd = devm_regulator_get(dev, "avdd");
+	if (IS_ERR(hx711_data->reg_avdd))
+		return PTR_ERR(hx711_data->reg_avdd);
+
+	ret = regulator_enable(hx711_data->reg_avdd);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * with
+	 * full scale differential input range: AVDD / GAIN
+	 * full scale output data: 2^24
+	 * we can say:
+	 *     AVDD / GAIN = 2^24
+	 * therefore:
+	 *     1 LSB = AVDD / GAIN / 2^24
+	 * AVDD is in uV, but we need 10^-9 mV
+	 * approximately to fit into a 32 bit number:
+	 * 1 LSB = (AVDD * 100) / GAIN / 1678 [10^-9 mV]
+	 */
+	ret = regulator_get_voltage(hx711_data->reg_avdd);
+	if (ret < 0) {
+		regulator_disable(hx711_data->reg_avdd);
+		return ret;
+	}
+	/* we need 10^-9 mV */
+	ret *= 100;
+
+	for (i = 0; i < HX711_GAIN_MAX; i++)
+		hx711_gain_to_scale[i].scale =
+			ret / hx711_gain_to_scale[i].gain / 1678;
+
+	hx711_data->gain_set = 128;
+	hx711_data->gain_chan_a = 128;
+
+	platform_set_drvdata(pdev, indio_dev);
+
+	indio_dev->name = "hx711";
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->info = &hx711_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+	indio_dev->channels = hx711_chan_spec;
+	indio_dev->num_channels = ARRAY_SIZE(hx711_chan_spec);
+
+	ret = iio_device_register(indio_dev);
+	if (ret < 0) {
+		dev_err(dev, "Couldn't register the device\n");
+		regulator_disable(hx711_data->reg_avdd);
+	}
+
+	return ret;
+}
+
+static int hx711_remove(struct platform_device *pdev)
+{
+	struct hx711_data *hx711_data;
+	struct iio_dev *indio_dev;
+
+	indio_dev = platform_get_drvdata(pdev);
+	hx711_data = iio_priv(indio_dev);
+
+	iio_device_unregister(indio_dev);
+
+	regulator_disable(hx711_data->reg_avdd);
+
+	return 0;
+}
+
+static const struct of_device_id of_hx711_match[] = {
+	{ .compatible = "avia,hx711", },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, of_hx711_match);
+
+static struct platform_driver hx711_driver = {
+	.probe		= hx711_probe,
+	.remove		= hx711_remove,
+	.driver		= {
+		.name		= "hx711-gpio",
+		.of_match_table	= of_hx711_match,
+	},
+};
+
+module_platform_driver(hx711_driver);
+
+MODULE_AUTHOR("Andreas Klinger <ak@it-klinger.de>");
+MODULE_DESCRIPTION("HX711 bitbanging driver - ADC for weight cells");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:hx711-gpio");
+
-- 
2.1.4

^ permalink raw reply related

* Re: [PATCH 1/6] ARM: dts: am335x-phycore-som: Update NAND partition table
From: Brian Norris @ 2017-01-05 17:56 UTC (permalink / raw)
  To: Tony Lindgren
  Cc: Mark Rutland, devicetree, Brian Norris, Rob Herring, linux-mtd,
	Benoît Cousson, Teresa Remmet, linux-omap, Adam Ford,
	linux-arm-kernel
In-Reply-To: <20170105171845.GK4310@atomide.com>

On Thu, Jan 05, 2017 at 09:18:45AM -0800, Tony Lindgren wrote:
> * Tony Lindgren <tony@atomide.com> [170105 07:37]:
> > * Teresa Remmet <t.remmet@phytec.de> [170105 06:57]:
> > > To improve NAND safety we updated the partition layout.
> > > Added barebox backup partition and removed kernel and oftree
> > > partition. They are kept in ubi now.
> > 
> > What about the users with earlier partition tables?
> > 
> > Please read about "flag day" changes, typically they are not
> > acceptable.
> 
> Adding Brian and Adam to Cc. Can you guys come up with some
> solution on this?

I don't have much context for this thread, and no I don't plan to solve
your problems for you. But I can provide tips!

> I'm suggesting we leave the kernel nodes empty and let u-boot
> populate them, so maybe you guys can discuss this on the related
> lists.

That's an option. I've worked with platforms that did something like
this, and that's really one of the only ways you can handle putting
partition information in the device tree. You're really hamstringing
yourself when you put all the partition information in the device tree.
And it's just dumb once that gets codified in the kernel source tree.

The best solution would be to try to migrate away from static device
tree representations of partition info entirely. UBI volumes are best
where possible. If not, then some other kind of on-flash data structures
(along the lines of a GPT) with a corresponding MTD partition parser is
an OK alternative. Unfortunately, there isn't any good standard format
for this on MTD, so it's typically all custom -- and so people use the
easiest approach: device tree. And it's even more difficult with NAND,
which has reliability problems, especially with static data (e.g., read
disturb).

Anyway, the parser solution is helpful only if one can properly fix the
"flag day" first. And it requires a little bit more work to be generally
useful; I posted some work for this over a year ago, but bikeshedding
brought it down.

> The rest of the series looks fine to me so applying it into
> omap-for-v4.11/dt.

Brian

^ permalink raw reply

* Re: [PATCH 2/5] drivers: mmc: sunxi: limit A64 MMC2 to 8K DMA buffer
From: Maxime Ripard @ 2017-01-05 17:57 UTC (permalink / raw)
  To: Rob Herring
  Cc: Andre Przywara, Ulf Hansson, Chen-Yu Tsai, Hans De Goede,
	Icenowy Zheng, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-mmc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <20170104140750.7qs4pvggwjdj5cma@rob-hp-laptop>

[-- Attachment #1: Type: text/plain, Size: 1719 bytes --]

Hi Rob,

On Wed, Jan 04, 2017 at 08:07:50AM -0600, Rob Herring wrote:
> On Mon, Jan 02, 2017 at 11:03:43PM +0000, Andre Przywara wrote:
> > From: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > 
> > Unlike the A64 user manual reports, the third MMC controller on the
> > A64 (and the only one capable of 8-bit HS400 eMMC transfers) has a
> > DMA buffer size limit of 8KB (much like the very old Allwinner SoCs).
> > This does not affect the other two controllers, so introduce a new
> > DT compatible string to let the driver use different settings for that
> > particular device. This will also help to enable the high-speed transfer
> > modes of that controller later.
> > 
> > Signed-off-by: Maxime Ripard <maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> > Signed-off-by: Andre Przywara <andre.przywara-5wv7dgnIgG8@public.gmane.org>
> > ---
> >  Documentation/devicetree/bindings/mmc/sunxi-mmc.txt | 1 +
> >  drivers/mmc/host/sunxi-mmc.c                        | 7 +++++++
> >  2 files changed, 8 insertions(+)
> 
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>

Some kind of a digression on this: we have three MMC controllers on
this SoC. Like this patch shows, the third one is clearly different,
and supports both more modes, a wider bus, and specific quirks. We
need a new compatible for this one, everything's perfect.

However, the other two are mostly the same, but seems to need
different tuning parameters to get more performances out of the
controller (but this is unclear yet). How do we usually deal with
that?

Thanks,
Maxime

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

^ permalink raw reply

* Re: [PATCH 1/1] spi: imx: support to set watermark level via DTS
From: Mark Brown @ 2017-01-05 17:58 UTC (permalink / raw)
  To: Jiada Wang; +Cc: robh+dt, mark.rutland, linux-spi, devicetree, linux-kernel
In-Reply-To: <20170105061015.7816-1-jiada_wang@mentor.com>

[-- Attachment #1: Type: text/plain, Size: 557 bytes --]

On Thu, Jan 05, 2017 at 03:10:15PM +0900, Jiada Wang wrote:

> Previously watermark level is configured to fifosize/2,
> DMA mode can be used only when transfer length can be divided
> by 'watermark level * bpw', which makes DMA mode not practical.

> This patch adds new DTS property 'dma-wml', user can configure
> DMA watermark level, by specify 'dma-wml' in corresponding ecspi
> node.

Doesn't this just move the problem around a bit - can we not have the
driver figure out a more sensible watermark for each transfer rather
than fixing one in the DT?

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]

^ permalink raw reply


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