Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH 06/16] regulator: madera-ldo1: LDO1 driver for Cirrus Logic Madera codecs
From: Mark Brown @ 2017-04-10 18:11 UTC (permalink / raw)
  To: Rob Herring
  Cc: gnurou, alsa-devel, jason, devicetree, Richard Fitzgerald,
	linus.walleij, patches, linux-kernel, linux-gpio, tglx, lee.jones
In-Reply-To: <20170410174917.dlklrvw2sraeq6xs@rob-hp-laptop>


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

On Mon, Apr 10, 2017 at 12:49:17PM -0500, Rob Herring wrote:

> Same question as Mark. Should this share bindings with arizona? The 
> arizona one looks a bit strange, so not sure we'd want to just copy it.

In what way?  Other than the -gpios stuff (which would just be a trivial
thing if we wanted to change it)?

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

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



^ permalink raw reply

* Re: [PATCH v4 1/9] pinctrl: generic: Add bi-directional and output-enable
From: Rob Herring @ 2017-04-10 18:06 UTC (permalink / raw)
  To: Jacopo Mondi
  Cc: linus.walleij, geert+renesas, laurent.pinchart, chris.brandt,
	mark.rutland, linux, linux-renesas-soc, linux-gpio, devicetree,
	linux-kernel
In-Reply-To: <1491401247-7030-2-git-send-email-jacopo+renesas@jmondi.org>

On Wed, Apr 05, 2017 at 04:07:19PM +0200, Jacopo Mondi wrote:
> Add bi-directional and output-enable pin configuration properties.
> 
> bi-directional allows to specify when a pin shall operate in input and
> output mode at the same time. This is particularly useful in platforms
> where input and output buffers have to be manually enabled.
> 
> output-enable is just syntactic sugar to specify that a pin shall
> operate in output mode, ignoring the provided argument.
> This pairs with input-enable pin configuration option.
> 
> Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
> ---
>  Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt | 2 ++
>  drivers/pinctrl/pinconf-generic.c                              | 3 +++
>  include/linux/pinctrl/pinconf-generic.h                        | 3 +++
>  3 files changed, 8 insertions(+)

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply

* Re: [PATCH 13/16] ASoC: madera: Add common support for Cirrus Logic Madera codecs
From: Rob Herring @ 2017-04-10 18:03 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: linus.walleij, gnurou, tglx, jason, lee.jones, broonie,
	alsa-devel, patches, linux-gpio, devicetree, linux-kernel
In-Reply-To: <1491386884-30689-14-git-send-email-rf@opensource.wolfsonmicro.com>

On Wed, Apr 05, 2017 at 11:08:01AM +0100, Richard Fitzgerald wrote:
> The Cirrus Logic Madera codecs are a family of related codecs with
> extensive digital and analogue I/O, digital mixing and routing,
> signal processing and programmable DSPs.
> 
> This patch adds common support code shared by all Madera codecs.
> 
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> Signed-off-by: Nariman Poushin <nariman@opensource.wolfsonmicro.com>
> Signed-off-by: Nikesh Oswal <Nikesh.Oswal@wolfsonmicro.com>
> Signed-off-by: Piotr Stankiewicz <piotrs@opensource.wolfsonmicro.com>
> Signed-off-by: Ajit Pandey <ajit.pandey@incubesol.com>
> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> ---
>  Documentation/devicetree/bindings/sound/madera.txt |   63 +
>  MAINTAINERS                                        |    5 +
>  include/dt-bindings/sound/madera.h                 |   18 +

Acked-by: Rob Herring <robh@kernel.org>

>  include/sound/madera-pdata.h                       |   70 +
>  sound/soc/codecs/Kconfig                           |    5 +
>  sound/soc/codecs/Makefile                          |    2 +
>  sound/soc/codecs/madera.c                          | 4430 ++++++++++++++++++++
>  sound/soc/codecs/madera.h                          |  470 +++
>  8 files changed, 5063 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/madera.txt
>  create mode 100644 include/dt-bindings/sound/madera.h
>  create mode 100644 include/sound/madera-pdata.h
>  create mode 100644 sound/soc/codecs/madera.c
>  create mode 100644 sound/soc/codecs/madera.h

^ permalink raw reply

* Re: [PATCH 09/16] pinctrl: madera: Add driver for Cirrus Logic Madera codecs
From: Rob Herring @ 2017-04-10 17:56 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: gnurou, alsa-devel, jason, devicetree, linus.walleij, patches,
	linux-kernel, linux-gpio, broonie, tglx, lee.jones
In-Reply-To: <1491386884-30689-10-git-send-email-rf@opensource.wolfsonmicro.com>

On Wed, Apr 05, 2017 at 11:07:57AM +0100, Richard Fitzgerald wrote:
> These codecs have a variable number of I/O lines each of which
> is individually selectable to a wide range of possible functions.
> 
> The functionality is slightly different from the traditional muxed
> GPIO since most of the functions can be mapped to any pin (and even
> the same function to multiple pins). Most pins have a dedicated
> "alternate" function that is only available on that pin. The
> alternate functions are usually a group of signals, though it is
> not always necessary to enable the full group, depending on the
> alternate function and how it is to be used. The mapping between
> alternate functions and GPIO pins varies between codecs depending
> on the number of alternate functions and available pins.
> 
> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> ---
>  .../bindings/pinctrl/cirrus,madera-pinctrl.txt     |  103 ++

As Linus said, separate patch is preferred. But I don't have any other 
comments, so I'm not going to require it:

Acked-by: Rob Herring <robh@kernel.org>

>  MAINTAINERS                                        |    2 +
>  drivers/pinctrl/Kconfig                            |   22 +
>  drivers/pinctrl/Makefile                           |    1 +
>  drivers/pinctrl/pinctrl-madera.c                   | 1092 ++++++++++++++++++++
>  5 files changed, 1220 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pinctrl/cirrus,madera-pinctrl.txt
>  create mode 100644 drivers/pinctrl/pinctrl-madera.c

^ permalink raw reply

* Re: [PATCH 08/16] irqchip: Add driver for Cirrus Logic Madera codecs
From: Rob Herring @ 2017-04-10 17:53 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: gnurou, alsa-devel, jason, devicetree, linus.walleij, patches,
	linux-kernel, linux-gpio, broonie, tglx, lee.jones
In-Reply-To: <1491386884-30689-9-git-send-email-rf@opensource.wolfsonmicro.com>

On Wed, Apr 05, 2017 at 11:07:56AM +0100, Richard Fitzgerald wrote:
> The Cirrus Logic Madera codecs (Cirrus Logic CS47L35/85/90/91 and WM1840)
> are highly complex devices containing up to 7 programmable DSPs and many
> other internal sources of interrupts plus a number of GPIOs that can be
> used as interrupt inputs. The large number (>150) of internal interrupt
> sources are managed by an on-board interrupt controller.
> 
> This driver provides the handling for the interrupt controller. As the
> codec is accessed via regmap, we can make use of the generic IRQ
> functionality from regmap to do most of the work. Only around half of
> the possible interrupt source are currently of interest from the driver
> so only this subset is defined. Others can be added in future if needed.
> 
> The KConfig options are not user-configurable because this driver is
> mandatory so is automatically included when the parent MFD driver is
> selected.
> 
> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  .../interrupt-controller/cirrus,madera.txt         |  31 ++
>  MAINTAINERS                                        |   3 +
>  drivers/irqchip/Kconfig                            |   5 +
>  drivers/irqchip/Makefile                           |   1 +
>  drivers/irqchip/irq-madera.c                       | 349 +++++++++++++++++++++
>  include/linux/irqchip/irq-madera-pdata.h           |  19 ++
>  include/linux/irqchip/irq-madera.h                 |  96 ++++++
>  7 files changed, 504 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/interrupt-controller/cirrus,madera.txt
>  create mode 100644 drivers/irqchip/irq-madera.c
>  create mode 100644 include/linux/irqchip/irq-madera-pdata.h
>  create mode 100644 include/linux/irqchip/irq-madera.h
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/cirrus,madera.txt b/Documentation/devicetree/bindings/interrupt-controller/cirrus,madera.txt
> new file mode 100644
> index 0000000..4505315
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/interrupt-controller/cirrus,madera.txt
> @@ -0,0 +1,31 @@
> +Cirrus Logic Madera class audio codec IRQ driver
> +
> +The IRQ properties are members of the parent MFD node.

Just document them in the MFD binding.

> +
> +See also the core bindings for the parent MFD driver:
> +See Documentation/devicetree/bindings/mfd/madera.txt
> +
> +Required properties:
> +  - interrupt-controller : Madera class devices contain interrupt controllers
> +    and may provide interrupt services to other devices.
> +
> +  - #interrupt-cells: the number of cells to describe an IRQ, this should be 2.
> +    The first cell is the IRQ number.
> +    The second cell is the flags, encoded as the trigger masks from
> +    bindings/interrupt-controller/interrupts.txt
> +
> +  - interrupts : The interrupt line the /IRQ signal for the device is
> +    connected to.
> +
> +  - interrupt-parent : The parent interrupt controller.
> +
> +Example:
> +
> +codec: cs47l85@0 {
> +	compatible = "cirrus,cs47l85";
> +
> +	interrupt-controller;
> +	#interrupt-cells = <2>;
> +	interrupts = <&host_irq1>;
> +	interrupt-parent = <&gic>;
> +};

^ permalink raw reply

* Re: [PATCH 06/16] regulator: madera-ldo1: LDO1 driver for Cirrus Logic Madera codecs
From: Rob Herring @ 2017-04-10 17:49 UTC (permalink / raw)
  To: Richard Fitzgerald
  Cc: linus.walleij, gnurou, tglx, jason, lee.jones, broonie,
	alsa-devel, patches, linux-gpio, devicetree, linux-kernel
In-Reply-To: <1491386884-30689-7-git-send-email-rf@opensource.wolfsonmicro.com>

On Wed, Apr 05, 2017 at 11:07:54AM +0100, Richard Fitzgerald wrote:
> This patch adds a driver for the internal LDO1 regulator on
> some Cirrus Logic Madera class codecs.
> 
> Signed-off-by: Richard Fitzgerald <rf@opensource.wolfsonmicro.com>
> Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
> ---
>  .../devicetree/bindings/regulator/madera-ldo1.txt  |  29 +++

cirrus-madera-ldo1.txt

Or perhaps a subdirectory. We should have done the same for arizona 
bindings.

Same question as Mark. Should this share bindings with arizona? The 
arizona one looks a bit strange, so not sure we'd want to just copy it.

>  MAINTAINERS                                        |   3 +
>  drivers/regulator/Kconfig                          |   8 +
>  drivers/regulator/Makefile                         |   1 +
>  drivers/regulator/madera-ldo1.c                    | 198 +++++++++++++++++++++
>  include/linux/regulator/madera-ldo1.h              |  24 +++
>  6 files changed, 263 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/regulator/madera-ldo1.txt
>  create mode 100644 drivers/regulator/madera-ldo1.c
>  create mode 100644 include/linux/regulator/madera-ldo1.h
> 
> diff --git a/Documentation/devicetree/bindings/regulator/madera-ldo1.txt b/Documentation/devicetree/bindings/regulator/madera-ldo1.txt
> new file mode 100644
> index 0000000..688f21d
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/regulator/madera-ldo1.txt
> @@ -0,0 +1,29 @@
> +Cirrus Logic Madera class audio codecs LDO1 regulator driver
> +
> +Only required if you are using the codec internal LDO1 regulator.
> +This is a subnode of the parent mfd node.
> +
> +See also the core bindings for the parent MFD driver:
> +See Documentation/devicetree/bindings/mfd/madera.txt
> +
> +Required properties:
> +  - compatible :  must be "cirrus,madera-ldo1"
> +  - LDOVDD-supply : Power supply for the LDO1 regulator.
> +
> +  - enable-gpio	: GPIO to use to enable/disable the regulator.

enable-gpios

And define whether active high or low.

> +    As defined in bindings/gpio.txt.
> +
> +Optional subnodes:
> +  Standard regulator bindings as described in bindings/regulator/regulator.txt
> +
> +Example:
> +
> +codec: cs47l85@0 {
> +	compatible = "cirrus,cs47l85";
> +
> +	ldo1 {
> +		compatible = "cirrus,madera-ldo1";
> +		LDOVDD-supply = <&pmic_vdd1>;
> +		enable-gpio = <&gpio 0>;
> +	};
> +};

^ permalink raw reply

* Re: [PATCHv3 02/10] serdev: add serdev_device_wait_until_sent
From: Sebastian Reichel @ 2017-04-10 17:10 UTC (permalink / raw)
  To: Rob Herring
  Cc: Greg Kroah-Hartman, Marcel Holtmann, Gustavo Padovan,
	Johan Hedberg, Samuel Thibault, Pavel Machek, Tony Lindgren,
	Jiri Slaby, Mark Rutland, open list:BLUETOOTH DRIVERS,
	linux-serial@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Andrey Smirnov
In-Reply-To: <CAL_JsqJCjob6NDfHe0r7X3dXPEniKh5vChXhBxfyHZRu7Fov7A@mail.gmail.com>

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

Hi,

On Mon, Apr 10, 2017 at 11:12:39AM -0500, Rob Herring wrote:
> On Mon, Apr 10, 2017 at 9:03 AM, Greg Kroah-Hartman
> <gregkh@linuxfoundation.org> wrote:
> > On Mon, Apr 10, 2017 at 08:46:57AM -0500, Rob Herring wrote:
> >> On Sat, Apr 8, 2017 at 11:57 AM, Greg Kroah-Hartman
> >> <gregkh@linuxfoundation.org> wrote:
> >> > On Tue, Mar 28, 2017 at 05:59:31PM +0200, Sebastian Reichel wrote:
> >> >> Add method, which waits until the transmission buffer has been sent.
> >> >> Note, that the change in ttyport_write_wakeup is related, since
> >> >> tty_wait_until_sent will hang without that change.
> >> >>
> >> >> Acked-by: Rob Herring <robh@kernel.org>
> >> >> Acked-by: Pavel Machek <pavel@ucw.cz>
> >> >> Signed-off-by: Sebastian Reichel <sre@kernel.org>
> >> >> ---
> >> >> Changes since PATCHv2:
> >> >>  * Avoid goto in ttyport_write_wakeup
> >> >> ---
> >> >>  drivers/tty/serdev/core.c           | 11 +++++++++++
> >> >>  drivers/tty/serdev/serdev-ttyport.c | 18 ++++++++++++++----
> >> >>  include/linux/serdev.h              |  3 +++
> >> >>  3 files changed, 28 insertions(+), 4 deletions(-)
> >> >>
> >> >> diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
> >> >> index f4c6c90add78..a63b74031e22 100644
> >> >> --- a/drivers/tty/serdev/core.c
> >> >> +++ b/drivers/tty/serdev/core.c
> >> >> @@ -173,6 +173,17 @@ void serdev_device_set_flow_control(struct serdev_device *serdev, bool enable)
> >> >>  }
> >> >>  EXPORT_SYMBOL_GPL(serdev_device_set_flow_control);
> >> >>
> >> >> +void serdev_device_wait_until_sent(struct serdev_device *serdev, long timeout)
> >> >> +{
> >> >> +     struct serdev_controller *ctrl = serdev->ctrl;
> >> >> +
> >> >> +     if (!ctrl || !ctrl->ops->wait_until_sent)
> >> >> +             return;
> >> >> +
> >> >> +     ctrl->ops->wait_until_sent(ctrl, timeout);
> >> >> +}
> >> >> +EXPORT_SYMBOL_GPL(serdev_device_wait_until_sent);
> >> >
> >> > Is this still needed now that we have serdev_device_write() with an
> >> > unlimited timeout available?
> >>
> >> Yes, because only this waits until the data is on the wire.
> >
> > What "wire" is that?  The serial wire?  How do you know this?  Many usb
> > to serial devices have no way to determine this, given that there is
> > another uart hanging off of the end of a USB connection.
> 
> Okay, maybe it's just out of linux s/w buffers for h/w which you don't
> know. It is the same semantics as tty_wait_until_sent which is
> documented as: "Wait for characters pending in a tty driver to hit the
> wire, or for a timeout to occur (eg due to flow control)"

For embedded h/w it usually means the serial wire. tty_wait_until_sent()
first waits for the tty buffer to be empty and then calls wait_until_sent()
in the driver providing the tty. In case of serial-core that is
implemented by uart_wait_until_sent(), which waits for the serial
driver's tx_empty() operation becoming true (grepping for
".tx_empty" returned 81 hits for me). Also at least some of the usb to
serial adapters seem to support this using usb_serial_generic_wait_until_sent()
and ".tx_empty":

$ git grep "\.tx_empty"
cp210x.c:       .tx_empty               = cp210x_tx_empty,
f81534.c:       .tx_empty =             f81534_tx_empty,
ftdi_sio.c:     .tx_empty =             ftdi_tx_empty,
io_ti.c:        .tx_empty               = edge_tx_empty,
io_ti.c:        .tx_empty               = edge_tx_empty,
mxuport.c:      .tx_empty               = mxuport_tx_empty,
ti_usb_3410_5052.c:     .tx_empty               = ti_tx_empty,
ti_usb_3410_5052.c:     .tx_empty               = ti_tx_empty,

The other ones will only wait for empty s/w buffer, but that's
already the case for tty_wait_until_sent(), so IMHO a different
problem.

-- Sebastian

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

^ permalink raw reply

* Re: [PATCH v2 2/2] mtd: spi-nor: add driver for STM32 quad spi flash controller
From: Ludovic BARRE @ 2017-04-10 16:52 UTC (permalink / raw)
  To: Marek Vasut, Cyrille Pitchen
  Cc: Boris Brezillon, Alexandre Torgue, devicetree, Richard Weinberger,
	linux-kernel, Rob Herring, linux-mtd, Brian Norris,
	David Woodhouse
In-Reply-To: <9a0c5f8e-01dc-3d2b-5ebb-069752594e8e@gmail.com>

hi Marek

tomorrow, I send a v3 with your/Rob reviews.

BR

Ludo


On 04/10/2017 06:15 PM, Marek Vasut wrote:
> On 04/10/2017 11:08 AM, Ludovic BARRE wrote:
>> On 04/07/2017 01:55 AM, Marek Vasut wrote:
>>> On 03/31/2017 07:02 PM, Ludovic Barre wrote:
>>>> From: Ludovic Barre <ludovic.barre@st.com>
>>>>
>>>> The quadspi is a specialized communication interface targeting single,
>>>> dual or quad SPI Flash memories.
>>>>
>>>> It can operate in any of the following modes:
>>>> -indirect mode: all the operations are performed using the quadspi
>>>>    registers
>>>> -read memory-mapped mode: the external Flash memory is mapped to the
>>>>    microcontroller address space and is seen by the system as if it was
>>>>    an internal memory
>>>>
>>>> Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
>>>> ---
>>>>    drivers/mtd/spi-nor/Kconfig         |   7 +
>>>>    drivers/mtd/spi-nor/Makefile        |   1 +
>>>>    drivers/mtd/spi-nor/stm32-quadspi.c | 690
>>>> ++++++++++++++++++++++++++++++++++++
>>>>    3 files changed, 698 insertions(+)
>>>>    create mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c
>>>>
>>> [...]
>>>
>>>> +struct stm32_qspi_flash {
>>>> +    struct spi_nor nor;
>>>> +    u32 cs;
>>>> +    u32 fsize;
>>>> +    u32 presc;
>>>> +    struct stm32_qspi *qspi;
>>>> +};
>>> [...]
>>>
>>>> +struct stm32_qspi_cmd {
>>>> +    struct {
>>>> +        u8 addr_width;
>>>> +        u8 dummy;
>>>> +        u8 data;
>>>> +    } conf;
>>> Is there any benefit in having this structure here or could you just
>>> make the struct stm32_qspi_cmd flat ?
>> no benefit, it was just to regroup,  so I can do a flat structure
> Well, as you like, but I think it does make sense to just make it flat.
>
>>>> +    u8 opcode;
>>>> +    u32 framemode;
>>>> +    u32 qspimode;
>>>> +    u32 addr;
>>>> +    size_t len;
>>>> +    void *buf;
>>>> +};
>>> [...]
>>>
>>>> +static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from,
>>>> size_t len,
>>>> +                   u_char *buf)
>>>> +{
>>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>>> +    struct stm32_qspi *qspi = flash->qspi;
>>>> +    struct stm32_qspi_cmd cmd;
>>>> +    int err;
>>>> +
>>>> +    dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
>>>> +        nor->read_opcode, buf, (u32)from, len);
>>>> +
>>>> +    memset(&cmd, 0, sizeof(cmd));
>>>> +    cmd.opcode = nor->read_opcode;
>>>> +    cmd.conf.addr_width = nor->addr_width;
>>>> +    cmd.addr = (u32)from;
>>> loff_t (from) can be 64bit ... how do we handle this ?
>> I'm surprise by the question,
>> the SPI NOR device uses 3 Bytes or 4 bytes address mode.
>> So, the stm32 qspi controller has a 32 bit register for NOR address.
>> On the other hand the framework and other drivers used this variable
>> (from) like
>> a 32 bits.
> Hmmm, (rhetorical question) then why do we even use loff_t in the
> framework ?
>
> Anyway, this is no problem then.
In fact, the loff_t 64 bit come from mtd interface
(needed to address biggest device constraint) but not needed for spi-nor 
devices.
>>>> +    cmd.conf.data = 1;
>>>> +    cmd.conf.dummy = nor->read_dummy;
>>>> +    cmd.len = len;
>>>> +    cmd.buf = buf;
>>>> +    cmd.qspimode = qspi->read_mode;
>>>> +
>>>> +    stm32_qspi_set_framemode(nor, &cmd, true);
>>>> +    err = stm32_qspi_send(flash, &cmd);
>>>> +
>>>> +    return err ? err : len;
>>>> +}
>>> [...]
>>>
>>>> +static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
>>>> +{
>>>> +    struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
>>>> +    u32 cr, sr, fcr = 0;
>>>> +
>>>> +    cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
>>>> +    sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
>>>> +
>>>> +    if ((cr & CR_TCIE) && (sr & SR_TCF)) {
>>>> +        /* tx complete */
>>>> +        fcr |= FCR_CTCF;
>>>> +        complete(&qspi->cmd_completion);
>>>> +    } else {
>>>> +        dev_info(qspi->dev, "spurious interrupt\n");
>>> You probably want to ratelimit this one ...
>> yes it's better if there is an issue.
> Yep
>
>>>> +    }
>>>> +
>>>> +    writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
>>>> +
>>>> +    return IRQ_HANDLED;
>>>> +}
>>>> +
>>>> +static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
>>>> +{
>>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>>> +    struct stm32_qspi *qspi = flash->qspi;
>>>> +
>>>> +    mutex_lock(&qspi->lock);
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops
>>>> ops)
>>>> +{
>>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>>> +    struct stm32_qspi *qspi = flash->qspi;
>>>> +
>>>> +    mutex_unlock(&qspi->lock);
>>>> +}
>>>> +
>>>> +static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
>>>> +                  struct device_node *np)
>>>> +{
>>>> +    u32 width, flash_read, presc, cs_num, max_rate = 0;
>>>> +    struct stm32_qspi_flash *flash;
>>>> +    struct mtd_info *mtd;
>>>> +    int ret;
>>>> +
>>>> +    of_property_read_u32(np, "reg", &cs_num);
>>>> +    if (cs_num >= STM32_MAX_NORCHIP)
>>>> +        return -EINVAL;
>>>> +
>>>> +    of_property_read_u32(np, "spi-max-frequency", &max_rate);
>>>> +    if (!max_rate)
>>>> +        return -EINVAL;
>>>> +
>>>> +    presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
>>>> +
>>>> +    if (of_property_read_u32(np, "spi-rx-bus-width", &width))
>>>> +        width = 1;
>>>> +
>>>> +    if (width == 4)
>>>> +        flash_read = SPI_NOR_QUAD;
>>>> +    else if (width == 2)
>>>> +        flash_read = SPI_NOR_DUAL;
>>>> +    else if (width == 1)
>>>> +        flash_read = SPI_NOR_NORMAL;
>>>> +    else
>>>> +        return -EINVAL;
>>>> +
>>>> +    flash = &qspi->flash[cs_num];
>>>> +    flash->qspi = qspi;
>>>> +    flash->cs = cs_num;
>>>> +    flash->presc = presc;
>>>> +
>>>> +    flash->nor.dev = qspi->dev;
>>>> +    spi_nor_set_flash_node(&flash->nor, np);
>>>> +    flash->nor.priv = flash;
>>>> +    mtd = &flash->nor.mtd;
>>>> +    mtd->priv = &flash->nor;
>>>> +
>>>> +    flash->nor.read = stm32_qspi_read;
>>>> +    flash->nor.write = stm32_qspi_write;
>>>> +    flash->nor.erase = stm32_qspi_erase;
>>>> +    flash->nor.read_reg = stm32_qspi_read_reg;
>>>> +    flash->nor.write_reg = stm32_qspi_write_reg;
>>>> +    flash->nor.prepare = stm32_qspi_prep;
>>>> +    flash->nor.unprepare = stm32_qspi_unprep;
>>>> +
>>>> +    writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
>>>> +
>>>> +    writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
>>>> +               | CR_EN, qspi->io_base + QUADSPI_CR);
>>>> +
>>>> +    /*
>>>> +     * in stm32 qspi controller, QUADSPI_DCR register has a fsize field
>>>> +     * which define the size of nor flash.
>>>> +     * if fsize is NULL, the controller can't sent spi-nor command.
>>>> +     * set a temporary value just to discover the nor flash with
>>>> +     * "spi_nor_scan". After, the right value (mtd->size) can be set.
>>>> +     */
>>> Is 25 the smallest value ? Use a macro for this ...
>> 25 is an arbitrary choice, I will define a smallest value
> Cool, thanks!
>


______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply

* Re: [PATCH v2 5/5] iio: dac: stm32: add support for waveform generator
From: Fabrice Gasnier @ 2017-04-10 16:43 UTC (permalink / raw)
  To: Jonathan Cameron, linux, robh+dt, linux-arm-kernel, devicetree,
	linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, benjamin.gaignard
In-Reply-To: <8fa183fe-42f1-dc27-efd9-1f7d2e5b5057@kernel.org>

On 04/09/2017 11:34 AM, Jonathan Cameron wrote:
> On 06/04/17 17:11, Fabrice Gasnier wrote:
>> STM32 DAC has built-in noise or triangle waveform generator.
>> - "wavetype" extended attribute selects noise or triangle.
>> - "amplitude" extended attribute selects amplitude for waveform generator
>>
>> A DC offset can be added to waveform generator output. This can be done
>> using out_voltage[1/2]_offset
>>
>> Waveform generator requires a trigger to be configured, to increment /
>> decrement internal counter in case of triangle generator. Noise
>> generator is a bit different,  but also requires a trigger to generate
>> samples.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> 
> Various bits inline.  Mostly I think the blockers on this will be
> making sure the ABI defined is generic enough to handle the more crazy
> DDS chips out there... (basically the ones doing frequency modulation).
> 
> Jonathan
>> ---
>> Changes in v2:
>> - use _offset parameter to add DC offset to waveform generator
> Conceptually this offset is just the normal DAC output value (particularly
yes
> in the flat case)  I guess we can paper over this by having the _raw
> and this always have th same value, but it's a little inelegant.
> Still people are going to expect _raw to control it when in DAC mode but
> that makes limited sense in DDS mode.
> 
> Mind you nothing stops us defining all DDS channels as the sum of whatever
> the DDS is doing and whatever is _raw is set to. Perhaps we tidy this up
> purely through documentation.  Think of the DDS as a modulation on top
> of the DAC...
> 
>> - Rework ABI to better fit existing DDS ABI: use out_voltageY_wavetype,
>>   out_voltage_wavetype_available, out_voltageY_amplitude,
>>   out_voltage_amplitude_available
> Hmm. I'm thinking those amplitude values aren't nice and don't fit well
> with the more general ABI.
> 
> I suggested (but didn't really expand upon) having standard defined types
> for each waveform then using scale to control the amplitude.

Do you mean _scale attribute ?
> 
> Is that something that might work here?

I probably miss the point here...
> 
> So say we have our triangle standard form having an amplitude of 1V Peak to
> Peak. Then we can use scale to make it whatever we actually have in this
> case?  The docs for wave type will need to describe those standard forms
> though.
... scale is fixed here, in line with _raw attribute. In 'amplitude'
description for STM32 DAC here (e.g. from 1...4095), same scale is used.
Can you elaborate ?

> 
> Hmm. Whether this is worth doing is unclear however as we'll still have
> to describe the 'frequency' in terms of the clock ticks (here the triggers)

Describing frequency may be an issue, not sure it makes senses in this
case: 'clock ticks', e.g. triggers here may be timers, but also an EXTI
(external...), or even software trig perhaps.

> So maybe amplitude is worth having.  Again, looking for input from ADI lot
> on this...  There are some really fiddly cases to describe were we are doing
> symbol encoding so have multiple waveforms that we are switching between based
> on some external signal. Any ABI needs to encompass that sort of usage.
> Parts like the AD9833 for example...
> 
>> - Better explain trigger usage in case of waveform generator.
>> ---
>>  Documentation/ABI/testing/sysfs-bus-iio-dac-stm32 |  16 +++
>>  drivers/iio/dac/stm32-dac-core.h                  |   4 +
>>  drivers/iio/dac/stm32-dac.c                       | 158 +++++++++++++++++++++-
>>  3 files changed, 177 insertions(+), 1 deletion(-)
>>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-stm32
>>
>> diff --git a/Documentation/ABI/testing/sysfs-bus-iio-dac-stm32 b/Documentation/ABI/testing/sysfs-bus-iio-dac-stm32
>> new file mode 100644
>> index 0000000..8f1fa009
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/sysfs-bus-iio-dac-stm32
> Fair enough to initially introduced these for this part only, but I'd very
> much like to see us agree on these sufficiently to get them into the main
> docs asap so we have something to work with for getting the DDS chips out
> of staging...
>> @@ -0,0 +1,16 @@
>> +What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_wavetype
>> +What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_wavetype_available
>> +KernelVersion:	4.12
>> +Contact:	fabrice.gasnier@st.com
>> +Description:
>> +		List and/or select waveform generation provided by STM32 DAC:
>> +		- "flat": waveform generator disabled (default)
>> +		- "noise": select noise waveform
>> +		- "triangle": select triangle waveform
>> +
>> +What:		/sys/bus/iio/devices/iio:deviceX/out_voltageY_amplitude
>> +What:		/sys/bus/iio/devices/iio:deviceX/out_voltage_amplitude_available
>> +KernelVersion:	4.12
>> +Contact:	fabrice.gasnier@st.com
>> +Description:
>> +		List and/or select amplitude used for waveform generator
>> diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
>> index e51a468..0f02975 100644
>> --- a/drivers/iio/dac/stm32-dac-core.h
>> +++ b/drivers/iio/dac/stm32-dac-core.h
>> @@ -37,8 +37,12 @@
>>  #define STM32H7_DAC_CR_TEN1		BIT(1)
>>  #define STM32H7_DAC_CR_TSEL1_SHIFT	2
>>  #define STM32H7_DAC_CR_TSEL1		GENMASK(5, 2)
>> +#define STM32_DAC_CR_WAVE1		GENMASK(7, 6)
>> +#define STM32_DAC_CR_MAMP1		GENMASK(11, 8)
>>  #define STM32H7_DAC_CR_HFSEL		BIT(15)
>>  #define STM32_DAC_CR_EN2		BIT(16)
>> +#define STM32_DAC_CR_WAVE2		GENMASK(23, 22)
>> +#define STM32_DAC_CR_MAMP2		GENMASK(27, 24)
>>  
>>  /* STM32_DAC_SWTRIGR bit fields */
>>  #define STM32_DAC_SWTRIGR_SWTRIG1	BIT(0)
>> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
>> index a7a078e..2ed75db 100644
>> --- a/drivers/iio/dac/stm32-dac.c
>> +++ b/drivers/iio/dac/stm32-dac.c
>> @@ -42,10 +42,12 @@
>>  /**
>>   * struct stm32_dac - private data of DAC driver
>>   * @common:		reference to DAC common data
>> + * @wavetype:		waveform generator
>>   * @swtrig:		Using software trigger
>>   */
>>  struct stm32_dac {
>>  	struct stm32_dac_common *common;
>> +	u32 wavetype;
>>  	bool swtrig;
>>  };
>>  
>> @@ -222,6 +224,29 @@ static int stm32_dac_set_value(struct stm32_dac *dac, int channel, int val)
>>  	return ret;
>>  }
>>  
>> +static int stm32_dac_get_offset(struct stm32_dac *dac, int channel, int *val)
>> +{
>> +	int ret;
>> +
>> +	/* Offset is only relevant in waveform generation mode. */
>> +	if (!dac->wavetype) {
>> +		*val = 0;
>> +		return IIO_VAL_INT;
>> +	}
>> +
>> +	/*
>> +	 * In waveform generation mode, DC offset in DHR is added to waveform
>> +	 * generator output, then stored to DOR (data output register).
>> +	 * Read offset from DHR.
>> +	 */
> Just thinking what fun we could have if we do the fifo based output to push
> this that I was suggesting for the previous patch ;) triangles on top
> of fun general waveforms..
> 
>> +	if (STM32_DAC_IS_CHAN_1(channel))
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DHR12R1, val);
>> +	else
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DHR12R2, val);
>> +
>> +	return ret ? ret : IIO_VAL_INT;
>> +}
>> +
>>  static int stm32_dac_read_raw(struct iio_dev *indio_dev,
>>  			      struct iio_chan_spec const *chan,
>>  			      int *val, int *val2, long mask)
>> @@ -231,6 +256,8 @@ static int stm32_dac_read_raw(struct iio_dev *indio_dev,
>>  	switch (mask) {
>>  	case IIO_CHAN_INFO_RAW:
>>  		return stm32_dac_get_value(dac, chan->channel, val);
>> +	case IIO_CHAN_INFO_OFFSET:
>> +		return stm32_dac_get_offset(dac, chan->channel, val);
>>  	case IIO_CHAN_INFO_SCALE:
>>  		*val = dac->common->vref_mv;
>>  		*val2 = chan->scan_type.realbits;
>> @@ -247,8 +274,16 @@ static int stm32_dac_write_raw(struct iio_dev *indio_dev,
>>  	struct stm32_dac *dac = iio_priv(indio_dev);
>>  
>>  	switch (mask) {
>> +	case IIO_CHAN_INFO_OFFSET:
>> +		/* Offset only makes sense in waveform generation mode */
>> +		if (dac->wavetype)
>> +			return stm32_dac_set_value(dac, chan->channel, val);
>> +		return -EBUSY;
> Yeah, I think I sent you down a blind alley here.  If people agree, lets
> just define DDS signals as always being the sum of _raw + the dds element.
> Then it's easy.
Ok, I can revert back to use _raw if this is fine ;-)

>>  	case IIO_CHAN_INFO_RAW:
>> -		return stm32_dac_set_value(dac, chan->channel, val);
>> +		if (!dac->wavetype)
>> +			return stm32_dac_set_value(dac, chan->channel, val);
>> +		/* raw value is read only in waveform generation mode */
>> +		return -EBUSY;
>>  	default:
>>  		return -EINVAL;
>>  	}
>> @@ -334,6 +369,122 @@ static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
>>  	.set = stm32_dac_set_powerdown_mode,
>>  };
>>  
>> +/* waveform generator wave selection */
>> +static const char * const stm32_dac_wavetype_desc[] = {
>> +	"flat",
>> +	"noise",
>> +	"triangle",
>> +};
>> +
>> +static int stm32_dac_set_wavetype(struct iio_dev *indio_dev,
>> +				  const struct iio_chan_spec *chan,
>> +				  unsigned int wavetype)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 mask, val;
>> +	int ret;
>> +
>> +	/*
>> +	 * Waveform generator requires a trigger to be configured, to increment
>> +	 * or decrement internal counter in case of triangle generator. Noise
>> +	 * generator is a bit different, but also requires a trigger to
>> +	 * generate samples.
>> +	 */
>> +	if (wavetype && !indio_dev->trig)
>> +		dev_dbg(&indio_dev->dev, "Wavegen requires a trigger\n");
>> +
>> +	if (STM32_DAC_IS_CHAN_1(chan->channel)) {
>> +		val = FIELD_PREP(STM32_DAC_CR_WAVE1, wavetype);
>> +		mask = STM32_DAC_CR_WAVE1;
>> +	} else {
>> +		val = FIELD_PREP(STM32_DAC_CR_WAVE2, wavetype);
>> +		mask = STM32_DAC_CR_WAVE2;
>> +	}
>> +
>> +	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, mask, val);
>> +	if (ret)
>> +		return ret;
>> +	dac->wavetype = wavetype;
>> +
>> +	return 0;
>> +}
>> +
>> +static int stm32_dac_get_wavetype(struct iio_dev *indio_dev,
>> +				  const struct iio_chan_spec *chan)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 val;
>> +	int ret;
>> +
>> +	ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (STM32_DAC_IS_CHAN_1(chan->channel))
>> +		return FIELD_GET(STM32_DAC_CR_WAVE1, val);
>> +	else
>> +		return FIELD_GET(STM32_DAC_CR_WAVE2, val);
>> +}
>> +
>> +static const struct iio_enum stm32_dac_wavetype_enum = {
>> +	.items = stm32_dac_wavetype_desc,
>> +	.num_items = ARRAY_SIZE(stm32_dac_wavetype_desc),
>> +	.get = stm32_dac_get_wavetype,
>> +	.set = stm32_dac_set_wavetype,
>> +};
>> +
>> +/*
>> + * waveform generator mamp selection: mask/amplitude
>> + * - noise: LFSR mask (linear feedback shift register, umasks bit 0, [1:0]...)
> This needs breaking out into two attributes - for noise it isn't amplitude in
> any conventional sense...  Keep the result device specific for now. I'm not
> even sure what type of pseudo random source that actually is...
Do you suggest to create specific attribute for this ? This will end-up
to write same register/bitfield as 'amplitude' for triangle generator.

Thanks & Regards,
Fabrice

> If anyone wants to figure it out it would be great to document it in a general
> form!
> 
>> + * - triangle: amplitude (equal to 1, 3, 5, 7... 4095)
>> + */
>> +static const char * const stm32_dac_amplitude_desc[] = {
>> +	"1", "3", "7", "15", "31", "63", "127", "255", "511", "1023", "2047",
>> +	"4095",
>> +};
>> +
>> +static int stm32_dac_set_amplitude(struct iio_dev *indio_dev,
>> +				   const struct iio_chan_spec *chan,
>> +				   unsigned int amplitude)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 mask, val;
>> +
>> +	if (STM32_DAC_IS_CHAN_1(chan->channel)) {
>> +		val = FIELD_PREP(STM32_DAC_CR_MAMP1, amplitude);
>> +		mask = STM32_DAC_CR_MAMP1;
>> +	} else {
>> +		val = FIELD_PREP(STM32_DAC_CR_MAMP2, amplitude);
>> +		mask = STM32_DAC_CR_MAMP2;
>> +	}
>> +
>> +	return regmap_update_bits(dac->common->regmap, STM32_DAC_CR, mask, val);
>> +}
>> +
>> +static int stm32_dac_get_amplitude(struct iio_dev *indio_dev,
>> +				   const struct iio_chan_spec *chan)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 val;
>> +	int ret;
>> +
>> +	ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	if (STM32_DAC_IS_CHAN_1(chan->channel))
>> +		return FIELD_GET(STM32_DAC_CR_MAMP1, val);
>> +	else
>> +		return FIELD_GET(STM32_DAC_CR_MAMP2, val);
>> +}
>> +
>> +static const struct iio_enum stm32_dac_amplitude_enum = {
>> +	.items = stm32_dac_amplitude_desc,
>> +	.num_items = ARRAY_SIZE(stm32_dac_amplitude_desc),
>> +	.get = stm32_dac_get_amplitude,
>> +	.set = stm32_dac_set_amplitude,
>> +};
>> +
>>  static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = {
>>  	{
>>  		.name = "powerdown",
>> @@ -343,6 +494,10 @@ static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
>>  	},
>>  	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en),
>>  	IIO_ENUM_AVAILABLE("powerdown_mode", &stm32_dac_powerdown_mode_en),
>> +	IIO_ENUM("wavetype", IIO_SEPARATE, &stm32_dac_wavetype_enum),
>> +	IIO_ENUM_AVAILABLE("wavetype", &stm32_dac_wavetype_enum),
>> +	IIO_ENUM("amplitude", IIO_SEPARATE, &stm32_dac_amplitude_enum),
>> +	IIO_ENUM_AVAILABLE("amplitude", &stm32_dac_amplitude_enum),
>>  	{},
>>  };
>>  
>> @@ -352,6 +507,7 @@ static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
>>  	.output = 1,					\
>>  	.channel = chan,				\
>>  	.info_mask_separate =				\
>> +		BIT(IIO_CHAN_INFO_OFFSET) |		\
>>  		BIT(IIO_CHAN_INFO_RAW) |		\
>>  		BIT(IIO_CHAN_INFO_SCALE),		\
>>  	/* scan_index is always 0 as num_channels is 1 */ \
>>
> 

^ permalink raw reply

* Re: [PATCH v2 4/5] iio: dac: stm32: add support for trigger events
From: Fabrice Gasnier @ 2017-04-10 16:37 UTC (permalink / raw)
  To: Jonathan Cameron, linux, robh+dt, linux-arm-kernel, devicetree,
	linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, benjamin.gaignard
In-Reply-To: <14dfe2a9-d459-0074-532e-d44daf336406@kernel.org>

On 04/09/2017 11:04 AM, Jonathan Cameron wrote:
> On 06/04/17 17:11, Fabrice Gasnier wrote:
>> STM32 DAC supports triggers to synchronize conversions. When trigger
>> occurs, data is transferred from DHR (data holding register) to DOR
>> (data output register) so output voltage is updated.
>> Both hardware and software triggers are supported.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> Hmm. I'm really not sure on how to handle this...  The problem to my mind
> is knowing when it has triggered so we can know that it makes sense to
> put the next reading in.... Anyhow bear with me...
> 
> I think the same arguement holds for this as equivalent input devices.
> There we have always argued that if you need multichannel synchronized
> capture (which is 'kind' of what we are looking at here) then you have
> to use the buffered interface.
> 
> I think we need buffered output for this to fit nicely in the subsystem.
> It definitely isn't a correct use of the event triggers.
> 
> That means we really need to figure out the ABI for buffered output and
> get that sorted.  To my mind it shouldn't be too tricky and should look
> much like buffered input, just with us writing to a fifo from userspace
> rather than reading from it.
> 
> The DMA side of that can come later, in a similar fashion to how it is
> added for the ADC side of things.  We can also have 'providers'
> (equivalent of 'consumers' on the ADC side), perhaps giving a neat way
> of describing DDS devices (I'm not so sure on this yet).
> 
> So to my mind, if you are not in buffered mode and do a sysfs write it
> should be 'instant'. If in buffered mode, then it will wait on the
> trigger.
> 
> So the complex side of things is what we 'know' about the data flow.
> 1) Case you have here.  We want to do direct write through to the device,
> but have no way of knowing (or do we?) that it has triggered and written
> the data to the output.  So we have no way of knowing we can push the next
> value in from a fifo yet...  In this case I guess the solution might be to
> have a fifo length of 0.  That is data flows straight to hardware.
> 
> 2) Simple stream case - always enough data in the fifo and we get an interrupt
> to signify that the previous trigger happened.
> 
> 3) Case where we are only just keeping up.  So we won't have data in the fifo
> until sometime after the previous trigger.  In this case we need the fifo to
> push straight through if there isn't data ready to go.
> 
> 4) Case where we are not pushing data fast enough.  Just don't update?
> 
> That last case 4 is nasty as the reason we typically want to do triggered
> DAC updates is to ensure we always have valid states in some control loop,
> but we might get a race here where one DAC has a value ready to go on a trigger
> and another one isn't quite ready.  In this case we might want to hold off
> until all are ready... So there might need to be a sanity check that everyone
> on a given trigger is ready to go - an extra callback.
> 
> So a bit fiddly and I'm not sure I like the representation of through flow as
> a fifo of 0 length... (can't think of a neater way though atm)
> 
> Anyhow, time to sort output buffers out once and for all I think if we can
> get a reasonable group of people together who have the time.
> 
> Sorry Fabrice that this has hit your driver!  Perhaps we can figure
> enough out to be able to at least get the basics (i.e. patches 1,2) in as
> asap.

Hi Jonathan,

Thanks for sharing your view on this.
I sent patches 1,2 updated with your comments. I dropped following
patches for the time being, as it obviously require additions...

I agree with your analysis and concerns above.
I hope Lars or others can give some feedback or guidelines on output
buffer? Is there something already, we may start to work on ?

Thanks all in advance.
Best Regards,
Fabrice

> 
> Jonathan
>> ---
>> Changes in v2:
>> - Fix issue with trigger, by using set_trigger callback
>> - trigger can now be assigned, no matters powerdown state
>> ---
>>  drivers/iio/dac/Kconfig          |   3 +
>>  drivers/iio/dac/stm32-dac-core.h |   8 +++
>>  drivers/iio/dac/stm32-dac.c      | 127 ++++++++++++++++++++++++++++++++++++++-
>>  3 files changed, 137 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
>> index 7198648..786c38b 100644
>> --- a/drivers/iio/dac/Kconfig
>> +++ b/drivers/iio/dac/Kconfig
>> @@ -278,6 +278,9 @@ config STM32_DAC
>>  	tristate "STMicroelectronics STM32 DAC"
>>  	depends on (ARCH_STM32 && OF) || COMPILE_TEST
>>  	depends on REGULATOR
>> +	select IIO_TRIGGERED_EVENT
>> +	select IIO_STM32_TIMER_TRIGGER
>> +	select MFD_STM32_TIMERS
>>  	select STM32_DAC_CORE
>>  	help
>>  	  Say yes here to build support for STMicroelectronics STM32 Digital
>> diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
>> index daf0993..e51a468 100644
>> --- a/drivers/iio/dac/stm32-dac-core.h
>> +++ b/drivers/iio/dac/stm32-dac-core.h
>> @@ -26,6 +26,7 @@
>>  
>>  /* STM32 DAC registers */
>>  #define STM32_DAC_CR		0x00
>> +#define STM32_DAC_SWTRIGR	0x04
>>  #define STM32_DAC_DHR12R1	0x08
>>  #define STM32_DAC_DHR12R2	0x14
>>  #define STM32_DAC_DOR1		0x2C
>> @@ -33,9 +34,16 @@
>>  
>>  /* STM32_DAC_CR bit fields */
>>  #define STM32_DAC_CR_EN1		BIT(0)
>> +#define STM32H7_DAC_CR_TEN1		BIT(1)
>> +#define STM32H7_DAC_CR_TSEL1_SHIFT	2
>> +#define STM32H7_DAC_CR_TSEL1		GENMASK(5, 2)
>>  #define STM32H7_DAC_CR_HFSEL		BIT(15)
>>  #define STM32_DAC_CR_EN2		BIT(16)
>>  
>> +/* STM32_DAC_SWTRIGR bit fields */
>> +#define STM32_DAC_SWTRIGR_SWTRIG1	BIT(0)
>> +#define STM32_DAC_SWTRIGR_SWTRIG2	BIT(1)
>> +
>>  /**
>>   * struct stm32_dac_common - stm32 DAC driver common data (for all instances)
>>   * @regmap: DAC registers shared via regmap
>> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
>> index c0d993a..a7a078e 100644
>> --- a/drivers/iio/dac/stm32-dac.c
>> +++ b/drivers/iio/dac/stm32-dac.c
>> @@ -23,6 +23,10 @@
>>  #include <linux/bitfield.h>
>>  #include <linux/delay.h>
>>  #include <linux/iio/iio.h>
>> +#include <linux/iio/timer/stm32-timer-trigger.h>
>> +#include <linux/iio/trigger.h>
>> +#include <linux/iio/trigger_consumer.h>
>> +#include <linux/iio/triggered_event.h>
>>  #include <linux/kernel.h>
>>  #include <linux/module.h>
>>  #include <linux/platform_device.h>
>> @@ -32,15 +36,113 @@
>>  #define STM32_DAC_CHANNEL_1		1
>>  #define STM32_DAC_CHANNEL_2		2
>>  #define STM32_DAC_IS_CHAN_1(ch)		((ch) & STM32_DAC_CHANNEL_1)
>> +/* channel2 shift */
>> +#define STM32_DAC_CHAN2_SHIFT		16
>>  
>>  /**
>>   * struct stm32_dac - private data of DAC driver
>>   * @common:		reference to DAC common data
>> + * @swtrig:		Using software trigger
>>   */
>>  struct stm32_dac {
>>  	struct stm32_dac_common *common;
>> +	bool swtrig;
>>  };
>>  
>> +/**
>> + * struct stm32_dac_trig_info - DAC trigger info
>> + * @name: name of the trigger, corresponding to its source
>> + * @tsel: trigger selection, value to be configured in DAC_CR.TSELx
>> + */
>> +struct stm32_dac_trig_info {
>> +	const char *name;
>> +	u32 tsel;
>> +};
>> +
>> +static const struct stm32_dac_trig_info stm32h7_dac_trinfo[] = {
>> +	{ "swtrig", 0 },
>> +	{ TIM1_TRGO, 1 },
>> +	{ TIM2_TRGO, 2 },
>> +	{ TIM4_TRGO, 3 },
>> +	{ TIM5_TRGO, 4 },
>> +	{ TIM6_TRGO, 5 },
>> +	{ TIM7_TRGO, 6 },
>> +	{ TIM8_TRGO, 7 },
>> +	{},
>> +};
>> +
>> +static irqreturn_t stm32_dac_trigger_handler(int irq, void *p)
>> +{
>> +	struct iio_poll_func *pf = p;
>> +	struct iio_dev *indio_dev = pf->indio_dev;
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	int channel = indio_dev->channels[0].channel;
>> +
>> +	/* Using software trigger? Then, trigger it now */
> Can we get here otherwise?
> If not I'd prefer to either see an error on the other case
> (perhaps simply return IRQ_NONE) 
>> +	if (dac->swtrig) {
>> +		u32 swtrig;
>> +
>> +		if (STM32_DAC_IS_CHAN_1(channel))
>> +			swtrig = STM32_DAC_SWTRIGR_SWTRIG1;
>> +		else
>> +			swtrig = STM32_DAC_SWTRIGR_SWTRIG2;
>> +		regmap_update_bits(dac->common->regmap, STM32_DAC_SWTRIGR,
>> +				   swtrig, swtrig);
>> +	}
>> +
>> +	iio_trigger_notify_done(indio_dev->trig);
>> +
>> +	return IRQ_HANDLED;
>> +}
>> +
>> +static unsigned int stm32_dac_get_trig_tsel(struct stm32_dac *dac,
>> +					    struct iio_trigger *trig)
>> +{
>> +	unsigned int i;
>> +
>> +	/* skip 1st trigger that should be swtrig */
>> +	for (i = 1; stm32h7_dac_trinfo[i].name; i++) {
>> +		/*
>> +		 * Checking both stm32 timer trigger type and trig name
>> +		 * should be safe against arbitrary trigger names.
>> +		 */
>> +		if (is_stm32_timer_trigger(trig) &&
>> +		    !strcmp(stm32h7_dac_trinfo[i].name, trig->name)) {
>> +			return stm32h7_dac_trinfo[i].tsel;
>> +		}
>> +	}
>> +
>> +	/* When no trigger has been found, default to software trigger */
>> +	dac->swtrig = true;
>> +
>> +	return stm32h7_dac_trinfo[0].tsel;
>> +}
>> +
>> +static int stm32_dac_set_trigger(struct iio_dev *indio_dev,
>> +				 struct iio_trigger *trig)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	int channel = indio_dev->channels[0].channel;
>> +	u32 shift = STM32_DAC_IS_CHAN_1(channel) ? 0 : STM32_DAC_CHAN2_SHIFT;
>> +	u32 val = 0, tsel;
>> +	u32 msk = (STM32H7_DAC_CR_TEN1 | STM32H7_DAC_CR_TSEL1) << shift;
>> +
>> +	dac->swtrig = false;
>> +	if (trig) {
>> +		/* select & enable trigger (tsel / ten) */
>> +		tsel = stm32_dac_get_trig_tsel(dac, trig);
>> +		val = tsel << STM32H7_DAC_CR_TSEL1_SHIFT;
>> +		val = (val | STM32H7_DAC_CR_TEN1) << shift;
>> +	}
>> +
>> +	if (trig)
>> +		dev_dbg(&indio_dev->dev, "enable trigger: %s\n", trig->name);
>> +	else
>> +		dev_dbg(&indio_dev->dev, "disable trigger\n");
>> +
>> +	return regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, val);
>> +}
>> +
>>  static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel)
>>  {
>>  	struct stm32_dac *dac = iio_priv(indio_dev);
>> @@ -167,6 +269,7 @@ static int stm32_dac_debugfs_reg_access(struct iio_dev *indio_dev,
>>  static const struct iio_info stm32_dac_iio_info = {
>>  	.read_raw = stm32_dac_read_raw,
>>  	.write_raw = stm32_dac_write_raw,
>> +	.set_trigger = stm32_dac_set_trigger,
>>  	.debugfs_reg_access = stm32_dac_debugfs_reg_access,
>>  	.driver_module = THIS_MODULE,
>>  };
>> @@ -326,7 +429,28 @@ static int stm32_dac_probe(struct platform_device *pdev)
>>  	if (ret < 0)
>>  		return ret;
>>  
>> -	return devm_iio_device_register(&pdev->dev, indio_dev);
>> +	ret = iio_triggered_event_setup(indio_dev, NULL,
>> +					stm32_dac_trigger_handler);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = iio_device_register(indio_dev);
>> +	if (ret) {
>> +		iio_triggered_event_cleanup(indio_dev);
>> +		return ret;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static int stm32_dac_remove(struct platform_device *pdev)
>> +{
>> +	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
>> +
>> +	iio_triggered_event_cleanup(indio_dev);
>> +	iio_device_unregister(indio_dev);
>> +
>> +	return 0;
>>  }
>>  
>>  static const struct of_device_id stm32_dac_of_match[] = {
>> @@ -337,6 +461,7 @@ static int stm32_dac_probe(struct platform_device *pdev)
>>  
>>  static struct platform_driver stm32_dac_driver = {
>>  	.probe = stm32_dac_probe,
>> +	.remove = stm32_dac_remove,
>>  	.driver = {
>>  		.name = "stm32-dac",
>>  		.of_match_table = stm32_dac_of_match,
>>
> 

^ permalink raw reply

* Re: [PATCH v3 6/9] drivers: remove useless comment from base/arch_topology.c
From: Russell King - ARM Linux @ 2017-04-10 16:33 UTC (permalink / raw)
  To: Juri Lelli
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	vincent.guittot, robh+dt, mark.rutland, sudeep.holla,
	lorenzo.pieralisi, catalin.marinas, will.deacon, morten.rasmussen,
	dietmar.eggemann, broonie, gregkh
In-Reply-To: <20170410140214.GE30804@e106622-lin>

On Mon, Apr 10, 2017 at 03:02:14PM +0100, Juri Lelli wrote:
> Hi,
> 
> On 10/04/17 14:51, Russell King - ARM Linux wrote:
> > On Mon, Mar 27, 2017 at 02:18:22PM +0100, Juri Lelli wrote:
> > > Printing out an error message when we failed to get the cpu device is
> > > not helping anyone. Remove it.
> > 
> > (1) the subject line talks about removing a "comment" but you're
> >     actually removing an error printk
> > (2) I don't think it's "not helping anyone", although the description
> >     above doesn't say _why_ - it's reporting the lack of a missing CPU
> >     device that we expect to be present.  If it's not present, then
> >     we're not going to end up with the cpu capacity attribute, and the
> >     error message answers the "why is that sysfs file missing" question.
> 
> That's the same I was thinking when I put the error message there in the
> first place. But, then Greg didn't seem to like it.

I don't think it was a case of "not liking it" - Greg asked what use it
was.  Greg also pointed out the race with userspace.

I think dropping this patch is the quickest way to move forward.

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

^ permalink raw reply

* Re: [PATCH v2 2/2] dt-bindings: document: add firefly-rk3399 board support
From: Rob Herring @ 2017-04-10 16:25 UTC (permalink / raw)
  To: Kever Yang
  Cc: heiko-4mtYJXux2i+zQB+pC5nmwQ,
	linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Jianqun Xu, Liang Chen,
	Brian Norris, linux-kernel-u79uwXL29TY76Z2rM5mHXA, Randy Li,
	Andy Yan, Eddie Cai, Mark Rutland,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Xing Zheng
In-Reply-To: <1491384800-22412-2-git-send-email-kever.yang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>

On Wed, Apr 05, 2017 at 05:33:20PM +0800, Kever Yang wrote:
> Use "firefly,firefly-rk3399" compatible string for firefly-rk3399 board.
> 
> Signed-off-by: Kever Yang <kever.yang-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> ---
> 
> Changes in v2: None
> 
>  Documentation/devicetree/bindings/arm/rockchip.txt | 4 ++++
>  1 file changed, 4 insertions(+)

Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
--
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 3/6] clk: qcom: Add CPU clock driver for msm8996
From: Rob Herring @ 2017-04-10 16:23 UTC (permalink / raw)
  To: Rajendra Nayak; +Cc: sboyd, mturquette, linux-clk, linux-arm-msm, devicetree
In-Reply-To: <1491368129-24721-4-git-send-email-rnayak@codeaurora.org>

On Wed, Apr 05, 2017 at 10:25:26AM +0530, Rajendra Nayak wrote:
> Each of the CPU clusters (Power and Perf) on msm8996 are
> clocked via 2 PLLs, a primary and alternate. There are also
> 2 Mux'es, a primary and secondary all connected together
> as shown below
> 
>                              +-------+
>               XO             |       |
>           +------------------>0      |
>                              |       |
>                    PLL/2     | SMUX  +----+
>                      +------->1      |    |
>                      |       |       |    |
>                      |       +-------+    |    +-------+
>                      |                    +---->0      |
>                      |                         |       |
> +---------------+    |             +----------->1      | CPU clk
> |Primary PLL    +----+ PLL_EARLY   |           |       +------>
> |               +------+-----------+    +------>2 PMUX |
> +---------------+      |                |      |       |
>                        |   +------+     |   +-->3      |
>                        +--^+  ACD +-----+   |  +-------+
> +---------------+          +------+         |
> |Alt PLL        |                           |
> |               +---------------------------+
> +---------------+         PLL_EARLY
> 
> The primary PLL is what drives the CPU clk, except for times
> when we are reprogramming the PLL itself (for rate changes) when
> we temporarily switch to an alternate PLL. A subsequent patch adds
> support to switch between primary and alternate PLL during rate
> changes.
> 
> The primary PLL operates on a single VCO range, between 600Mhz
> and 3Ghz. However the CPUs do support OPPs with frequencies
> between 300Mhz and 600Mhz. In order to support running the CPUs
> at those frequencies we end up having to lock the PLL at twice
> the rate and drive the CPU clk via the PLL/2 output and SMUX.
> 
> So for frequencies above 600Mhz we follow the following path
>  Primary PLL --> PLL_EARLY --> PMUX(1) --> CPU clk
> and for frequencies between 300Mhz and 600Mhz we follow
>  Primary PLL --> PLL/2 --> SMUX(1) --> PMUX(0) --> CPU clk
> Support for this is added in a subsequent patch as well.
> 
> ACD stands for Adaptive Clock Distribution and is used to
> detect voltage droops. We do not add support for ACD as yet.
> This can be added at a later point as needed.
> 
> Signed-off-by: Rajendra Nayak <rnayak@codeaurora.org>
> ---
>  .../devicetree/bindings/clock/qcom,kryocc.txt      |  17 +

Acked-by: Rob Herring <robh@kernel.org>

>  drivers/clk/qcom/Kconfig                           |   8 +
>  drivers/clk/qcom/Makefile                          |   1 +
>  drivers/clk/qcom/clk-cpu-8996.c                    | 388 +++++++++++++++++++++
>  4 files changed, 414 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/clock/qcom,kryocc.txt
>  create mode 100644 drivers/clk/qcom/clk-cpu-8996.c

^ permalink raw reply

* Re: [PATCH v3 5/9] arm, arm64: factorize common cpu capacity default code
From: Juri Lelli @ 2017-04-10 16:23 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA, mark.rutland-5wv7dgnIgG8,
	devicetree-u79uwXL29TY76Z2rM5mHXA, lorenzo.pieralisi-5wv7dgnIgG8,
	vincent.guittot-QSEj5FYQhm4dnm+yROfE0A,
	linux-pm-u79uwXL29TY76Z2rM5mHXA, peterz-wEGCiKHe2LqWVfeAwA7xHQ,
	broonie-DgEjT+Ai2ygdnm+yROfE0A, will.deacon-5wv7dgnIgG8,
	gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r,
	dietmar.eggemann-5wv7dgnIgG8, Russell King,
	robh+dt-DgEjT+Ai2ygdnm+yROfE0A, sudeep.holla-5wv7dgnIgG8,
	linux-lFZ/pmaqli7XmaaqVzeoHQ, morten.rasmussen-5wv7dgnIgG8,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <20170410081806.GB27538-M2fw3Uu6cmfZROr8t4l/smS4ubULX0JqMm0uRHvK7Nw@public.gmane.org>

Hi,

On 10/04/17 09:18, Catalin Marinas wrote:
> On Mon, Mar 27, 2017 at 02:18:21PM +0100, Juri Lelli wrote:
> > arm and arm64 share lot of code relative to parsing CPU capacity
> > information from DT, using that information for appropriate scaling and
> > exposing a sysfs interface for chaging such values at runtime.
> > 
> > Factorize such code in a common place (driver/base/arch_topology.c) in
> > preparation for further additions.
> > 
> > Suggested-by: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> > Suggested-by: Mark Rutland <mark.rutland-5wv7dgnIgG8@public.gmane.org>
> > Suggested-by: Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>
> > Cc: Russell King <linux-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org>
> > Cc: Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>
> > Cc: Will Deacon <will.deacon-5wv7dgnIgG8@public.gmane.org>
> > Cc: Greg Kroah-Hartman <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org>
> > Signed-off-by: Juri Lelli <juri.lelli-5wv7dgnIgG8@public.gmane.org>
> > ---
> > 
> > Changes from v2:
> >  - make capacity_scale and raw_capacity static
> >  - added SPDX header
> >  - improved indent
> >  - misc. whitespaces/newlines fixes
> > 
> > Changes from v1:
> >  - keep the original GPLv2 header
> > ---
> >  arch/arm/Kconfig             |   1 +
> >  arch/arm/kernel/topology.c   | 213 ++-----------------------------------
> >  arch/arm64/Kconfig           |   1 +
> >  arch/arm64/kernel/topology.c | 219 +--------------------------------------
> >  drivers/base/Kconfig         |   8 ++
> >  drivers/base/Makefile        |   1 +
> >  drivers/base/arch_topology.c | 242 +++++++++++++++++++++++++++++++++++++++++++
> 
> For arm64:
> 
> Acked-by: Catalin Marinas <catalin.marinas-5wv7dgnIgG8@public.gmane.org>

Thanks for reviewing the series.

Best,

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

^ permalink raw reply

* Re: [PATCH v3 0/9] Fix issues and factorize arm/arm64 capacity information code
From: Juri Lelli @ 2017-04-10 16:21 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-kernel, linux-pm, linux-arm-kernel, devicetree, peterz,
	vincent.guittot, robh+dt, mark.rutland, sudeep.holla,
	lorenzo.pieralisi, catalin.marinas, will.deacon, morten.rasmussen,
	dietmar.eggemann, broonie, gregkh
In-Reply-To: <20170410150503.GS17774@n2100.armlinux.org.uk>

Hi,

On 10/04/17 16:05, Russell King - ARM Linux wrote:
> On Mon, Mar 27, 2017 at 02:18:16PM +0100, Juri Lelli wrote:
> > arm and arm64 topology.c share a lot of code related to parsing of capacity
> > information. This is v3 of a solution [1] (based on Will's, Catalin's and
> > Mark's off-line suggestions) to move such common code in a single place:
> > drivers/base/arch_topology.c (by creating such file and conditionally compiling
> > it for arm and arm64 only).
> 
> I think overall this is okay, with the exception of one patch which seems
> to be wrongly worded.

As I said in reply to your comments, we could also consider dropping
that patch entirely. What's your opinion?

> Once that's resolved, then:
> 
> Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
> 
> for the series.
> 

Also, I'd like to update 3/9 as suggested by Vincent.

Thanks for the review.

Best,

- Juri

^ permalink raw reply

* DT overlay issues - dtc flags
From: Andreas Färber @ 2017-04-10 16:16 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA, U-Boot
  Cc: Rob Herring,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-rpi-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Alexander Graf,
	Simon Glass

Hi,

I've tried to play around with Device Tree overlays (.dtbo files):

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/overlay-notes.txt

First of all, that document refers to a non-existing
Documentation/devicetree/dt-object-internal.txt. Could someone please
fix that one way or another?

In my particular example I've tried to extend the &i2c1 and &gpio nodes
of 4.11-rc5 arm64 broadcom/bcm2837-rpi-3-b.dts. The above documentation
prominently claims that this can be done via target = <&foo> syntax, but
U-Boot's fdt apply command fails for such a file. If instead I use the
alternative target-path = "/soc/..." then it works just fine.

As mentioned in the very bottom of the documentation, resolution of
phandle target references requires a __symbols__ node in the base .dtb.
IIUC this is only generated when passing the -@ dtc command line flag.

At first I thought this were an issue with how we build the .dtb files
in openSUSE [1], but by my reading of the kernel Makefiles not passing
-@ in DTC_FLAGS or cmd_dtc, you should run into the exact same issue.

I could think of a few ARMv7-M systems where such DT bloat might be
undesired (small flash sector sizes), but then it would seem easier to
suppress -@ where needed than to have a feature that by all practical
means is half unusable by default.

U-Boot itself appears to face a similar issue in that its internal
Device Trees are built without -@, and via Alex' distro boot extensions
this internal DT is passed on via UEFI as fallback when no external .dtb
file is found. So in the non-SPL case the DT should probably be built
with -@, too.

Or am I misunderstanding something here?

Thanks,
Andreas

[1]
https://build.opensuse.org/package/view_file/Kernel:HEAD/dtb-aarch64/dtb-aarch64.spec?expand=1

-- 
SUSE Linux GmbH, Maxfeldstr. 5, 90409 Nürnberg, Germany
GF: Felix Imendörffer, Jane Smithard, Graham Norton
HRB 21284 (AG Nürnberg)
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v2 2/2] mtd: spi-nor: add driver for STM32 quad spi flash controller
From: Marek Vasut @ 2017-04-10 16:15 UTC (permalink / raw)
  To: Ludovic BARRE, Cyrille Pitchen
  Cc: David Woodhouse, Brian Norris, Boris Brezillon,
	Richard Weinberger, Alexandre Torgue, Rob Herring, linux-mtd,
	linux-kernel, devicetree
In-Reply-To: <601e2aa5-7cd3-34fb-660e-359f2a016b65@st.com>

On 04/10/2017 11:08 AM, Ludovic BARRE wrote:
> 
> On 04/07/2017 01:55 AM, Marek Vasut wrote:
>> On 03/31/2017 07:02 PM, Ludovic Barre wrote:
>>> From: Ludovic Barre <ludovic.barre@st.com>
>>>
>>> The quadspi is a specialized communication interface targeting single,
>>> dual or quad SPI Flash memories.
>>>
>>> It can operate in any of the following modes:
>>> -indirect mode: all the operations are performed using the quadspi
>>>   registers
>>> -read memory-mapped mode: the external Flash memory is mapped to the
>>>   microcontroller address space and is seen by the system as if it was
>>>   an internal memory
>>>
>>> Signed-off-by: Ludovic Barre <ludovic.barre@st.com>
>>> ---
>>>   drivers/mtd/spi-nor/Kconfig         |   7 +
>>>   drivers/mtd/spi-nor/Makefile        |   1 +
>>>   drivers/mtd/spi-nor/stm32-quadspi.c | 690
>>> ++++++++++++++++++++++++++++++++++++
>>>   3 files changed, 698 insertions(+)
>>>   create mode 100644 drivers/mtd/spi-nor/stm32-quadspi.c
>>>
>> [...]
>>
>>> +struct stm32_qspi_flash {
>>> +    struct spi_nor nor;
>>> +    u32 cs;
>>> +    u32 fsize;
>>> +    u32 presc;
>>> +    struct stm32_qspi *qspi;
>>> +};
>> [...]
>>
>>> +struct stm32_qspi_cmd {
>>> +    struct {
>>> +        u8 addr_width;
>>> +        u8 dummy;
>>> +        u8 data;
>>> +    } conf;
>> Is there any benefit in having this structure here or could you just
>> make the struct stm32_qspi_cmd flat ?
> no benefit, it was just to regroup,  so I can do a flat structure

Well, as you like, but I think it does make sense to just make it flat.

>>> +    u8 opcode;
>>> +    u32 framemode;
>>> +    u32 qspimode;
>>> +    u32 addr;
>>> +    size_t len;
>>> +    void *buf;
>>> +};
>> [...]
>>
>>> +static ssize_t stm32_qspi_read(struct spi_nor *nor, loff_t from,
>>> size_t len,
>>> +                   u_char *buf)
>>> +{
>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>> +    struct stm32_qspi *qspi = flash->qspi;
>>> +    struct stm32_qspi_cmd cmd;
>>> +    int err;
>>> +
>>> +    dev_dbg(qspi->dev, "read(%#.2x): buf:%p from:%#.8x len:%#x\n",
>>> +        nor->read_opcode, buf, (u32)from, len);
>>> +
>>> +    memset(&cmd, 0, sizeof(cmd));
>>> +    cmd.opcode = nor->read_opcode;
>>> +    cmd.conf.addr_width = nor->addr_width;
>>> +    cmd.addr = (u32)from;
>> loff_t (from) can be 64bit ... how do we handle this ?
> I'm surprise by the question,
> the SPI NOR device uses 3 Bytes or 4 bytes address mode.
> So, the stm32 qspi controller has a 32 bit register for NOR address.
> On the other hand the framework and other drivers used this variable
> (from) like
> a 32 bits.

Hmmm, (rhetorical question) then why do we even use loff_t in the
framework ?

Anyway, this is no problem then.

>>> +    cmd.conf.data = 1;
>>> +    cmd.conf.dummy = nor->read_dummy;
>>> +    cmd.len = len;
>>> +    cmd.buf = buf;
>>> +    cmd.qspimode = qspi->read_mode;
>>> +
>>> +    stm32_qspi_set_framemode(nor, &cmd, true);
>>> +    err = stm32_qspi_send(flash, &cmd);
>>> +
>>> +    return err ? err : len;
>>> +}
>> [...]
>>
>>> +static irqreturn_t stm32_qspi_irq(int irq, void *dev_id)
>>> +{
>>> +    struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id;
>>> +    u32 cr, sr, fcr = 0;
>>> +
>>> +    cr = readl_relaxed(qspi->io_base + QUADSPI_CR);
>>> +    sr = readl_relaxed(qspi->io_base + QUADSPI_SR);
>>> +
>>> +    if ((cr & CR_TCIE) && (sr & SR_TCF)) {
>>> +        /* tx complete */
>>> +        fcr |= FCR_CTCF;
>>> +        complete(&qspi->cmd_completion);
>>> +    } else {
>>> +        dev_info(qspi->dev, "spurious interrupt\n");
>> You probably want to ratelimit this one ...
> yes it's better if there is an issue.

Yep

>>> +    }
>>> +
>>> +    writel_relaxed(fcr, qspi->io_base + QUADSPI_FCR);
>>> +
>>> +    return IRQ_HANDLED;
>>> +}
>>> +
>>> +static int stm32_qspi_prep(struct spi_nor *nor, enum spi_nor_ops ops)
>>> +{
>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>> +    struct stm32_qspi *qspi = flash->qspi;
>>> +
>>> +    mutex_lock(&qspi->lock);
>>> +    return 0;
>>> +}
>>> +
>>> +static void stm32_qspi_unprep(struct spi_nor *nor, enum spi_nor_ops
>>> ops)
>>> +{
>>> +    struct stm32_qspi_flash *flash = nor->priv;
>>> +    struct stm32_qspi *qspi = flash->qspi;
>>> +
>>> +    mutex_unlock(&qspi->lock);
>>> +}
>>> +
>>> +static int stm32_qspi_flash_setup(struct stm32_qspi *qspi,
>>> +                  struct device_node *np)
>>> +{
>>> +    u32 width, flash_read, presc, cs_num, max_rate = 0;
>>> +    struct stm32_qspi_flash *flash;
>>> +    struct mtd_info *mtd;
>>> +    int ret;
>>> +
>>> +    of_property_read_u32(np, "reg", &cs_num);
>>> +    if (cs_num >= STM32_MAX_NORCHIP)
>>> +        return -EINVAL;
>>> +
>>> +    of_property_read_u32(np, "spi-max-frequency", &max_rate);
>>> +    if (!max_rate)
>>> +        return -EINVAL;
>>> +
>>> +    presc = DIV_ROUND_UP(qspi->clk_rate, max_rate) - 1;
>>> +
>>> +    if (of_property_read_u32(np, "spi-rx-bus-width", &width))
>>> +        width = 1;
>>> +
>>> +    if (width == 4)
>>> +        flash_read = SPI_NOR_QUAD;
>>> +    else if (width == 2)
>>> +        flash_read = SPI_NOR_DUAL;
>>> +    else if (width == 1)
>>> +        flash_read = SPI_NOR_NORMAL;
>>> +    else
>>> +        return -EINVAL;
>>> +
>>> +    flash = &qspi->flash[cs_num];
>>> +    flash->qspi = qspi;
>>> +    flash->cs = cs_num;
>>> +    flash->presc = presc;
>>> +
>>> +    flash->nor.dev = qspi->dev;
>>> +    spi_nor_set_flash_node(&flash->nor, np);
>>> +    flash->nor.priv = flash;
>>> +    mtd = &flash->nor.mtd;
>>> +    mtd->priv = &flash->nor;
>>> +
>>> +    flash->nor.read = stm32_qspi_read;
>>> +    flash->nor.write = stm32_qspi_write;
>>> +    flash->nor.erase = stm32_qspi_erase;
>>> +    flash->nor.read_reg = stm32_qspi_read_reg;
>>> +    flash->nor.write_reg = stm32_qspi_write_reg;
>>> +    flash->nor.prepare = stm32_qspi_prep;
>>> +    flash->nor.unprepare = stm32_qspi_unprep;
>>> +
>>> +    writel_relaxed(LPTR_DFT_TIMEOUT, qspi->io_base + QUADSPI_LPTR);
>>> +
>>> +    writel_relaxed(CR_PRESC(presc) | CR_FTHRES(3) | CR_TCEN | CR_SSHIFT
>>> +               | CR_EN, qspi->io_base + QUADSPI_CR);
>>> +
>>> +    /*
>>> +     * in stm32 qspi controller, QUADSPI_DCR register has a fsize field
>>> +     * which define the size of nor flash.
>>> +     * if fsize is NULL, the controller can't sent spi-nor command.
>>> +     * set a temporary value just to discover the nor flash with
>>> +     * "spi_nor_scan". After, the right value (mtd->size) can be set.
>>> +     */
>> Is 25 the smallest value ? Use a macro for this ...
> 25 is an arbitrary choice, I will define a smallest value

Cool, thanks!

-- 
Best regards,
Marek Vasut

^ permalink raw reply

* [git:media_tree/master] [media] s5p-cec.txt: document the HDMI controller phandle
From: Mauro Carvalho Chehab @ 2017-04-10 16:13 UTC (permalink / raw)
  To: linuxtv-commits-dJidKbW2IEtAfugRpC6u6w
  Cc: Rob Herring, linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	Hans Verkuil, Krzysztof Kozlowski,
	devicetree-u79uwXL29TY76Z2rM5mHXA

This is an automatic generated email to let you know that the following patch were queued:

Subject: [media] s5p-cec.txt: document the HDMI controller phandle
Author:  Hans Verkuil <hans.verkuil@cisco.com>
Date:    Tue Dec 13 12:37:16 2016 -0200

Update the bindings documenting the new hdmi phandle.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Krzysztof Kozlowski <krzk@kernel.org>
Acked-by: Rob Herring <robh@kernel.org>
CC: linux-samsung-soc@vger.kernel.org
CC: devicetree@vger.kernel.org
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

 Documentation/devicetree/bindings/media/s5p-cec.txt | 2 ++
 1 file changed, 2 insertions(+)

---

diff --git a/Documentation/devicetree/bindings/media/s5p-cec.txt b/Documentation/devicetree/bindings/media/s5p-cec.txt
index 925ab4d72eaa..4bb08d9d940b 100644
--- a/Documentation/devicetree/bindings/media/s5p-cec.txt
+++ b/Documentation/devicetree/bindings/media/s5p-cec.txt
@@ -15,6 +15,7 @@ Required properties:
   - clock-names : from common clock binding: must contain "hdmicec",
 		  corresponding to entry in the clocks property.
   - samsung,syscon-phandle - phandle to the PMU system controller
+  - hdmi-phandle - phandle to the HDMI controller
 
 Example:
 
@@ -25,6 +26,7 @@ hdmicec: cec@100B0000 {
 	clocks = <&clock CLK_HDMI_CEC>;
 	clock-names = "hdmicec";
 	samsung,syscon-phandle = <&pmu_system_controller>;
+	hdmi-phandle = <&hdmi>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&hdmi_cec>;
 	status = "okay";

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

^ permalink raw reply related

* [git:media_tree/master] [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
From: Mauro Carvalho Chehab @ 2017-04-10 16:12 UTC (permalink / raw)
  To: linuxtv-commits-dJidKbW2IEtAfugRpC6u6w
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA, Hans Verkuil,
	Krzysztof Kozlowski, Marek Szyprowski

This is an automatic generated email to let you know that the following patch were queued:

Subject: [media] ARM: dts: exynos: add HDMI controller phandle to exynos4.dtsi
Author:  Hans Verkuil <hans.verkuil@cisco.com>
Date:    Tue Dec 13 12:37:16 2016 -0200

Add the new hdmi phandle to exynos4.dtsi. This phandle is needed by the
s5p-cec driver to initialize the CEC notifier framework.

Tested with my Odroid U3.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
CC: linux-samsung-soc@vger.kernel.org
CC: devicetree@vger.kernel.org
CC: Krzysztof Kozlowski <krzk@kernel.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>

 arch/arm/boot/dts/exynos4.dtsi | 1 +
 1 file changed, 1 insertion(+)

---

diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index 18def1c774d5..84fcdff140ae 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -771,6 +771,7 @@
 		clocks = <&clock CLK_HDMI_CEC>;
 		clock-names = "hdmicec";
 		samsung,syscon-phandle = <&pmu_system_controller>;
+		hdmi-phandle = <&hdmi>;
 		pinctrl-names = "default";
 		pinctrl-0 = <&hdmi_cec>;
 		status = "disabled";

_______________________________________________
linuxtv-commits mailing list
linuxtv-commits@linuxtv.org
https://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits

^ permalink raw reply related

* Re: [PATCHv3 02/10] serdev: add serdev_device_wait_until_sent
From: Rob Herring @ 2017-04-10 16:12 UTC (permalink / raw)
  To: Greg Kroah-Hartman
  Cc: Sebastian Reichel, Marcel Holtmann, Gustavo Padovan,
	Johan Hedberg, Samuel Thibault, Pavel Machek, Tony Lindgren,
	Jiri Slaby, Mark Rutland, open list:BLUETOOTH DRIVERS,
	linux-serial-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Andrey Smirnov
In-Reply-To: <20170410140313.GA31894-U8xfFu+wG4EAvxtiuMwx3w@public.gmane.org>

+ Andrey

On Mon, Apr 10, 2017 at 9:03 AM, Greg Kroah-Hartman
<gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> wrote:
> On Mon, Apr 10, 2017 at 08:46:57AM -0500, Rob Herring wrote:
>> On Sat, Apr 8, 2017 at 11:57 AM, Greg Kroah-Hartman
>> <gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r@public.gmane.org> wrote:
>> > On Tue, Mar 28, 2017 at 05:59:31PM +0200, Sebastian Reichel wrote:
>> >> Add method, which waits until the transmission buffer has been sent.
>> >> Note, that the change in ttyport_write_wakeup is related, since
>> >> tty_wait_until_sent will hang without that change.
>> >>
>> >> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> >> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
>> >> Signed-off-by: Sebastian Reichel <sre-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> >> ---
>> >> Changes since PATCHv2:
>> >>  * Avoid goto in ttyport_write_wakeup
>> >> ---
>> >>  drivers/tty/serdev/core.c           | 11 +++++++++++
>> >>  drivers/tty/serdev/serdev-ttyport.c | 18 ++++++++++++++----
>> >>  include/linux/serdev.h              |  3 +++
>> >>  3 files changed, 28 insertions(+), 4 deletions(-)
>> >>
>> >> diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c
>> >> index f4c6c90add78..a63b74031e22 100644
>> >> --- a/drivers/tty/serdev/core.c
>> >> +++ b/drivers/tty/serdev/core.c
>> >> @@ -173,6 +173,17 @@ void serdev_device_set_flow_control(struct serdev_device *serdev, bool enable)
>> >>  }
>> >>  EXPORT_SYMBOL_GPL(serdev_device_set_flow_control);
>> >>
>> >> +void serdev_device_wait_until_sent(struct serdev_device *serdev, long timeout)
>> >> +{
>> >> +     struct serdev_controller *ctrl = serdev->ctrl;
>> >> +
>> >> +     if (!ctrl || !ctrl->ops->wait_until_sent)
>> >> +             return;
>> >> +
>> >> +     ctrl->ops->wait_until_sent(ctrl, timeout);
>> >> +}
>> >> +EXPORT_SYMBOL_GPL(serdev_device_wait_until_sent);
>> >
>> > Is this still needed now that we have serdev_device_write() with an
>> > unlimited timeout available?
>>
>> Yes, because only this waits until the data is on the wire.
>
> What "wire" is that?  The serial wire?  How do you know this?  Many usb
> to serial devices have no way to determine this, given that there is
> another uart hanging off of the end of a USB connection.

Okay, maybe it's just out of linux s/w buffers for h/w which you don't
know. It is the same semantics as tty_wait_until_sent which is
documented as: "Wait for characters pending in a tty driver to hit the
wire, or for a timeout to occur (eg due to flow control)"

> Doesn't serdev_device_write() return when the write is finished?

No, it returns when data is accepted by the tty layer (as serdev has
no buffering of its own).

>  I
> think we need some good documentation here for all of the different
> variants of how to send data, as I'm sure confused...

Fair enough. However, I think that's somewhat orthogonal to this function.

There's 2 modes of sending data which are basically sync and async operation.

- serdev_device_write_buf - Only sends what can be immediately
accepted by lower layers. Caller should provide write_wakeup callback
to be notified.

- serdev_device_write - Sleeps until all data is accepted by lower
layers or a timeout occurs.

It's valid to call serdev_device_wait_until_sent in either case.


Yes, the naming is not the best, but we kept serdev_device_write_buf
to avoid any cross tree merges. We can remove or rename later as it is
just a wrapper now for serdev_device_write.

Rob

^ permalink raw reply

* Re: [PATCH v2 2/5] iio: dac: add support for stm32 DAC
From: Fabrice Gasnier @ 2017-04-10 15:56 UTC (permalink / raw)
  To: Jonathan Cameron, linux, robh+dt, linux-arm-kernel, devicetree,
	linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, benjamin.gaignard
In-Reply-To: <ceac5030-3a3c-dfdc-aa5d-9b5ea0165a0c@kernel.org>

On 04/09/2017 10:39 AM, Jonathan Cameron wrote:
> On 06/04/17 17:11, Fabrice Gasnier wrote:
>> Add support for STMicroelectronics STM32 DAC. It's a 12-bit, voltage
>> output digital-to-analog converter. It has two output channels, each
>> with its own converter.
>> It supports 8 bits or 12bits left/right aligned data format. Only
>> 12bits right-aligned is used here. It has built-in noise or
>> triangle waveform generator, and supports external triggers for
>> conversions.
>> Each channel can be used independently, with separate trigger, then
>> separate IIO devices are used to handle this. Core driver is intended
>> to share common resources such as clock, reset, reference voltage and
>> registers.
>>
>> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
> A few little bits and pieces from the change to powerdown modes...
> 
> I have also been thinking about whether we can take this prior to sorting
> out the DDS side, but worry a little that we may end up wanting to change
> the way we define the channels - so that might need sorting to some degree
> before we can get the basics in place.

Hi Jonathan,

Just sent updated v3 with powerdown changes as per your comments.

> 
> Jonathan
>> ---
>> Changes in v2:
>> - Define 'Hi-Z'/'enable' powerdown modes instead of using 'enable'
>>   attribute normally not used for DACs.
>> - use 'reg' instead of 'st,dac-channel' property
>> - Use macro to differentiate channels
>> - Fix typos, remove leading '&' for functions
>> - Add comments on single channel per device
>> - Use devm_iio_device_register variant, removes need for .remove
>> ---
>>  drivers/iio/dac/Kconfig          |  15 ++
>>  drivers/iio/dac/Makefile         |   2 +
>>  drivers/iio/dac/stm32-dac-core.c | 180 ++++++++++++++++++++
>>  drivers/iio/dac/stm32-dac-core.h |  51 ++++++
>>  drivers/iio/dac/stm32-dac.c      | 350 +++++++++++++++++++++++++++++++++++++++
>>  5 files changed, 598 insertions(+)
>>  create mode 100644 drivers/iio/dac/stm32-dac-core.c
>>  create mode 100644 drivers/iio/dac/stm32-dac-core.h
>>  create mode 100644 drivers/iio/dac/stm32-dac.c
>>
>> diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
>> index d3084028..7198648 100644
>> --- a/drivers/iio/dac/Kconfig
>> +++ b/drivers/iio/dac/Kconfig
>> @@ -274,6 +274,21 @@ config MCP4922
>>  	  To compile this driver as a module, choose M here: the module
>>  	  will be called mcp4922.
>>  
>> +config STM32_DAC
>> +	tristate "STMicroelectronics STM32 DAC"
>> +	depends on (ARCH_STM32 && OF) || COMPILE_TEST
>> +	depends on REGULATOR
>> +	select STM32_DAC_CORE
>> +	help
>> +	  Say yes here to build support for STMicroelectronics STM32 Digital
>> +	  to Analog Converter (DAC).
>> +
>> +	  This driver can also be built as a module.  If so, the module
>> +	  will be called stm32-dac.
>> +
>> +config STM32_DAC_CORE
>> +	tristate
>> +
>>  config VF610_DAC
>>  	tristate "Vybrid vf610 DAC driver"
>>  	depends on OF
>> diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
>> index f01bf4a..afe8ae7 100644
>> --- a/drivers/iio/dac/Makefile
>> +++ b/drivers/iio/dac/Makefile
>> @@ -29,4 +29,6 @@ obj-$(CONFIG_MAX517) += max517.o
>>  obj-$(CONFIG_MAX5821) += max5821.o
>>  obj-$(CONFIG_MCP4725) += mcp4725.o
>>  obj-$(CONFIG_MCP4922) += mcp4922.o
>> +obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
>> +obj-$(CONFIG_STM32_DAC) += stm32-dac.o
>>  obj-$(CONFIG_VF610_DAC) += vf610_dac.o
>> diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
>> new file mode 100644
>> index 0000000..75e4878
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac-core.c
>> @@ -0,0 +1,180 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/module.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/regulator/consumer.h>
>> +#include <linux/reset.h>
>> +
>> +#include "stm32-dac-core.h"
>> +
>> +/**
>> + * struct stm32_dac_priv - stm32 DAC core private data
>> + * @pclk:		peripheral clock common for all DACs
>> + * @rst:		peripheral reset control
>> + * @vref:		regulator reference
>> + * @common:		Common data for all DAC instances
>> + */
>> +struct stm32_dac_priv {
>> +	struct clk *pclk;
>> +	struct reset_control *rst;
>> +	struct regulator *vref;
>> +	struct stm32_dac_common common;
>> +};
>> +
>> +static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com)
>> +{
>> +	return container_of(com, struct stm32_dac_priv, common);
>> +}
>> +
>> +static const struct regmap_config stm32_dac_regmap_cfg = {
>> +	.reg_bits = 32,
>> +	.val_bits = 32,
>> +	.reg_stride = sizeof(u32),
>> +	.max_register = 0x3fc,
>> +};
>> +
>> +static int stm32_dac_probe(struct platform_device *pdev)
>> +{
>> +	struct device *dev = &pdev->dev;
>> +	struct stm32_dac_priv *priv;
>> +	struct regmap *regmap;
>> +	struct resource *res;
>> +	void __iomem *mmio;
>> +	int ret;
>> +
>> +	if (!dev->of_node)
>> +		return -ENODEV;
>> +
>> +	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
>> +	if (!priv)
>> +		return -ENOMEM;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	mmio = devm_ioremap_resource(dev, res);
>> +	if (IS_ERR(mmio))
>> +		return PTR_ERR(mmio);
>> +
>> +	regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
>> +	if (IS_ERR(regmap))
>> +		return PTR_ERR(regmap);
>> +	priv->common.regmap = regmap;
>> +
>> +	priv->vref = devm_regulator_get(dev, "vref");
>> +	if (IS_ERR(priv->vref)) {
>> +		ret = PTR_ERR(priv->vref);
>> +		dev_err(dev, "vref get failed, %d\n", ret);
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_enable(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(dev, "vref enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	ret = regulator_get_voltage(priv->vref);
>> +	if (ret < 0) {
>> +		dev_err(dev, "vref get voltage failed, %d\n", ret);
>> +		goto err_vref;
>> +	}
>> +	priv->common.vref_mv = ret / 1000;
>> +	dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
>> +
>> +	priv->pclk = devm_clk_get(dev, "pclk");
>> +	if (IS_ERR(priv->pclk)) {
>> +		ret = PTR_ERR(priv->pclk);
>> +		dev_err(dev, "pclk get failed\n");
>> +		goto err_vref;
>> +	}
>> +
>> +	ret = clk_prepare_enable(priv->pclk);
>> +	if (ret < 0) {
>> +		dev_err(dev, "pclk enable failed\n");
>> +		goto err_vref;
>> +	}
>> +
>> +	priv->rst = devm_reset_control_get(dev, NULL);
>> +	if (!IS_ERR(priv->rst)) {
>> +		reset_control_assert(priv->rst);
>> +		udelay(2);
>> +		reset_control_deassert(priv->rst);
>> +	}
>> +
>> +	/* When clock speed is higher than 80MHz, set HFSEL */
>> +	priv->common.hfsel = (clk_get_rate(priv->pclk) > 80000000UL);
>> +	ret = regmap_update_bits(regmap, STM32_DAC_CR, STM32H7_DAC_CR_HFSEL,
>> +				 priv->common.hfsel ? STM32H7_DAC_CR_HFSEL : 0);
>> +	if (ret)
>> +		goto err_pclk;
>> +
>> +	platform_set_drvdata(pdev, &priv->common);
>> +
>> +	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
>> +	if (ret < 0) {
>> +		dev_err(dev, "failed to populate DT children\n");
>> +		goto err_pclk;
>> +	}
>> +
>> +	return 0;
>> +
>> +err_pclk:
>> +	clk_disable_unprepare(priv->pclk);
>> +err_vref:
>> +	regulator_disable(priv->vref);
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_remove(struct platform_device *pdev)
>> +{
>> +	struct stm32_dac_common *common = platform_get_drvdata(pdev);
>> +	struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
>> +
>> +	of_platform_depopulate(&pdev->dev);
>> +	clk_disable_unprepare(priv->pclk);
>> +	regulator_disable(priv->vref);
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id stm32_dac_of_match[] = {
>> +	{ .compatible = "st,stm32h7-dac-core", },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
>> +
>> +static struct platform_driver stm32_dac_driver = {
>> +	.probe = stm32_dac_probe,
>> +	.remove = stm32_dac_remove,
>> +	.driver = {
>> +		.name = "stm32-dac-core",
>> +		.of_match_table = stm32_dac_of_match,
>> +	},
>> +};
>> +module_platform_driver(stm32_dac_driver);
>> +
>> +MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
>> +MODULE_DESCRIPTION("STMicroelectronics STM32 DAC core driver");
>> +MODULE_LICENSE("GPL v2");
>> +MODULE_ALIAS("platform:stm32-dac-core");
>> diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
>> new file mode 100644
>> index 0000000..daf0993
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac-core.h
>> @@ -0,0 +1,51 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#ifndef __STM32_DAC_CORE_H
>> +#define __STM32_DAC_CORE_H
>> +
>> +#include <linux/regmap.h>
>> +
>> +/* STM32 DAC registers */
>> +#define STM32_DAC_CR		0x00
>> +#define STM32_DAC_DHR12R1	0x08
>> +#define STM32_DAC_DHR12R2	0x14
>> +#define STM32_DAC_DOR1		0x2C
>> +#define STM32_DAC_DOR2		0x30
>> +
>> +/* STM32_DAC_CR bit fields */
>> +#define STM32_DAC_CR_EN1		BIT(0)
>> +#define STM32H7_DAC_CR_HFSEL		BIT(15)
>> +#define STM32_DAC_CR_EN2		BIT(16)
>> +
>> +/**
>> + * struct stm32_dac_common - stm32 DAC driver common data (for all instances)
>> + * @regmap: DAC registers shared via regmap
>> + * @vref_mv: reference voltage (mv)
>> + * @hfsel: high speed bus clock selected
>> + */
>> +struct stm32_dac_common {
>> +	struct regmap			*regmap;
>> +	int				vref_mv;
>> +	bool				hfsel;
>> +};
>> +
>> +#endif
>> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
>> new file mode 100644
>> index 0000000..c0d993a
>> --- /dev/null
>> +++ b/drivers/iio/dac/stm32-dac.c
>> @@ -0,0 +1,350 @@
>> +/*
>> + * This file is part of STM32 DAC driver
>> + *
>> + * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
>> + * Authors: Amelie Delaunay <amelie.delaunay@st.com>
>> + *	    Fabrice Gasnier <fabrice.gasnier@st.com>
>> + *
>> + * License type: GPLv2
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License version 2 as published by
>> + * the Free Software Foundation.
>> + *
>> + * 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.
>> + *
>> + * You should have received a copy of the GNU General Public License along with
>> + * this program. If not, see <http://www.gnu.org/licenses/>.
>> + */
>> +
>> +#include <linux/bitfield.h>
>> +#include <linux/delay.h>
>> +#include <linux/iio/iio.h>
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/platform_device.h>
>> +
>> +#include "stm32-dac-core.h"
>> +
>> +#define STM32_DAC_CHANNEL_1		1
>> +#define STM32_DAC_CHANNEL_2		2
>> +#define STM32_DAC_IS_CHAN_1(ch)		((ch) & STM32_DAC_CHANNEL_1)
>> +
>> +/**
>> + * struct stm32_dac - private data of DAC driver
>> + * @common:		reference to DAC common data
>> + */
>> +struct stm32_dac {
>> +	struct stm32_dac_common *common;
>> +};
>> +
>> +static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 en, val;
>> +	int ret;
>> +
>> +	ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
>> +	if (ret < 0)
>> +		return ret;
>> +	if (STM32_DAC_IS_CHAN_1(channel))
>> +		en = FIELD_GET(STM32_DAC_CR_EN1, val);
>> +	else
>> +		en = FIELD_GET(STM32_DAC_CR_EN2, val);
>> +
>> +	return !!en;
>> +}
>> +
>> +static int stm32_dac_enable(struct iio_dev *indio_dev, int channel)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 en = STM32_DAC_IS_CHAN_1(channel) ?
>> +		STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, en, en);
>> +	if (ret < 0) {
>> +		dev_err(&indio_dev->dev, "Enable failed\n");
>> +		return ret;
>> +	}
>> +
>> +	/*
>> +	 * When HFSEL is set, it is not allowed to write the DHRx register
>> +	 * during 8 clock cycles after the ENx bit is set. It is not allowed
>> +	 * to make software/hardware trigger during this period either.
>> +	 */
>> +	if (dac->common->hfsel)
>> +		udelay(1);
>> +
>> +	return 0;
>> +}
>> +
>> +static int stm32_dac_disable(struct iio_dev *indio_dev, int channel)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +	u32 en = STM32_DAC_IS_CHAN_1(channel) ?
>> +		STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
>> +	int ret;
>> +
>> +	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, en, 0);
>> +	if (ret)
>> +		dev_err(&indio_dev->dev, "Disable failed\n");
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
>> +{
>> +	int ret;
>> +
>> +	if (STM32_DAC_IS_CHAN_1(channel))
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR1, val);
>> +	else
>> +		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR2, val);
>> +
>> +	return ret ? ret : IIO_VAL_INT;
>> +}
>> +
>> +static int stm32_dac_set_value(struct stm32_dac *dac, int channel, int val)
>> +{
>> +	int ret;
>> +
>> +	if (STM32_DAC_IS_CHAN_1(channel))
>> +		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R1, val);
>> +	else
>> +		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R2, val);
>> +
>> +	return ret;
>> +}
>> +
>> +static int stm32_dac_read_raw(struct iio_dev *indio_dev,
>> +			      struct iio_chan_spec const *chan,
>> +			      int *val, int *val2, long mask)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_RAW:
>> +		return stm32_dac_get_value(dac, chan->channel, val);
>> +	case IIO_CHAN_INFO_SCALE:
>> +		*val = dac->common->vref_mv;
>> +		*val2 = chan->scan_type.realbits;
>> +		return IIO_VAL_FRACTIONAL_LOG2;
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int stm32_dac_write_raw(struct iio_dev *indio_dev,
>> +			       struct iio_chan_spec const *chan,
>> +			       int val, int val2, long mask)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +
>> +	switch (mask) {
>> +	case IIO_CHAN_INFO_RAW:
>> +		return stm32_dac_set_value(dac, chan->channel, val);
>> +	default:
>> +		return -EINVAL;
>> +	}
>> +}
>> +
>> +static int stm32_dac_debugfs_reg_access(struct iio_dev *indio_dev,
>> +					unsigned reg, unsigned writeval,
>> +					unsigned *readval)
>> +{
>> +	struct stm32_dac *dac = iio_priv(indio_dev);
>> +
>> +	if (!readval)
>> +		return regmap_write(dac->common->regmap, reg, writeval);
>> +	else
>> +		return regmap_read(dac->common->regmap, reg, readval);
>> +}
>> +
>> +static const struct iio_info stm32_dac_iio_info = {
>> +	.read_raw = stm32_dac_read_raw,
>> +	.write_raw = stm32_dac_write_raw,
>> +	.debugfs_reg_access = stm32_dac_debugfs_reg_access,
>> +	.driver_module = THIS_MODULE,
>> +};
>> +
>> +static const char * const stm32_dac_powerdown_modes[] = {
>> +	"Hi-Z",
>> +	"enable",
> I wouldn't expect to see enable in here, that is handled by the power down
> attribute.
> 
> Hi-Z is the currently defined threestate I think?
> 
> Documenation/ABI/testing/sysfs-bus-iio

Yes, documentation states: "three_state: left floating".
Thanks for pointing that out.

> 
> Fine to propose additions to this but they need documenting in that general
> file.
>> +};
>> +
>> +static int stm32_dac_get_powerdown_mode(struct iio_dev *indio_dev,
>> +					const struct iio_chan_spec *chan)
>> +{
>> +	return stm32_dac_is_enabled(indio_dev, chan->channel);
>> +}
>> +
>> +static int stm32_dac_set_powerdown_mode(struct iio_dev *indio_dev,
>> +					const struct iio_chan_spec *chan,
>> +					unsigned int type)
>> +{
>> +	if (type)
>> +		return stm32_dac_enable(indio_dev, chan->channel);
>> +	else
>> +		return stm32_dac_disable(indio_dev, chan->channel);
>> +}
>> +
>> +static ssize_t stm32_dac_read_powerdown(struct iio_dev *indio_dev,
>> +					uintptr_t private,
>> +					const struct iio_chan_spec *chan,
>> +					char *buf)
>> +{
>> +	int ret = stm32_dac_is_enabled(indio_dev, chan->channel);
>> +
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return sprintf(buf, "%d\n", ret);
>> +}
>> +
>> +static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
>> +					 uintptr_t private,
>> +					 const struct iio_chan_spec *chan,
>> +					 const char *buf, size_t len)
>> +{
>> +	unsigned int en;
>> +	int ret;
>> +
>> +	ret = kstrtouint(buf, 0, &en);
> strtobool perhaps?

Done in v3. I also reworked a little all around powerdown mode.

Thanks,
Fabrice

>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = stm32_dac_set_powerdown_mode(indio_dev, chan, en);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return len;
>> +}
>> +
>> +static const struct iio_enum stm32_dac_powerdown_mode_en = {
>> +	.items = stm32_dac_powerdown_modes,
>> +	.num_items = ARRAY_SIZE(stm32_dac_powerdown_modes),
>> +	.get = stm32_dac_get_powerdown_mode,
>> +	.set = stm32_dac_set_powerdown_mode,
>> +};
>> +
>> +static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = {
>> +	{
>> +		.name = "powerdown",
>> +		.read = stm32_dac_read_powerdown,
>> +		.write = stm32_dac_write_powerdown,
>> +		.shared = IIO_SEPARATE,
>> +	},
>> +	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en),
>> +	IIO_ENUM_AVAILABLE("powerdown_mode", &stm32_dac_powerdown_mode_en),
>> +	{},
>> +};
>> +
>> +#define STM32_DAC_CHANNEL(chan, name) {			\
>> +	.type = IIO_VOLTAGE,				\
>> +	.indexed = 1,					\
>> +	.output = 1,					\
>> +	.channel = chan,				\
>> +	.info_mask_separate =				\
>> +		BIT(IIO_CHAN_INFO_RAW) |		\
>> +		BIT(IIO_CHAN_INFO_SCALE),		\
>> +	/* scan_index is always 0 as num_channels is 1 */ \
>> +	.scan_type = {					\
>> +		.sign = 'u',				\
>> +		.realbits = 12,				\
>> +		.storagebits = 16,			\
>> +	},						\
>> +	.datasheet_name = name,				\
>> +	.ext_info = stm32_dac_ext_info			\
>> +}
>> +
>> +static const struct iio_chan_spec stm32_dac_channels[] = {
>> +	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_1, "out1"),
>> +	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_2, "out2"),
>> +};
>> +
>> +static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
>> +{
>> +	struct device_node *np = indio_dev->dev.of_node;
>> +	unsigned int i;
>> +	u32 channel;
>> +	int ret;
>> +
>> +	ret = of_property_read_u32(np, "reg", &channel);
>> +	if (ret) {
>> +		dev_err(&indio_dev->dev, "Failed to read reg property\n");
>> +		return ret;
>> +	}
>> +
>> +	for (i = 0; i < ARRAY_SIZE(stm32_dac_channels); i++) {
>> +		if (stm32_dac_channels[i].channel == channel)
>> +			break;
>> +	}
>> +	if (i >= ARRAY_SIZE(stm32_dac_channels)) {
>> +		dev_err(&indio_dev->dev, "Invalid st,dac-channel\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	indio_dev->channels = &stm32_dac_channels[i];
>> +	/*
>> +	 * Expose only one channel here, as they can be used independently,
>> +	 * with separate trigger. Then separate IIO devices are instantiated
>> +	 * to manage this.
>> +	 */
>> +	indio_dev->num_channels = 1;
>> +
>> +	return 0;
>> +};
>> +
>> +static int stm32_dac_probe(struct platform_device *pdev)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct iio_dev *indio_dev;
>> +	struct stm32_dac *dac;
>> +	int ret;
>> +
>> +	if (!np)
>> +		return -ENODEV;
>> +
>> +	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +	platform_set_drvdata(pdev, indio_dev);
>> +
>> +	dac = iio_priv(indio_dev);
>> +	dac->common = dev_get_drvdata(pdev->dev.parent);
>> +	indio_dev->name = dev_name(&pdev->dev);
>> +	indio_dev->dev.parent = &pdev->dev;
>> +	indio_dev->dev.of_node = pdev->dev.of_node;
>> +	indio_dev->info = &stm32_dac_iio_info;
>> +	indio_dev->modes = INDIO_DIRECT_MODE;
>> +
>> +	ret = stm32_dac_chan_of_init(indio_dev);
>> +	if (ret < 0)
>> +		return ret;
>> +
>> +	return devm_iio_device_register(&pdev->dev, indio_dev);
>> +}
>> +
>> +static const struct of_device_id stm32_dac_of_match[] = {
>> +	{ .compatible = "st,stm32-dac", },
>> +	{},
>> +};
>> +MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
>> +
>> +static struct platform_driver stm32_dac_driver = {
>> +	.probe = stm32_dac_probe,
>> +	.driver = {
>> +		.name = "stm32-dac",
>> +		.of_match_table = stm32_dac_of_match,
>> +	},
>> +};
>> +module_platform_driver(stm32_dac_driver);
>> +
>> +MODULE_ALIAS("platform:stm32-dac");
>> +MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
>> +MODULE_DESCRIPTION("STMicroelectronics STM32 DAC driver");
>> +MODULE_LICENSE("GPL v2");
>>
> 

^ permalink raw reply

* [PATCH v3 2/2] iio: dac: add support for stm32 DAC
From: Fabrice Gasnier @ 2017-04-10 15:49 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: linux-iio, mark.rutland, mcoquelin.stm32, alexandre.torgue, lars,
	knaack.h, pmeerw, fabrice.gasnier, benjamin.gaignard,
	benjamin.gaignard
In-Reply-To: <1491839390-2449-1-git-send-email-fabrice.gasnier@st.com>

Add support for STMicroelectronics STM32 DAC. It's a 12-bit, voltage
output digital-to-analog converter. It has two output channels, each
with its own converter.
It supports 8 bits or 12bits left/right aligned data format. Only
12bits right-aligned is used here. It has built-in noise or
triangle waveform generator, and supports external triggers for
conversions.
Each channel can be used independently, with separate trigger, then
separate IIO devices are used to handle this. Core driver is intended
to share common resources such as clock, reset, reference voltage and
registers.

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v3:
- Fix powerdown, no need for 'enable', use 'three_state' as standard name
  for 'left floating' as per ABI documentation, instead of 'Hi-Z'.

Changes in v2:
- Define 'Hi-Z'/'enable' powerdown modes instead of using 'enable'
  attribute normally not used for DACs.
- use 'reg' instead of 'st,dac-channel' property
- Use macro to differentiate channels
- Fix typos, remove leading '&' for functions
- Add comments on single channel per device
- Use devm_iio_device_register variant, removes need for .remove
---
 drivers/iio/dac/Kconfig          |  15 ++
 drivers/iio/dac/Makefile         |   2 +
 drivers/iio/dac/stm32-dac-core.c | 180 +++++++++++++++++++++
 drivers/iio/dac/stm32-dac-core.h |  51 ++++++
 drivers/iio/dac/stm32-dac.c      | 334 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 582 insertions(+)
 create mode 100644 drivers/iio/dac/stm32-dac-core.c
 create mode 100644 drivers/iio/dac/stm32-dac-core.h
 create mode 100644 drivers/iio/dac/stm32-dac.c

diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig
index d3084028..7198648 100644
--- a/drivers/iio/dac/Kconfig
+++ b/drivers/iio/dac/Kconfig
@@ -274,6 +274,21 @@ config MCP4922
 	  To compile this driver as a module, choose M here: the module
 	  will be called mcp4922.
 
+config STM32_DAC
+	tristate "STMicroelectronics STM32 DAC"
+	depends on (ARCH_STM32 && OF) || COMPILE_TEST
+	depends on REGULATOR
+	select STM32_DAC_CORE
+	help
+	  Say yes here to build support for STMicroelectronics STM32 Digital
+	  to Analog Converter (DAC).
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called stm32-dac.
+
+config STM32_DAC_CORE
+	tristate
+
 config VF610_DAC
 	tristate "Vybrid vf610 DAC driver"
 	depends on OF
diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile
index f01bf4a..afe8ae7 100644
--- a/drivers/iio/dac/Makefile
+++ b/drivers/iio/dac/Makefile
@@ -29,4 +29,6 @@ obj-$(CONFIG_MAX517) += max517.o
 obj-$(CONFIG_MAX5821) += max5821.o
 obj-$(CONFIG_MCP4725) += mcp4725.o
 obj-$(CONFIG_MCP4922) += mcp4922.o
+obj-$(CONFIG_STM32_DAC_CORE) += stm32-dac-core.o
+obj-$(CONFIG_STM32_DAC) += stm32-dac.o
 obj-$(CONFIG_VF610_DAC) += vf610_dac.o
diff --git a/drivers/iio/dac/stm32-dac-core.c b/drivers/iio/dac/stm32-dac-core.c
new file mode 100644
index 0000000..75e4878
--- /dev/null
+++ b/drivers/iio/dac/stm32-dac-core.c
@@ -0,0 +1,180 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
+ *
+ * License type: GPLv2
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+
+#include "stm32-dac-core.h"
+
+/**
+ * struct stm32_dac_priv - stm32 DAC core private data
+ * @pclk:		peripheral clock common for all DACs
+ * @rst:		peripheral reset control
+ * @vref:		regulator reference
+ * @common:		Common data for all DAC instances
+ */
+struct stm32_dac_priv {
+	struct clk *pclk;
+	struct reset_control *rst;
+	struct regulator *vref;
+	struct stm32_dac_common common;
+};
+
+static struct stm32_dac_priv *to_stm32_dac_priv(struct stm32_dac_common *com)
+{
+	return container_of(com, struct stm32_dac_priv, common);
+}
+
+static const struct regmap_config stm32_dac_regmap_cfg = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = sizeof(u32),
+	.max_register = 0x3fc,
+};
+
+static int stm32_dac_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct stm32_dac_priv *priv;
+	struct regmap *regmap;
+	struct resource *res;
+	void __iomem *mmio;
+	int ret;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	mmio = devm_ioremap_resource(dev, res);
+	if (IS_ERR(mmio))
+		return PTR_ERR(mmio);
+
+	regmap = devm_regmap_init_mmio(dev, mmio, &stm32_dac_regmap_cfg);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+	priv->common.regmap = regmap;
+
+	priv->vref = devm_regulator_get(dev, "vref");
+	if (IS_ERR(priv->vref)) {
+		ret = PTR_ERR(priv->vref);
+		dev_err(dev, "vref get failed, %d\n", ret);
+		return ret;
+	}
+
+	ret = regulator_enable(priv->vref);
+	if (ret < 0) {
+		dev_err(dev, "vref enable failed\n");
+		return ret;
+	}
+
+	ret = regulator_get_voltage(priv->vref);
+	if (ret < 0) {
+		dev_err(dev, "vref get voltage failed, %d\n", ret);
+		goto err_vref;
+	}
+	priv->common.vref_mv = ret / 1000;
+	dev_dbg(dev, "vref+=%dmV\n", priv->common.vref_mv);
+
+	priv->pclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(priv->pclk)) {
+		ret = PTR_ERR(priv->pclk);
+		dev_err(dev, "pclk get failed\n");
+		goto err_vref;
+	}
+
+	ret = clk_prepare_enable(priv->pclk);
+	if (ret < 0) {
+		dev_err(dev, "pclk enable failed\n");
+		goto err_vref;
+	}
+
+	priv->rst = devm_reset_control_get(dev, NULL);
+	if (!IS_ERR(priv->rst)) {
+		reset_control_assert(priv->rst);
+		udelay(2);
+		reset_control_deassert(priv->rst);
+	}
+
+	/* When clock speed is higher than 80MHz, set HFSEL */
+	priv->common.hfsel = (clk_get_rate(priv->pclk) > 80000000UL);
+	ret = regmap_update_bits(regmap, STM32_DAC_CR, STM32H7_DAC_CR_HFSEL,
+				 priv->common.hfsel ? STM32H7_DAC_CR_HFSEL : 0);
+	if (ret)
+		goto err_pclk;
+
+	platform_set_drvdata(pdev, &priv->common);
+
+	ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, dev);
+	if (ret < 0) {
+		dev_err(dev, "failed to populate DT children\n");
+		goto err_pclk;
+	}
+
+	return 0;
+
+err_pclk:
+	clk_disable_unprepare(priv->pclk);
+err_vref:
+	regulator_disable(priv->vref);
+
+	return ret;
+}
+
+static int stm32_dac_remove(struct platform_device *pdev)
+{
+	struct stm32_dac_common *common = platform_get_drvdata(pdev);
+	struct stm32_dac_priv *priv = to_stm32_dac_priv(common);
+
+	of_platform_depopulate(&pdev->dev);
+	clk_disable_unprepare(priv->pclk);
+	regulator_disable(priv->vref);
+
+	return 0;
+}
+
+static const struct of_device_id stm32_dac_of_match[] = {
+	{ .compatible = "st,stm32h7-dac-core", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
+
+static struct platform_driver stm32_dac_driver = {
+	.probe = stm32_dac_probe,
+	.remove = stm32_dac_remove,
+	.driver = {
+		.name = "stm32-dac-core",
+		.of_match_table = stm32_dac_of_match,
+	},
+};
+module_platform_driver(stm32_dac_driver);
+
+MODULE_AUTHOR("Fabrice Gasnier <fabrice.gasnier@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DAC core driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stm32-dac-core");
diff --git a/drivers/iio/dac/stm32-dac-core.h b/drivers/iio/dac/stm32-dac-core.h
new file mode 100644
index 0000000..daf0993
--- /dev/null
+++ b/drivers/iio/dac/stm32-dac-core.h
@@ -0,0 +1,51 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Author: Fabrice Gasnier <fabrice.gasnier@st.com>.
+ *
+ * License type: GPLv2
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __STM32_DAC_CORE_H
+#define __STM32_DAC_CORE_H
+
+#include <linux/regmap.h>
+
+/* STM32 DAC registers */
+#define STM32_DAC_CR		0x00
+#define STM32_DAC_DHR12R1	0x08
+#define STM32_DAC_DHR12R2	0x14
+#define STM32_DAC_DOR1		0x2C
+#define STM32_DAC_DOR2		0x30
+
+/* STM32_DAC_CR bit fields */
+#define STM32_DAC_CR_EN1		BIT(0)
+#define STM32H7_DAC_CR_HFSEL		BIT(15)
+#define STM32_DAC_CR_EN2		BIT(16)
+
+/**
+ * struct stm32_dac_common - stm32 DAC driver common data (for all instances)
+ * @regmap: DAC registers shared via regmap
+ * @vref_mv: reference voltage (mv)
+ * @hfsel: high speed bus clock selected
+ */
+struct stm32_dac_common {
+	struct regmap			*regmap;
+	int				vref_mv;
+	bool				hfsel;
+};
+
+#endif
diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
new file mode 100644
index 0000000..50f8ec0
--- /dev/null
+++ b/drivers/iio/dac/stm32-dac.c
@@ -0,0 +1,334 @@
+/*
+ * This file is part of STM32 DAC driver
+ *
+ * Copyright (C) 2017, STMicroelectronics - All Rights Reserved
+ * Authors: Amelie Delaunay <amelie.delaunay@st.com>
+ *	    Fabrice Gasnier <fabrice.gasnier@st.com>
+ *
+ * License type: GPLv2
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "stm32-dac-core.h"
+
+#define STM32_DAC_CHANNEL_1		1
+#define STM32_DAC_CHANNEL_2		2
+#define STM32_DAC_IS_CHAN_1(ch)		((ch) & STM32_DAC_CHANNEL_1)
+
+/**
+ * struct stm32_dac - private data of DAC driver
+ * @common:		reference to DAC common data
+ */
+struct stm32_dac {
+	struct stm32_dac_common *common;
+};
+
+static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel)
+{
+	struct stm32_dac *dac = iio_priv(indio_dev);
+	u32 en, val;
+	int ret;
+
+	ret = regmap_read(dac->common->regmap, STM32_DAC_CR, &val);
+	if (ret < 0)
+		return ret;
+	if (STM32_DAC_IS_CHAN_1(channel))
+		en = FIELD_GET(STM32_DAC_CR_EN1, val);
+	else
+		en = FIELD_GET(STM32_DAC_CR_EN2, val);
+
+	return !!en;
+}
+
+static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
+				      bool enable)
+{
+	struct stm32_dac *dac = iio_priv(indio_dev);
+	u32 msk = STM32_DAC_IS_CHAN_1(ch) ? STM32_DAC_CR_EN1 : STM32_DAC_CR_EN2;
+	u32 en = enable ? msk : 0;
+	int ret;
+
+	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
+	if (ret < 0) {
+		dev_err(&indio_dev->dev, "%s failed\n", en ?
+			"Enable" : "Disable");
+		return ret;
+	}
+
+	/*
+	 * When HFSEL is set, it is not allowed to write the DHRx register
+	 * during 8 clock cycles after the ENx bit is set. It is not allowed
+	 * to make software/hardware trigger during this period either.
+	 */
+	if (en && dac->common->hfsel)
+		udelay(1);
+
+	return 0;
+}
+
+static int stm32_dac_get_value(struct stm32_dac *dac, int channel, int *val)
+{
+	int ret;
+
+	if (STM32_DAC_IS_CHAN_1(channel))
+		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR1, val);
+	else
+		ret = regmap_read(dac->common->regmap, STM32_DAC_DOR2, val);
+
+	return ret ? ret : IIO_VAL_INT;
+}
+
+static int stm32_dac_set_value(struct stm32_dac *dac, int channel, int val)
+{
+	int ret;
+
+	if (STM32_DAC_IS_CHAN_1(channel))
+		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R1, val);
+	else
+		ret = regmap_write(dac->common->regmap, STM32_DAC_DHR12R2, val);
+
+	return ret;
+}
+
+static int stm32_dac_read_raw(struct iio_dev *indio_dev,
+			      struct iio_chan_spec const *chan,
+			      int *val, int *val2, long mask)
+{
+	struct stm32_dac *dac = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return stm32_dac_get_value(dac, chan->channel, val);
+	case IIO_CHAN_INFO_SCALE:
+		*val = dac->common->vref_mv;
+		*val2 = chan->scan_type.realbits;
+		return IIO_VAL_FRACTIONAL_LOG2;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int stm32_dac_write_raw(struct iio_dev *indio_dev,
+			       struct iio_chan_spec const *chan,
+			       int val, int val2, long mask)
+{
+	struct stm32_dac *dac = iio_priv(indio_dev);
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+		return stm32_dac_set_value(dac, chan->channel, val);
+	default:
+		return -EINVAL;
+	}
+}
+
+static int stm32_dac_debugfs_reg_access(struct iio_dev *indio_dev,
+					unsigned reg, unsigned writeval,
+					unsigned *readval)
+{
+	struct stm32_dac *dac = iio_priv(indio_dev);
+
+	if (!readval)
+		return regmap_write(dac->common->regmap, reg, writeval);
+	else
+		return regmap_read(dac->common->regmap, reg, readval);
+}
+
+static const struct iio_info stm32_dac_iio_info = {
+	.read_raw = stm32_dac_read_raw,
+	.write_raw = stm32_dac_write_raw,
+	.debugfs_reg_access = stm32_dac_debugfs_reg_access,
+	.driver_module = THIS_MODULE,
+};
+
+static const char * const stm32_dac_powerdown_modes[] = {
+	"three_state",
+};
+
+static int stm32_dac_get_powerdown_mode(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan)
+{
+	return 0;
+}
+
+static int stm32_dac_set_powerdown_mode(struct iio_dev *indio_dev,
+					const struct iio_chan_spec *chan,
+					unsigned int type)
+{
+	return 0;
+}
+
+static ssize_t stm32_dac_read_powerdown(struct iio_dev *indio_dev,
+					uintptr_t private,
+					const struct iio_chan_spec *chan,
+					char *buf)
+{
+	int ret = stm32_dac_is_enabled(indio_dev, chan->channel);
+
+	if (ret < 0)
+		return ret;
+
+	return sprintf(buf, "%d\n", ret ? 0 : 1);
+}
+
+static ssize_t stm32_dac_write_powerdown(struct iio_dev *indio_dev,
+					 uintptr_t private,
+					 const struct iio_chan_spec *chan,
+					 const char *buf, size_t len)
+{
+	bool powerdown;
+	int ret;
+
+	ret = strtobool(buf, &powerdown);
+	if (ret)
+		return ret;
+
+	ret = stm32_dac_set_enable_state(indio_dev, chan->channel, !powerdown);
+	if (ret)
+		return ret;
+
+	return len;
+}
+
+static const struct iio_enum stm32_dac_powerdown_mode_en = {
+	.items = stm32_dac_powerdown_modes,
+	.num_items = ARRAY_SIZE(stm32_dac_powerdown_modes),
+	.get = stm32_dac_get_powerdown_mode,
+	.set = stm32_dac_set_powerdown_mode,
+};
+
+static const struct iio_chan_spec_ext_info stm32_dac_ext_info[] = {
+	{
+		.name = "powerdown",
+		.read = stm32_dac_read_powerdown,
+		.write = stm32_dac_write_powerdown,
+		.shared = IIO_SEPARATE,
+	},
+	IIO_ENUM("powerdown_mode", IIO_SEPARATE, &stm32_dac_powerdown_mode_en),
+	IIO_ENUM_AVAILABLE("powerdown_mode", &stm32_dac_powerdown_mode_en),
+	{},
+};
+
+#define STM32_DAC_CHANNEL(chan, name) {			\
+	.type = IIO_VOLTAGE,				\
+	.indexed = 1,					\
+	.output = 1,					\
+	.channel = chan,				\
+	.info_mask_separate =				\
+		BIT(IIO_CHAN_INFO_RAW) |		\
+		BIT(IIO_CHAN_INFO_SCALE),		\
+	/* scan_index is always 0 as num_channels is 1 */ \
+	.scan_type = {					\
+		.sign = 'u',				\
+		.realbits = 12,				\
+		.storagebits = 16,			\
+	},						\
+	.datasheet_name = name,				\
+	.ext_info = stm32_dac_ext_info			\
+}
+
+static const struct iio_chan_spec stm32_dac_channels[] = {
+	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_1, "out1"),
+	STM32_DAC_CHANNEL(STM32_DAC_CHANNEL_2, "out2"),
+};
+
+static int stm32_dac_chan_of_init(struct iio_dev *indio_dev)
+{
+	struct device_node *np = indio_dev->dev.of_node;
+	unsigned int i;
+	u32 channel;
+	int ret;
+
+	ret = of_property_read_u32(np, "reg", &channel);
+	if (ret) {
+		dev_err(&indio_dev->dev, "Failed to read reg property\n");
+		return ret;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(stm32_dac_channels); i++) {
+		if (stm32_dac_channels[i].channel == channel)
+			break;
+	}
+	if (i >= ARRAY_SIZE(stm32_dac_channels)) {
+		dev_err(&indio_dev->dev, "Invalid st,dac-channel\n");
+		return -EINVAL;
+	}
+
+	indio_dev->channels = &stm32_dac_channels[i];
+	/*
+	 * Expose only one channel here, as they can be used independently,
+	 * with separate trigger. Then separate IIO devices are instantiated
+	 * to manage this.
+	 */
+	indio_dev->num_channels = 1;
+
+	return 0;
+};
+
+static int stm32_dac_probe(struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct iio_dev *indio_dev;
+	struct stm32_dac *dac;
+	int ret;
+
+	if (!np)
+		return -ENODEV;
+
+	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*dac));
+	if (!indio_dev)
+		return -ENOMEM;
+	platform_set_drvdata(pdev, indio_dev);
+
+	dac = iio_priv(indio_dev);
+	dac->common = dev_get_drvdata(pdev->dev.parent);
+	indio_dev->name = dev_name(&pdev->dev);
+	indio_dev->dev.parent = &pdev->dev;
+	indio_dev->dev.of_node = pdev->dev.of_node;
+	indio_dev->info = &stm32_dac_iio_info;
+	indio_dev->modes = INDIO_DIRECT_MODE;
+
+	ret = stm32_dac_chan_of_init(indio_dev);
+	if (ret < 0)
+		return ret;
+
+	return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static const struct of_device_id stm32_dac_of_match[] = {
+	{ .compatible = "st,stm32-dac", },
+	{},
+};
+MODULE_DEVICE_TABLE(of, stm32_dac_of_match);
+
+static struct platform_driver stm32_dac_driver = {
+	.probe = stm32_dac_probe,
+	.driver = {
+		.name = "stm32-dac",
+		.of_match_table = stm32_dac_of_match,
+	},
+};
+module_platform_driver(stm32_dac_driver);
+
+MODULE_ALIAS("platform:stm32-dac");
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 DAC driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 1/2] dt-bindings: iio: stm32-dac: Add support for STM32 DAC
From: Fabrice Gasnier @ 2017-04-10 15:49 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, fabrice.gasnier,
	benjamin.gaignard
In-Reply-To: <1491839390-2449-1-git-send-email-fabrice.gasnier@st.com>

Document STMicroelectronics STM32 DAC (digital-to-analog converter).

Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
---
Changes in v2:
- use 'reg' instead of 'st,dac-channel' property
- remove alignment from description
---
 .../devicetree/bindings/iio/dac/st,stm32-dac.txt   | 61 ++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt

diff --git a/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
new file mode 100644
index 0000000..bcee71f
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
@@ -0,0 +1,61 @@
+STMicroelectronics STM32 DAC
+
+The STM32 DAC is a 12-bit voltage output digital-to-analog converter. The DAC
+may be configured in 8 or 12-bit mode. It has two output channels, each with
+its own converter.
+It has built-in noise and triangle waveform generator and supports external
+triggers for conversions. The DAC's output buffer allows a high drive output
+current.
+
+Contents of a stm32 dac root node:
+-----------------------------------
+Required properties:
+- compatible: Must be "st,stm32h7-dac-core".
+- reg: Offset and length of the device's register set.
+- clocks: Must contain an entry for pclk (which feeds the peripheral bus
+  interface)
+- clock-names: Must be "pclk".
+- vref-supply: Phandle to the vref+ input analog reference supply.
+- #address-cells = <1>;
+- #size-cells = <0>;
+
+Optional properties:
+- resets: Must contain the phandle to the reset controller.
+- A pinctrl state named "default" for each DAC channel may be defined to set
+  DAC_OUTx pin in mode of operation for analog output on external pin.
+
+Contents of a stm32 dac child node:
+-----------------------------------
+DAC core node should contain at least one subnode, representing a
+DAC instance/channel available on the machine.
+
+Required properties:
+- compatible: Must be "st,stm32-dac".
+- reg: Must be either 1 or 2, to define (single) channel in use
+- #io-channel-cells = <1>: See the IIO bindings section "IIO consumers" in
+  Documentation/devicetree/bindings/iio/iio-bindings.txt
+
+Example:
+	dac: dac@40007400 {
+		compatible = "st,stm32h7-dac-core";
+		reg = <0x40007400 0x400>;
+		clocks = <&clk>;
+		clock-names = "pclk";
+		vref-supply = <&reg_vref>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&dac_out1 &dac_out2>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		dac1: dac@1 {
+			compatible = "st,stm32-dac";
+			#io-channels-cells = <1>;
+			reg = <1>;
+		};
+
+		dac2: dac@2 {
+			compatible = "st,stm32-dac";
+			#io-channels-cells = <1>;
+			reg = <2>;
+		};
+	};
-- 
1.9.1

^ permalink raw reply related

* [PATCH v3 0/2] Add STM32H7 DAC driver
From: Fabrice Gasnier @ 2017-04-10 15:49 UTC (permalink / raw)
  To: jic23, linux, robh+dt, linux-arm-kernel, devicetree, linux-kernel
  Cc: mark.rutland, benjamin.gaignard, lars, alexandre.torgue,
	linux-iio, pmeerw, mcoquelin.stm32, knaack.h, fabrice.gasnier,
	benjamin.gaignard

This patchset adds support for the STM32H7 DAC controller

It's a 12-bit, voltage output digital-to-analog converter. It has two
output channels, each with its own converter, trigger sources and
waveform generator.

Each channel can be used independently, so common resources are managed
in stm32-dac-core driver (e.g. clock, reset, regulator, registers).
One IIO device is instantiated per DAC output channel, in stm32-dac
driver, so each channel can have its own trigger.

Examples, using this driver to generate DC voltage output on channel1:
# set max DC voltage / enable / min DC voltage / disable on out1
cd /sys/bus/iio/devices/iio\:device0
echo 4095 > out_voltage1_raw
echo 0 > out_voltage1_powerdown
echo 0 > out_voltage1_raw
echo 1 > out_voltage1_powerdown
cat out_voltage_powerdown_mode_available
three_state

---
Changes in v3:
- Fix powerdown mode, use 'three_state' as documented in sysfs-bus-iio
- For now, drop support for triggers & waveform generator that requires more work.
  This needs to be discussed more deeply.

Changes in v2:
- Update dt binding, use 'reg' property to select channel
- Use 'powerdown' attribute instead of 'enable'
- Added set_trigger callback
- Use 'offset' attribute in waveform generation mode to add DC offset
- rework ABI for waveform generation mode
- Various typos, comments

Fabrice Gasnier (2):
  dt-bindings: iio: stm32-dac: Add support for STM32 DAC
  iio: dac: add support for stm32 DAC

 .../devicetree/bindings/iio/dac/st,stm32-dac.txt   |  61 ++++
 drivers/iio/dac/Kconfig                            |  15 +
 drivers/iio/dac/Makefile                           |   2 +
 drivers/iio/dac/stm32-dac-core.c                   | 180 +++++++++++
 drivers/iio/dac/stm32-dac-core.h                   |  51 ++++
 drivers/iio/dac/stm32-dac.c                        | 334 +++++++++++++++++++++
 6 files changed, 643 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/dac/st,stm32-dac.txt
 create mode 100644 drivers/iio/dac/stm32-dac-core.c
 create mode 100644 drivers/iio/dac/stm32-dac-core.h
 create mode 100644 drivers/iio/dac/stm32-dac.c

-- 
1.9.1

^ permalink raw reply

* Re: [PATCH 2/2] devicetree: Document the max31760 device binding.
From: Rob Herring @ 2017-04-10 15:44 UTC (permalink / raw)
  To: John Muir
  Cc: Jean Delvare, Guenter Roeck, Jonathan Corbet, Pawel Moll,
	Ian Campbell, Kumar Gala, devicetree@vger.kernel.org, linux-hwmon,
	linux-doc@vger.kernel.org, Anatol Pomazau, Mark Segal
In-Reply-To: <20170410154249.r77b6vf3ctzn4kua@rob-hp-laptop>

On Mon, Apr 10, 2017 at 10:42 AM, Rob Herring <robh@kernel.org> wrote:
> On Tue, Apr 04, 2017 at 12:20:34PM -0700, John Muir wrote:
>> Signed-off-by: John Muir <john@jmuir.com>
>> ---
>>  .../devicetree/bindings/hwmon/max31760.txt         | 58 ++++++++++++++++++++++
>>  1 file changed, 58 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/hwmon/max31760.txt
>>
>> diff --git a/Documentation/devicetree/bindings/hwmon/max31760.txt b/Documentation/devicetree/bindings/hwmon/max31760.txt
>> new file mode 100644
>> index 000000000000..43787a77c322
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/hwmon/max31760.txt
>> @@ -0,0 +1,58 @@
>> +MAX31760 fan controller
>> +-----------------------
>> +
>> +This device supports I2C only. Many properties of this device are configurable
>> +thorugh the hwmon interface. See also Documentation/hwmon/max31760.
>
> I really think we need to describe the fans as separate nodes and
> preferably with a common binding. This is the second fan controller
> binding recently[1].

Forgot the link: https://patchwork.kernel.org/patch/9643643/

^ 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