Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Dmitry Torokhov @ 2016-12-08 18:12 UTC (permalink / raw)
  To: Rob Herring
  Cc: Benjamin Tissoires, Doug Anderson, Brian Norris, Jiri Kosina,
	Caesar Wang, open list:ARM/Rockchip SoC...,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Mark Rutland
In-Reply-To: <CAL_JsqKu0yhLVyEjcZs_rn=VqM9O4F_VMhOkfhEEvbYAjvWSTg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Thu, Dec 08, 2016 at 10:26:41AM -0600, Rob Herring wrote:
> On Thu, Dec 8, 2016 at 10:13 AM, Dmitry Torokhov
> <dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> > On December 8, 2016 8:03:06 AM PST, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> >>On Thu, Dec 8, 2016 at 9:41 AM, Benjamin Tissoires
> >><benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> >>> On Dec 06 2016 or thereabouts, Doug Anderson wrote:
> >>>> Hi,
> >>>>
> >>>> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> >>>> > On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
> >>>> > <benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> >>>> >> On Dec 05 2016 or thereabouts, Rob Herring wrote:
> >>>> >>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
> >>>> >>> > Hi Benjamin and Rob,
> >>>> >>> >
> >>>> >>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires
> >>wrote:
> >>>> >>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
> >>>> >>> > > > From: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> >>>> >>> > > >
> >>>> >>> > > > Add a compatible string and regulator property for Wacom
> >>W9103
> >>>> >>> > > > digitizer. Its VDD supply may need to be enabled before
> >>using it.
> >>>> >>> > > >
> >>>> >>> > > > Signed-off-by: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> >>>> >>> > > > Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>>> >>> > > > Cc: Jiri Kosina <jikos-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>>> >>> > > > Cc: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >>>> >>> > > > Signed-off-by: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> >>>> >>> > > > ---
> >>>> >>> > > > v1 was a few months back. I finally got around to
> >>rewriting it based on
> >>>> >>> > > > DT binding feedback.
> >>>> >>> > > >
> >>>> >>> > > > v2:
> >>>> >>> > > >  * add compatible property for wacom
> >>>> >>> > > >  * name the regulator property specifically (VDD)
> >>>> >>> > > >
> >>>> >>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>| 6 +++++-
> >>>> >>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
> >>>> >>> > > >
> >>>> >>> > > > diff --git
> >>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>>> >>> > > > index 488edcb264c4..eb98054e60c9 100644
> >>>> >>> > > > ---
> >>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>>> >>> > > > +++
> >>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>>> >>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel
> >>module i2c-hid will handle the communication
> >>>> >>> > > >  with the device and the generic hid core layer will
> >>handle the protocol.
> >>>> >>> > > >
> >>>> >>> > > >  Required properties:
> >>>> >>> > > > -- compatible: must be "hid-over-i2c"
> >>>> >>> > > > +- compatible: must be "hid-over-i2c", or a
> >>device-specific string like:
> >>>> >>> > > > +    * "wacom,w9013"
> >>>> >>> > >
> >>>> >>> > > NACK on this one.
> >>>> >>> > >
> >>>> >>> > > After re-reading the v1 submission I realized Rob asked for
> >>this change,
> >>>> >>> > > but I strongly disagree.
> >>>> >>> > >
> >>>> >>> > > HID over I2C is a generic protocol, in the same way HID over
> >>USB is. We
> >>>> >>> > > can not start adding device specifics here, this is opening
> >>the can of
> >>>> >>> > > worms. If the device is a HID one, nothing else should
> >>matter. The rest
> >>>> >>> > > (description of the device, name, etc...) is all provided by
> >>the
> >>>> >>> > > protocol.
> >>>> >>> >
> >>>> >>> > I should have spoken up when Rob made the suggestion, because
> >>I more or
> >>>> >>> > less agree with Benjamin here. I don't really see why this
> >>needs to have
> >>>> >>> > a specialized compatible string, as the property is still
> >>fairly
> >>>> >>> > generic, and the entire device handling is via a generic
> >>protocol. The
> >>>> >>> > fact that we manage its power via a regulator is not very
> >>>> >>> > device-specific.
> >>>> >>>
> >>>> >>> It doesn't matter that the protocol is generic. The device
> >>attached and
> >>>> >>> the implementation is not. Implementations have been known to
> >>have
> >>>> >>> bugs/quirks (generally speaking, not HID over I2C in
> >>particular). There
> >>>> >>> are also things outside the scope of what is 'hid-over-i2c' like
> >>what's
> >>>> >>> needed to power-on the device which this patch clearly show.
> >>>> >>
> >>>> >> Yes, there are bugs, quirks, even with HID. But the HID declares
> >>within
> >>>> >> the protocol the Vendor ID and the Product ID, which means once
> >>we pass
> >>>> >> the initial "device is ready" step and can do a single i2c
> >>write/read,
> >>>> >> we don't give a crap about device tree anymore.
> >>>> >>
> >>>> >> This is just about setting the device in shape so that it can
> >>answer a
> >>>> >> single write/read.
> >>>> >>
> >>>> >>>
> >>>> >>> This is no different than a panel attached via LVDS, eDP, etc.,
> >>or
> >>>> >>> USB/PCIe device hard-wired on a board. They all use standard
> >>protocols
> >>>> >>> and all need additional data to describe them. Of course, adding
> >>a
> >>>> >>> single property for a delay would not be a big deal, but it's
> >>never
> >>>> >>> ending. Next you need multiple supplies, GPIO controls, mutiple
> >>>> >>> delays... This has been discussed to death already. As Thierry
> >>Reding
> >>>> >>> said, you're not special[1].
> >>>> >>
> >>>> >> I can somewhat understand what you mean. The official
> >>specification is
> >>>> >> for ACPI. And ACPI allows to calls various settings while
> >>querying the
> >>>> >> _STA method for instance. So in the ACPI world, we don't need to
> >>care
> >>>> >> about regulators or GPIOs because the OEM deals with this in its
> >>own
> >>>> >> blob.
> >>>> >>
> >>>> >> Now, coming back to our issue. We are not special, maybe, if he
> >>says so.
> >>>> >> But this really feels like a design choice between putting the
> >>burden on
> >>>> >> device tree and OEMs or in the module maintainers. And I'd rather
> >>have
> >>>> >> the OEM deal with their device than me having to update the
> >>module for
> >>>> >> each generations of hardware. Indeed, this looks like an
> >>"endless"
> >>>> >> amount of quirks, but I'd rather have this endless amount of
> >>quirks than
> >>>> >> having to maintain an endless amount of list of new devices that
> >>behaves
> >>>> >> the same way. We are talking here about "wacom,w9013", but then
> >>comes
> >>>> >> "wacom,w9014" and we need to upgrade the kernel.
> >>>> >
> >>>> > No. If the w9014 can claim compatibility with then w9013, then you
> >>>> > don't need a kernel change. The DT should list the w9014 AND
> >>w9013,
> >>>> > but the kernel only needs to know about the w9013. That is until
> >>there
> >>>> > is some difference which is why the DT should list w9014 to start
> >>>> > with.
> >>>> >
> >>>> > If you don't have any power control to deal with, then the kernel
> >>can
> >>>> > always just match on "hid-over-i2c" compatible.
> >>>>
> >>>> Just my $0.02.  Feel free to ignore.
> >>>>
> >>>> One thought is that I would say that the need to power on the device
> >>>> explicitly seems more like a board level difference and less like a
> >>>> difference associated with a particular digitizer.  Said another
> >>way,
> >>>> it seems likely there will be boards with a w9013 without explicit
> >>>> control of the regulator in software and it seems like there will be
> >>>> boards with other digitizers where suddenly a new board will come
> >>out
> >>>> that needs explicit control of the regulator.
> >>>>
> >>>> In this particular case I feel like we can draw a lot of parallels
> >>to
> >>>> an SDIO bus.
> >>>>
> >>>> When you specify an SDIO bus you don't specify what kind of card
> >>will
> >>>> be present, you just say "I've got an SDIO bus" and then the
> >>specific
> >>>> device underneath is probed.  Here we've say "I've got an i2c
> >>>> connection intended for HID" and then you probe for the HID device
> >>>> that's on the connection.
> >>>>
> >>>> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
> >>>> resets that need to be controlled, but the specific details of these
> >>>> regulator / GPIOs / resets are specific to a given board and not
> >>>> necessarily a given SDIO device.
> >>>>
> >>>
> >>> Thanks Doug for this. I had the feeling this wasn't right, but you
> >>> actually managed to put the words on it. If it's a board problem (if
> >>> you switch the wacom device with an other HID over I2C device and you
> >>> still need the same regulator/timing parameters), then this should
> >>> simply be mentioned on the patch.
> >>>
> >>> So Brian, could you please respin the series and remve the Wacom
> >>> mentions and explain that it is required for the board itself?
> >>
> >>In advance, NAK.
> >>
> >>This is not how DT works. Either this binding needs a Wacom compatible
> >>or don't use DT.
> >>
> >
> > And if tomorrow there is Elan device that is drop-in compatible
> > (same connector, etc) with Wacom i2c-hid, will you ask for
> > Elan-specific binding? Atmel? Weida? They all need to be powered up
> > ultimately.
> 
> Yes, I will. Anyone who's worked on drop-in or pin compatible parts
> knows there's no such thing.

And yet we are shipping quite a few of Chromebooks with touchpads that
are dual-sourced and can be exchanged at any time without any changes to
the software (be it kernel or firmware).

> 
> That in no way means the OS driver has to know about each and every
> one. If they can all claim compatibility with Wacom (including power
> control), then they can have a Wacom compatible string too. Or you can
> just never tell me that there's a different manufacturer and I won't
> care as long you don't need different control. But soon as a device
> needs another power rail, GPIO or different timing, then you'd better
> have a new compatible string.

That I simply do not understand. We routinely enhance bindings because
the devices get used on different boards that expose more or less
connections. I.e. quite often we start with a device whose rails are
controlled by the firmware, and so the binding only contains register
and interrupt data. Then we come across board that exposes reset GPIO
and we add that to the binding (bit we do not invent new compatible
string just because there is GPIO now). Then we get a board that
actually wants kernel to control power to the chip and we add a
regulator. Non-optional, mind you, because we rely on the regulator
system to give us a dummy one if it is not described by the
firmware/other means. And then we get another board that exposes another
power rail (let's say 3.3V to the panel whereas the previous one did not
use it). And we add another regulator binding. All this time we have
the same compatibility string.

So in this case we finally got to the point where we admit that devices
speaking HID over I2C do have power rails; we simply did not need to
control them before. The same Wacom digitizer, that you now demand to
add a compatible for, may have been used in other boards where power
rails were either turned on by the firmware at boot time and left on
until the board is shutdown, or ACPI was controlling them (via _ON/_OFF
methods), or there was some other magic. Having a supply and ability to
control the time it takes to bring the device into operating state is in
no way Wacom-specific, so why new compatibility instead of enhancing
the current binding?

And on top of that, currently multiple compatible strings are utterly
broken with regard to module loading (you only emit modalias for the
first component), so having DTS with multiples does not work well in
real life.

-- 
Dmitry
--
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/6] net: stmmac: make DMA programmable burst length more configurable
From: David Miller @ 2016-12-08 18:07 UTC (permalink / raw)
  To: niklas.cassel; +Cc: netdev, niklass, devicetree, linux-kernel, linux-doc
In-Reply-To: <1481120409-18103-1-git-send-email-niklass@axis.com>

From: Niklas Cassel <niklas.cassel@axis.com>
Date: Wed, 7 Dec 2016 15:20:02 +0100

> Make DMA programmable burst length more configurable in the stmmac driver.
> 
> This is done by adding support for independent pbl for tx/rx through DT.
> More fine grained tuning of pbl is possible thanks to a DT property saying
> that we should NOT multiply pbl values by x8/x4 in hardware.
> 
> All new DT properties are optional, and created in a way that it will not
> affect any existing DT configurations.

Series applied to net-next, thanks.

^ permalink raw reply

* Re: [PATCH v2 4/5] arm64: dts: exynos5433: Add bus dt node using VDD_INT for Exynos5433
From: Krzysztof Kozlowski @ 2016-12-08 17:52 UTC (permalink / raw)
  To: Chanwoo Choi
  Cc: krzk, javier, kgene, robh+dt, s.nawrocki, tomasz.figa,
	myungjoo.ham, kyungmin.park, devicetree, linux-samsung-soc,
	linux-arm-kernel, linux-kernel
In-Reply-To: <1481173091-9728-5-git-send-email-cw00.choi@samsung.com>

On Thu, Dec 08, 2016 at 01:58:10PM +0900, Chanwoo Choi wrote:
> This patch adds the bus nodes using VDD_INT for Exynos5433 SoC.
> Exynos5433 has the following AMBA AXI buses to translate data
> between DRAM and sub-blocks.
> 
> Following list specify the detailed correlation between sub-block and clock:
> - CLK_ACLK_G2D_{400|266}  : Bus clock for G2D (2D graphic engine)
> - CLK_ACLK_MSCL_400       : Bus clock for MSCL (Memory to memory Scaler)
> - CLK_ACLK_GSCL_333       : Bus clock for GSCL (General Scaler)
> - CLK_SCLK_JPEG_MSCL      : Bus clock for JPEG
> - CLK_ACLK_MFC_400        : Bus clock for MFC (Multi Format Codec)
> - CLK_ACLK_HEVC_400       : Bus clock for HEVC (High Efficient Video Codec)
> - CLK_ACLK_BUS0_400       : NoC(Network On Chip)'s bus clock for PERIC/PERIS/FSYS/MSCL
> - CLK_ACLK_BUS1_400       : NoC's bus clock for MFC/HEVC/G3D
> - CLK_ACLK_BUS2_400       : NoC's bus clock for GSCL/DISP/G2D/CAM0/CAM1/ISP
> 
> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
> ---
>  arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi | 197 +++++++++++++++++++++++++
>  arch/arm64/boot/dts/exynos/exynos5433.dtsi     |   1 +
>  2 files changed, 198 insertions(+)
>  create mode 100644 arch/arm64/boot/dts/exynos/exynos5433-bus.dtsi

For the reference:
Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>

I'll queue it for v4.11, after this merge window.

Best regards,
Krzysztof

^ permalink raw reply

* [PATCH] misc: eeprom: implement compatible DT probing
From: Linus Walleij @ 2016-12-08 17:47 UTC (permalink / raw)
  To: Wolfram Sang
  Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA, Linus Walleij,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The compatible string for an EEPROM in the device tree is currently
completely ignored by the kernel, simply stated it will not make the
corresponding AT24 EEPROM driver probe properly. It is instead still
relying on the DT node name to be set to one of the I2C device IDs
which works due to a side effect in the I2C DT parsing code.

Fix this up by making the DT probe mechanism a bit more elaborate:
actually match on the compatible strings defined in the device
tree bindings in Documentation/devicetree/bindings/eeprom/eeprom.txt:
map these to the corresponding I2C IDs by name and look up the
magic flags from the I2C ID before proceeding, also make the DT
compatible string take precedence.

Keep the second DT parsing callback that sets up per-chip flags as
this needs to happen after mangling the magic flags passed from the
I2C ID table.

All vendor compatible strings listed in the binding document are
added to the driver.

After this it is possible to name the device tree node for the EEPROM
whatever you actually like to call it, and the probing will be done
from the compatible string.

Before this patch, the following device tree node does not probe,
which might be considered a bug:

eeprom@52 {
	compatible = "atmel,at24c128";
	reg = <0x52>;
	pagesize = <64>;
};

After this patch, the driver probes fine from this node.

As checkpatch is complaining about the vendor "catalyst" not
existing in the vendor prefixes, despite being mentioned in the
EEPROM DT binding document, we add this as part of this patch so
that checkpatch is happy.

Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/vendor-prefixes.txt        |  1 +
 drivers/misc/eeprom/at24.c                         | 82 ++++++++++++++++++----
 2 files changed, 68 insertions(+), 15 deletions(-)

diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index f0a48ea78659..40bdf9aa590c 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -47,6 +47,7 @@ brcm	Broadcom Corporation
 buffalo	Buffalo, Inc.
 calxeda	Calxeda
 capella	Capella Microsystems, Inc
+catalyst	Catalyst Semiconductor Inc.
 cavium	Cavium, Inc.
 cdns	Cadence Design Systems Inc.
 ceva	Ceva, Inc.
diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
index 051b14766ef9..246b15539d45 100644
--- a/drivers/misc/eeprom/at24.c
+++ b/drivers/misc/eeprom/at24.c
@@ -20,6 +20,7 @@
 #include <linux/bitops.h>
 #include <linux/jiffies.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/acpi.h>
 #include <linux/i2c.h>
 #include <linux/nvmem-provider.h>
@@ -563,23 +564,70 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
 }
 
 #ifdef CONFIG_OF
-static void at24_get_ofdata(struct i2c_client *client,
-			    struct at24_platform_data *chip)
+static void at24_get_of_magic(struct device *dev,
+			      kernel_ulong_t *magic)
 {
-	const __be32 *val;
-	struct device_node *node = client->dev.of_node;
-
-	if (node) {
-		if (of_get_property(node, "read-only", NULL))
-			chip->flags |= AT24_FLAG_READONLY;
-		val = of_get_property(node, "pagesize", NULL);
-		if (val)
-			chip->page_size = be32_to_cpup(val);
+	const char *name;
+	const struct i2c_device_id *id;
+	int i;
+
+	name = of_device_get_match_data(dev);
+	if (!name)
+		return;
+
+	for (i = 0; i < ARRAY_SIZE(at24_ids); i++) {
+		id = &at24_ids[i];
+		if (!strcmp(id->name, name)) {
+			*magic = id->driver_data;
+			break;
+		}
 	}
+	if (i == ARRAY_SIZE(at24_ids))
+		return;
+
+	dev_dbg(dev, "DT match for %s -> %s\n", name, id->name);
+}
+
+static void at24_get_of_chipdata(struct device_node *np,
+				 struct at24_platform_data *chip)
+{
+	u32 val;
+	int ret;
+
+	if (of_property_read_bool(np, "read-only"))
+		chip->flags |= AT24_FLAG_READONLY;
+
+	ret = of_property_read_u32(np, "pagesize", &val);
+	if (!ret)
+		chip->page_size = val;
 }
+
+static const struct of_device_id at24_of_match[] = {
+	{ .compatible = "atmel,at24c00", .data = "24c00" },
+	{ .compatible = "atmel,at24c01", .data = "24c01" },
+	{ .compatible = "atmel,at24c02", .data = "24c02" },
+	{ .compatible = "atmel,at24c04", .data = "24c04" },
+	{ .compatible = "atmel,at24c08", .data = "24c08" },
+	{ .compatible = "atmel,at24c16", .data = "24c16" },
+	{ .compatible = "atmel,at24c32", .data = "24c32" },
+	{ .compatible = "atmel,at24c64", .data = "24c64" },
+	{ .compatible = "atmel,at24c128", .data = "24c128" },
+	{ .compatible = "atmel,at24c256", .data = "24c256" },
+	{ .compatible = "atmel,at24c512", .data = "24c512" },
+	{ .compatible = "atmel,at24c1024", .data = "24c1024" },
+	{ .compatible = "catalyst,24c32", .data = "24c32" },
+	{ .compatible = "ramtron,24c64", .data = "24c64" },
+	{ .compatible = "renesas,r1ex24002", .data = "24c02" },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, at24_of_match);
+
 #else
-static void at24_get_ofdata(struct i2c_client *client,
-			    struct at24_platform_data *chip)
+static void at24_get_of_magic(struct device *dev,
+			      kernel_ulong_t *magic)
+{ }
+static void at24_get_of_chipdata(struct device_node *np,
+				 struct at24_platform_data *chip)
 { }
 #endif /* CONFIG_OF */
 
@@ -598,7 +646,10 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	if (client->dev.platform_data) {
 		chip = *(struct at24_platform_data *)client->dev.platform_data;
 	} else {
-		if (id) {
+		if (client->dev.of_node) {
+			/* Get chipdata if OF is present */
+			at24_get_of_magic(&client->dev, &magic);
+		} else if (id) {
 			magic = id->driver_data;
 		} else {
 			const struct acpi_device_id *aid;
@@ -621,7 +672,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		chip.page_size = 1;
 
 		/* update chipdata if OF is present */
-		at24_get_ofdata(client, &chip);
+		at24_get_of_chipdata(client->dev.of_node, &chip);
 
 		chip.setup = NULL;
 		chip.context = NULL;
@@ -822,6 +873,7 @@ static struct i2c_driver at24_driver = {
 	.driver = {
 		.name = "at24",
 		.acpi_match_table = ACPI_PTR(at24_acpi_ids),
+		.of_match_table = of_match_ptr(at24_of_match),
 	},
 	.probe = at24_probe,
 	.remove = at24_remove,
-- 
2.7.4

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

^ permalink raw reply related

* Re: [RESEND-PATCH] ARM: EXYNOS: remove smp hook from machine descriptor
From: Krzysztof Kozlowski @ 2016-12-08 17:33 UTC (permalink / raw)
  To: Pankaj Dubey
  Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	devicetree-u79uwXL29TY76Z2rM5mHXA, arnd-r2nGTMty4D4,
	krzk-DgEjT+Ai2ygdnm+yROfE0A, kgene-DgEjT+Ai2ygdnm+yROfE0A,
	javier-JPH+aEBZ4P+UEJcrhfAQsw, thomas.ab-Sze3O3UU22JBDgjK7y7TUQ
In-Reply-To: <1481166135-1588-1-git-send-email-pankaj.dubey-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>

On Thu, Dec 08, 2016 at 08:32:15AM +0530, Pankaj Dubey wrote:
> Use CPU_METHOD_OF_DECLARE() for smp_ops instead of using it
> via machine descriptor.
> 
> Signed-off-by: Pankaj Dubey <pankaj.dubey-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>
> ---
> 
> Resending as I missed to include samsung mailing list.
> 
>  arch/arm/boot/dts/exynos3250.dtsi      | 1 +
>  arch/arm/boot/dts/exynos4210.dtsi      | 1 +
>  arch/arm/boot/dts/exynos4212.dtsi      | 1 +
>  arch/arm/boot/dts/exynos4412.dtsi      | 1 +
>  arch/arm/boot/dts/exynos5250.dtsi      | 1 +
>  arch/arm/boot/dts/exynos5260.dtsi      | 1 +
>  arch/arm/boot/dts/exynos5410.dtsi      | 1 +
>  arch/arm/boot/dts/exynos5420-cpus.dtsi | 1 +
>  arch/arm/boot/dts/exynos5422-cpus.dtsi | 1 +
>  arch/arm/boot/dts/exynos5440.dtsi      | 1 +
>  arch/arm/mach-exynos/common.h          | 2 --
>  arch/arm/mach-exynos/exynos.c          | 1 -
>  arch/arm/mach-exynos/platsmp.c         | 2 ++
>  13 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
> index ba17ee1..f28f669 100644
> --- a/arch/arm/boot/dts/exynos3250.dtsi
> +++ b/arch/arm/boot/dts/exynos3250.dtsi
> @@ -53,6 +53,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
> index 7f3a18c..6dfd98d 100644
> --- a/arch/arm/boot/dts/exynos4210.dtsi
> +++ b/arch/arm/boot/dts/exynos4210.dtsi
> @@ -35,6 +35,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@900 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
> index 5389011..3e8982e 100644
> --- a/arch/arm/boot/dts/exynos4212.dtsi
> +++ b/arch/arm/boot/dts/exynos4212.dtsi
> @@ -25,6 +25,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@A00 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
> index 40beede..faf2fb8 100644
> --- a/arch/arm/boot/dts/exynos4412.dtsi
> +++ b/arch/arm/boot/dts/exynos4412.dtsi
> @@ -25,6 +25,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@A00 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
> index b6d7444..580897c 100644
> --- a/arch/arm/boot/dts/exynos5250.dtsi
> +++ b/arch/arm/boot/dts/exynos5250.dtsi
> @@ -52,6 +52,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5260.dtsi b/arch/arm/boot/dts/exynos5260.dtsi
> index 5818718..1af6e76 100644
> --- a/arch/arm/boot/dts/exynos5260.dtsi
> +++ b/arch/arm/boot/dts/exynos5260.dtsi
> @@ -32,6 +32,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5410.dtsi b/arch/arm/boot/dts/exynos5410.dtsi
> index 2b6adaf..b092cdc 100644
> --- a/arch/arm/boot/dts/exynos5410.dtsi
> +++ b/arch/arm/boot/dts/exynos5410.dtsi
> @@ -33,6 +33,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5420-cpus.dtsi b/arch/arm/boot/dts/exynos5420-cpus.dtsi
> index 5c052d7..a587704 100644
> --- a/arch/arm/boot/dts/exynos5420-cpus.dtsi
> +++ b/arch/arm/boot/dts/exynos5420-cpus.dtsi
> @@ -24,6 +24,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5422-cpus.dtsi b/arch/arm/boot/dts/exynos5422-cpus.dtsi
> index bf3c6f1..7fcdfd0 100644
> --- a/arch/arm/boot/dts/exynos5422-cpus.dtsi
> +++ b/arch/arm/boot/dts/exynos5422-cpus.dtsi
> @@ -23,6 +23,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu0: cpu@100 {
>  			device_type = "cpu";
> diff --git a/arch/arm/boot/dts/exynos5440.dtsi b/arch/arm/boot/dts/exynos5440.dtsi
> index 2a2e570..0a958e8 100644
> --- a/arch/arm/boot/dts/exynos5440.dtsi
> +++ b/arch/arm/boot/dts/exynos5440.dtsi
> @@ -50,6 +50,7 @@
>  	cpus {
>  		#address-cells = <1>;
>  		#size-cells = <0>;
> +		enable-method = "samsung,exynos-smp";
>  
>  		cpu@0 {
>  			device_type = "cpu";
> diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
> index fb12d11..051e1ab 100644
> --- a/arch/arm/mach-exynos/common.h
> +++ b/arch/arm/mach-exynos/common.h
> @@ -143,8 +143,6 @@ static inline void exynos_pm_init(void) {}
>  extern void exynos_cpu_resume(void);
>  extern void exynos_cpu_resume_ns(void);
>  
> -extern const struct smp_operations exynos_smp_ops;
> -
>  extern void exynos_cpu_power_down(int cpu);
>  extern void exynos_cpu_power_up(int cpu);
>  extern int  exynos_cpu_power_state(int cpu);
> diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
> index fa08ef9..f0a766e 100644
> --- a/arch/arm/mach-exynos/exynos.c
> +++ b/arch/arm/mach-exynos/exynos.c
> @@ -211,7 +211,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
>  	/* Maintainer: Kukjin Kim <kgene.kim-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org> */
>  	.l2c_aux_val	= 0x3c400001,
>  	.l2c_aux_mask	= 0xc20fffff,
> -	.smp		= smp_ops(exynos_smp_ops),
>  	.map_io		= exynos_init_io,
>  	.init_early	= exynos_firmware_init,
>  	.init_irq	= exynos_init_irq,
> diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
> index 94405c7..43eec10 100644
> --- a/arch/arm/mach-exynos/platsmp.c
> +++ b/arch/arm/mach-exynos/platsmp.c
> @@ -474,3 +474,5 @@ const struct smp_operations exynos_smp_ops __initconst = {
>  	.cpu_die		= exynos_cpu_die,
>  #endif
>  };
> +
> +CPU_METHOD_OF_DECLARE(exynos_smp, "samsung,exynos-smp", &exynos_smp_ops);

Three issues:
1. This has to be documented. Checkpatch did not complain about it?
2. I think this breaks the ABI with existing DTBs because now the
   enable-method of cpus becomes mandatory. But the
   Documentation/devicetree/bindings/arm/cpus.txt is saying that:
   "On ARM 32-bit systems this property is optional and can be one of"

3. Please split DTS changes to separate patches. This is, by the way,
   connected with #2 above: if there was no ABI break, then the DTS
   could go to separate branch easily.

Best regards,
Krzysztof
--
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

* Applied "spi: armada-3700: Add documentation for the Armada 3700 SPI Controller" to the spi tree
From: Mark Brown @ 2016-12-08 16:55 UTC (permalink / raw)
  To: Romain Perier; +Cc: Gregory CLEMENT, Rob Herring, Mark Brown
In-Reply-To: <20161129143939.3191-4-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The patch

   spi: armada-3700: Add documentation for the Armada 3700 SPI Controller

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 4049537742b3ed39fac4da10d31f3171a2ee9a3e Mon Sep 17 00:00:00 2001
From: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Date: Thu, 8 Dec 2016 15:58:45 +0100
Subject: [PATCH] spi: armada-3700: Add documentation for the Armada 3700 SPI
 Controller

This adds the devicetree bindings documentation for the SPI controller
present in the Marvell Armada 3700 SoCs.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 .../devicetree/bindings/spi/spi-armada-3700.txt    | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-armada-3700.txt

diff --git a/Documentation/devicetree/bindings/spi/spi-armada-3700.txt b/Documentation/devicetree/bindings/spi/spi-armada-3700.txt
new file mode 100644
index 000000000000..1564aa8c02cd
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-armada-3700.txt
@@ -0,0 +1,25 @@
+* Marvell Armada 3700 SPI Controller
+
+Required Properties:
+
+- compatible: should be "marvell,armada-3700-spi"
+- reg: physical base address of the controller and length of memory mapped
+       region.
+- interrupts: The interrupt number. The interrupt specifier format depends on
+	      the interrupt controller and of its driver.
+- clocks: Must contain the clock source, usually from the North Bridge clocks.
+- num-cs: The number of chip selects that is supported by this SPI Controller
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+
+Example:
+
+	spi0: spi@10600 {
+		compatible = "marvell,armada-3700-spi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x10600 0x5d>;
+		clocks = <&nb_perih_clk 7>;
+		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+		num-cs = <4>;
+	};
-- 
2.10.2

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

^ permalink raw reply related

* Applied "spi: Add support for Armada 3700 SPI Controller" to the spi tree
From: Mark Brown @ 2016-12-08 16:55 UTC (permalink / raw)
  To: Romain Perier; +Cc: Gregory CLEMENT, Mark Brown
In-Reply-To: <20161208145847.7794-2-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

The patch

   spi: Add support for Armada 3700 SPI Controller

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5762ab71eb24a8393a167361510d7ca5e18c99f9 Mon Sep 17 00:00:00 2001
From: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Date: Thu, 8 Dec 2016 15:58:44 +0100
Subject: [PATCH] spi: Add support for Armada 3700 SPI Controller

Marvell Armada 3700 SoC comprises an SPI Controller. This Controller
supports up to 4 SPI slave devices, with dedicated chip selects,supports
SPI mode 0/1/2 and 3, CPIO or Fifo mode with DMA transfers and different
SPI transfer mode (Single, Dual or Quad).

This commit adds basic driver support for FIFO mode. In this mode,
dedicated registers are used to store the instruction, the address, the
read mode and the data. Write and Read FIFO are used to store the
outcoming or incoming data. The data FIFOs are accessible via DMA or by
the CPU. Only the CPU is supported for now.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Signed-off-by: Mark Brown <broonie-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---
 drivers/spi/Kconfig           |   7 +
 drivers/spi/Makefile          |   1 +
 drivers/spi/spi-armada-3700.c | 923 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 931 insertions(+)
 create mode 100644 drivers/spi/spi-armada-3700.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b7995474148c..1faad2ce4b4b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -67,6 +67,13 @@ config SPI_ATH79
 	  This enables support for the SPI controller present on the
 	  Atheros AR71XX/AR724X/AR913X SoCs.
 
+config SPI_ARMADA_3700
+	tristate "Marvell Armada 3700 SPI Controller"
+	depends on (ARCH_MVEBU && OF) || COMPILE_TEST
+	help
+	  This enables support for the SPI controller present on the
+	  Marvell Armada 3700 SoCs.
+
 config SPI_ATMEL
 	tristate "Atmel SPI Controller"
 	depends on HAS_DMA
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index aa939d955521..140ca45aa9d2 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST)		+= spi-loopback-test.o
 
 # SPI master controller drivers (bus)
 obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o
+obj-$(CONFIG_SPI_ARMADA_3700)		+= spi-armada-3700.o
 obj-$(CONFIG_SPI_ATMEL)			+= spi-atmel.o
 obj-$(CONFIG_SPI_ATH79)			+= spi-ath79.o
 obj-$(CONFIG_SPI_AU1550)		+= spi-au1550.o
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
new file mode 100644
index 000000000000..e89da0af45d2
--- /dev/null
+++ b/drivers/spi/spi-armada-3700.c
@@ -0,0 +1,923 @@
+/*
+ * Marvell Armada-3700 SPI controller driver
+ *
+ * Copyright (C) 2016 Marvell Ltd.
+ *
+ * Author: Wilson Ding <dingwei-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
+ * Author: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME			"armada_3700_spi"
+
+#define A3700_SPI_TIMEOUT		10
+
+/* SPI Register Offest */
+#define A3700_SPI_IF_CTRL_REG		0x00
+#define A3700_SPI_IF_CFG_REG		0x04
+#define A3700_SPI_DATA_OUT_REG		0x08
+#define A3700_SPI_DATA_IN_REG		0x0C
+#define A3700_SPI_IF_INST_REG		0x10
+#define A3700_SPI_IF_ADDR_REG		0x14
+#define A3700_SPI_IF_RMODE_REG		0x18
+#define A3700_SPI_IF_HDR_CNT_REG	0x1C
+#define A3700_SPI_IF_DIN_CNT_REG	0x20
+#define A3700_SPI_IF_TIME_REG		0x24
+#define A3700_SPI_INT_STAT_REG		0x28
+#define A3700_SPI_INT_MASK_REG		0x2C
+
+/* A3700_SPI_IF_CTRL_REG */
+#define A3700_SPI_EN			BIT(16)
+#define A3700_SPI_ADDR_NOT_CONFIG	BIT(12)
+#define A3700_SPI_WFIFO_OVERFLOW	BIT(11)
+#define A3700_SPI_WFIFO_UNDERFLOW	BIT(10)
+#define A3700_SPI_RFIFO_OVERFLOW	BIT(9)
+#define A3700_SPI_RFIFO_UNDERFLOW	BIT(8)
+#define A3700_SPI_WFIFO_FULL		BIT(7)
+#define A3700_SPI_WFIFO_EMPTY		BIT(6)
+#define A3700_SPI_RFIFO_FULL		BIT(5)
+#define A3700_SPI_RFIFO_EMPTY		BIT(4)
+#define A3700_SPI_WFIFO_RDY		BIT(3)
+#define A3700_SPI_RFIFO_RDY		BIT(2)
+#define A3700_SPI_XFER_RDY		BIT(1)
+#define A3700_SPI_XFER_DONE		BIT(0)
+
+/* A3700_SPI_IF_CFG_REG */
+#define A3700_SPI_WFIFO_THRS		BIT(28)
+#define A3700_SPI_RFIFO_THRS		BIT(24)
+#define A3700_SPI_AUTO_CS		BIT(20)
+#define A3700_SPI_DMA_RD_EN		BIT(18)
+#define A3700_SPI_FIFO_MODE		BIT(17)
+#define A3700_SPI_SRST			BIT(16)
+#define A3700_SPI_XFER_START		BIT(15)
+#define A3700_SPI_XFER_STOP		BIT(14)
+#define A3700_SPI_INST_PIN		BIT(13)
+#define A3700_SPI_ADDR_PIN		BIT(12)
+#define A3700_SPI_DATA_PIN1		BIT(11)
+#define A3700_SPI_DATA_PIN0		BIT(10)
+#define A3700_SPI_FIFO_FLUSH		BIT(9)
+#define A3700_SPI_RW_EN			BIT(8)
+#define A3700_SPI_CLK_POL		BIT(7)
+#define A3700_SPI_CLK_PHA		BIT(6)
+#define A3700_SPI_BYTE_LEN		BIT(5)
+#define A3700_SPI_CLK_PRESCALE		BIT(0)
+#define A3700_SPI_CLK_PRESCALE_MASK	(0x1f)
+
+#define A3700_SPI_WFIFO_THRS_BIT	28
+#define A3700_SPI_RFIFO_THRS_BIT	24
+#define A3700_SPI_FIFO_THRS_MASK	0x7
+
+#define A3700_SPI_DATA_PIN_MASK		0x3
+
+/* A3700_SPI_IF_HDR_CNT_REG */
+#define A3700_SPI_DUMMY_CNT_BIT		12
+#define A3700_SPI_DUMMY_CNT_MASK	0x7
+#define A3700_SPI_RMODE_CNT_BIT		8
+#define A3700_SPI_RMODE_CNT_MASK	0x3
+#define A3700_SPI_ADDR_CNT_BIT		4
+#define A3700_SPI_ADDR_CNT_MASK		0x7
+#define A3700_SPI_INSTR_CNT_BIT		0
+#define A3700_SPI_INSTR_CNT_MASK	0x3
+
+/* A3700_SPI_IF_TIME_REG */
+#define A3700_SPI_CLK_CAPT_EDGE		BIT(7)
+
+/* Flags and macros for struct a3700_spi */
+#define A3700_INSTR_CNT			1
+#define A3700_ADDR_CNT			3
+#define A3700_DUMMY_CNT			1
+
+struct a3700_spi {
+	struct spi_master *master;
+	void __iomem *base;
+	struct clk *clk;
+	unsigned int irq;
+	unsigned int flags;
+	bool xmit_data;
+	const u8 *tx_buf;
+	u8 *rx_buf;
+	size_t buf_len;
+	u8 byte_len;
+	u32 wait_mask;
+	struct completion done;
+	u32 addr_cnt;
+	u32 instr_cnt;
+	size_t hdr_cnt;
+};
+
+static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset)
+{
+	return readl(a3700_spi->base + offset);
+}
+
+static void spireg_write(struct a3700_spi *a3700_spi, u32 offset, u32 data)
+{
+	writel(data, a3700_spi->base + offset);
+}
+
+static void a3700_spi_auto_cs_unset(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~A3700_SPI_AUTO_CS;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_activate_cs(struct a3700_spi *a3700_spi, unsigned int cs)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	val |= (A3700_SPI_EN << cs);
+	spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val);
+}
+
+static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi,
+				    unsigned int cs)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	val &= ~(A3700_SPI_EN << cs);
+	spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val);
+}
+
+static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
+				  unsigned int pin_mode)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_INST_PIN | A3700_SPI_ADDR_PIN);
+	val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1);
+
+	switch (pin_mode) {
+	case 1:
+		break;
+	case 2:
+		val |= A3700_SPI_DATA_PIN0;
+		break;
+	case 4:
+		val |= A3700_SPI_DATA_PIN1;
+		break;
+	default:
+		dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
+		return -EINVAL;
+	}
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	return 0;
+}
+
+static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_FIFO_MODE;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_mode_set(struct a3700_spi *a3700_spi,
+			       unsigned int mode_bits)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+
+	if (mode_bits & SPI_CPOL)
+		val |= A3700_SPI_CLK_POL;
+	else
+		val &= ~A3700_SPI_CLK_POL;
+
+	if (mode_bits & SPI_CPHA)
+		val |= A3700_SPI_CLK_PHA;
+	else
+		val &= ~A3700_SPI_CLK_PHA;
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
+				unsigned int speed_hz, u16 mode)
+{
+	u32 val;
+	u32 prescale;
+
+	prescale = DIV_ROUND_UP(clk_get_rate(a3700_spi->clk), speed_hz);
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val = val & ~A3700_SPI_CLK_PRESCALE_MASK;
+
+	val = val | (prescale & A3700_SPI_CLK_PRESCALE_MASK);
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	if (prescale <= 2) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_TIME_REG);
+		val |= A3700_SPI_CLK_CAPT_EDGE;
+		spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val);
+	}
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA);
+
+	if (mode & SPI_CPOL)
+		val |= A3700_SPI_CLK_POL;
+
+	if (mode & SPI_CPHA)
+		val |= A3700_SPI_CLK_PHA;
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	if (len == 4)
+		val |= A3700_SPI_BYTE_LEN;
+	else
+		val &= ~A3700_SPI_BYTE_LEN;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	a3700_spi->byte_len = len;
+}
+
+static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
+{
+	int timeout = A3700_SPI_TIMEOUT;
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_FIFO_FLUSH;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_FIFO_FLUSH))
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int a3700_spi_init(struct a3700_spi *a3700_spi)
+{
+	struct spi_master *master = a3700_spi->master;
+	u32 val;
+	int i, ret = 0;
+
+	/* Reset SPI unit */
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_SRST;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	udelay(A3700_SPI_TIMEOUT);
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~A3700_SPI_SRST;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	/* Disable AUTO_CS and deactivate all chip-selects */
+	a3700_spi_auto_cs_unset(a3700_spi);
+	for (i = 0; i < master->num_chipselect; i++)
+		a3700_spi_deactivate_cs(a3700_spi, i);
+
+	/* Enable FIFO mode */
+	a3700_spi_fifo_mode_set(a3700_spi);
+
+	/* Set SPI mode */
+	a3700_spi_mode_set(a3700_spi, master->mode_bits);
+
+	/* Reset counters */
+	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG, 0);
+
+	/* Mask the interrupts and clear cause bits */
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, ~0U);
+
+	return ret;
+}
+
+static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_master *master = dev_id;
+	struct a3700_spi *a3700_spi;
+	u32 cause;
+
+	a3700_spi = spi_master_get_devdata(master);
+
+	/* Get interrupt causes */
+	cause = spireg_read(a3700_spi, A3700_SPI_INT_STAT_REG);
+
+	if (!cause || !(a3700_spi->wait_mask & cause))
+		return IRQ_NONE;
+
+	/* mask and acknowledge the SPI interrupts */
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause);
+
+	/* Wake up the transfer */
+	if (a3700_spi->wait_mask & cause)
+		complete(&a3700_spi->done);
+
+	return IRQ_HANDLED;
+}
+
+static bool a3700_spi_wait_completion(struct spi_device *spi)
+{
+	struct a3700_spi *a3700_spi;
+	unsigned int timeout;
+	unsigned int ctrl_reg;
+	unsigned long timeout_jiffies;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+
+	/* SPI interrupt is edge-triggered, which means an interrupt will
+	 * be generated only when detecting a specific status bit changed
+	 * from '0' to '1'. So when we start waiting for a interrupt, we
+	 * need to check status bit in control reg first, if it is already 1,
+	 * then we do not need to wait for interrupt
+	 */
+	ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	if (a3700_spi->wait_mask & ctrl_reg)
+		return true;
+
+	reinit_completion(&a3700_spi->done);
+
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG,
+		     a3700_spi->wait_mask);
+
+	timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT);
+	timeout = wait_for_completion_timeout(&a3700_spi->done,
+					      timeout_jiffies);
+
+	a3700_spi->wait_mask = 0;
+
+	if (timeout)
+		return true;
+
+	/* there might be the case that right after we checked the
+	 * status bits in this routine and before start to wait for
+	 * interrupt by wait_for_completion_timeout, the interrupt
+	 * happens, to avoid missing it we need to double check
+	 * status bits in control reg, if it is already 1, then
+	 * consider that we have the interrupt successfully and
+	 * return true.
+	 */
+	ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	if (a3700_spi->wait_mask & ctrl_reg)
+		return true;
+
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+
+	return true;
+}
+
+static bool a3700_spi_transfer_wait(struct spi_device *spi,
+				    unsigned int bit_mask)
+{
+	struct a3700_spi *a3700_spi;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+	a3700_spi->wait_mask = bit_mask;
+
+	return a3700_spi_wait_completion(spi);
+}
+
+static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi,
+				     unsigned int bytes)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_RFIFO_THRS_BIT);
+	val |= (bytes - 1) << A3700_SPI_RFIFO_THRS_BIT;
+	val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_WFIFO_THRS_BIT);
+	val |= (7 - bytes) << A3700_SPI_WFIFO_THRS_BIT;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_transfer_setup(struct spi_device *spi,
+				    struct spi_transfer *xfer)
+{
+	struct a3700_spi *a3700_spi;
+	unsigned int byte_len;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+
+	a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode);
+
+	byte_len = xfer->bits_per_word >> 3;
+
+	a3700_spi_fifo_thres_set(a3700_spi, byte_len);
+}
+
+static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(spi->master);
+
+	if (!enable)
+		a3700_spi_activate_cs(a3700_spi, spi->chip_select);
+	else
+		a3700_spi_deactivate_cs(a3700_spi, spi->chip_select);
+}
+
+static void a3700_spi_header_set(struct a3700_spi *a3700_spi)
+{
+	u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0;
+	u32 val = 0;
+
+	/* Clear the header registers */
+	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0);
+
+	/* Set header counters */
+	if (a3700_spi->tx_buf) {
+		if (a3700_spi->buf_len <= a3700_spi->instr_cnt) {
+			instr_cnt = a3700_spi->buf_len;
+		} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt +
+						  a3700_spi->addr_cnt)) {
+			instr_cnt = a3700_spi->instr_cnt;
+			addr_cnt = a3700_spi->buf_len - instr_cnt;
+		} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) {
+			instr_cnt = a3700_spi->instr_cnt;
+			addr_cnt = a3700_spi->addr_cnt;
+			/* Need to handle the normal write case with 1 byte
+			 * data
+			 */
+			if (!a3700_spi->tx_buf[instr_cnt + addr_cnt])
+				dummy_cnt = a3700_spi->buf_len - instr_cnt -
+					    addr_cnt;
+		}
+		val |= ((instr_cnt & A3700_SPI_INSTR_CNT_MASK)
+			<< A3700_SPI_INSTR_CNT_BIT);
+		val |= ((addr_cnt & A3700_SPI_ADDR_CNT_MASK)
+			<< A3700_SPI_ADDR_CNT_BIT);
+		val |= ((dummy_cnt & A3700_SPI_DUMMY_CNT_MASK)
+			<< A3700_SPI_DUMMY_CNT_BIT);
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
+
+	/* Update the buffer length to be transferred */
+	a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt);
+
+	/* Set Instruction */
+	val = 0;
+	while (instr_cnt--) {
+		val = (val << 8) | a3700_spi->tx_buf[0];
+		a3700_spi->tx_buf++;
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, val);
+
+	/* Set Address */
+	val = 0;
+	while (addr_cnt--) {
+		val = (val << 8) | a3700_spi->tx_buf[0];
+		a3700_spi->tx_buf++;
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
+}
+
+static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	return (val & A3700_SPI_WFIFO_FULL);
+}
+
+static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+	int i = 0;
+
+	while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
+		val = 0;
+		if (a3700_spi->buf_len >= 4) {
+			val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
+			spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
+
+			a3700_spi->buf_len -= 4;
+			a3700_spi->tx_buf += 4;
+		} else {
+			/*
+			 * If the remained buffer length is less than 4-bytes,
+			 * we should pad the write buffer with all ones. So that
+			 * it avoids overwrite the unexpected bytes following
+			 * the last one.
+			 */
+			val = GENMASK(31, 0);
+			while (a3700_spi->buf_len) {
+				val &= ~(0xff << (8 * i));
+				val |= *a3700_spi->tx_buf++ << (8 * i);
+				i++;
+				a3700_spi->buf_len--;
+
+				spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG,
+					     val);
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int a3700_is_rfifo_empty(struct a3700_spi *a3700_spi)
+{
+	u32 val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+
+	return (val & A3700_SPI_RFIFO_EMPTY);
+}
+
+static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
+		val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
+		if (a3700_spi->buf_len >= 4) {
+			u32 data = le32_to_cpu(val);
+			memcpy(a3700_spi->rx_buf, &data, 4);
+
+			a3700_spi->buf_len -= 4;
+			a3700_spi->rx_buf += 4;
+		} else {
+			/*
+			 * When remain bytes is not larger than 4, we should
+			 * avoid memory overwriting and just write the left rx
+			 * buffer bytes.
+			 */
+			while (a3700_spi->buf_len) {
+				*a3700_spi->rx_buf = val & 0xff;
+				val >>= 8;
+
+				a3700_spi->buf_len--;
+				a3700_spi->rx_buf++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void a3700_spi_transfer_abort_fifo(struct a3700_spi *a3700_spi)
+{
+	int timeout = A3700_SPI_TIMEOUT;
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_XFER_START))
+			break;
+		udelay(1);
+	}
+
+	a3700_spi_fifo_flush(a3700_spi);
+
+	val &= ~A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static int a3700_spi_prepare_message(struct spi_master *master,
+				     struct spi_message *message)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+	struct spi_device *spi = message->spi;
+	int ret;
+
+	ret = clk_enable(a3700_spi->clk);
+	if (ret) {
+		dev_err(&spi->dev, "failed to enable clk with error %d\n", ret);
+		return ret;
+	}
+
+	/* Flush the FIFOs */
+	ret = a3700_spi_fifo_flush(a3700_spi);
+	if (ret)
+		return ret;
+
+	a3700_spi_bytelen_set(a3700_spi, 4);
+
+	return 0;
+}
+
+static int a3700_spi_transfer_one(struct spi_master *master,
+				  struct spi_device *spi,
+				  struct spi_transfer *xfer)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+	int ret = 0, timeout = A3700_SPI_TIMEOUT;
+	unsigned int nbits = 0;
+	u32 val;
+
+	a3700_spi_transfer_setup(spi, xfer);
+
+	a3700_spi->tx_buf  = xfer->tx_buf;
+	a3700_spi->rx_buf  = xfer->rx_buf;
+	a3700_spi->buf_len = xfer->len;
+
+	/* SPI transfer headers */
+	a3700_spi_header_set(a3700_spi);
+
+	if (xfer->tx_buf)
+		nbits = xfer->tx_nbits;
+	else if (xfer->rx_buf)
+		nbits = xfer->rx_nbits;
+
+	a3700_spi_pin_mode_set(a3700_spi, nbits);
+
+	if (xfer->rx_buf) {
+		/* Set read data length */
+		spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
+			     a3700_spi->buf_len);
+		/* Start READ transfer */
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val &= ~A3700_SPI_RW_EN;
+		val |= A3700_SPI_XFER_START;
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	} else if (xfer->tx_buf) {
+		/* Start Write transfer */
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val |= (A3700_SPI_XFER_START | A3700_SPI_RW_EN);
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+		/*
+		 * If there are data to be written to the SPI device, xmit_data
+		 * flag is set true; otherwise the instruction in SPI_INSTR does
+		 * not require data to be written to the SPI device, then
+		 * xmit_data flag is set false.
+		 */
+		a3700_spi->xmit_data = (a3700_spi->buf_len != 0);
+	}
+
+	while (a3700_spi->buf_len) {
+		if (a3700_spi->tx_buf) {
+			/* Wait wfifo ready */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_WFIFO_RDY)) {
+				dev_err(&spi->dev,
+					"wait wfifo ready timed out\n");
+				ret = -ETIMEDOUT;
+				goto error;
+			}
+			/* Fill up the wfifo */
+			ret = a3700_spi_fifo_write(a3700_spi);
+			if (ret)
+				goto error;
+		} else if (a3700_spi->rx_buf) {
+			/* Wait rfifo ready */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_RFIFO_RDY)) {
+				dev_err(&spi->dev,
+					"wait rfifo ready timed out\n");
+				ret = -ETIMEDOUT;
+				goto error;
+			}
+			/* Drain out the rfifo */
+			ret = a3700_spi_fifo_read(a3700_spi);
+			if (ret)
+				goto error;
+		}
+	}
+
+	/*
+	 * Stop a write transfer in fifo mode:
+	 *	- wait all the bytes in wfifo to be shifted out
+	 *	 - set XFER_STOP bit
+	 *	- wait XFER_START bit clear
+	 *	- clear XFER_STOP bit
+	 * Stop a read transfer in fifo mode:
+	 *	- the hardware is to reset the XFER_START bit
+	 *	   after the number of bytes indicated in DIN_CNT
+	 *	   register
+	 *	- just wait XFER_START bit clear
+	 */
+	if (a3700_spi->tx_buf) {
+		if (a3700_spi->xmit_data) {
+			/*
+			 * If there are data written to the SPI device, wait
+			 * until SPI_WFIFO_EMPTY is 1 to wait for all data to
+			 * transfer out of write FIFO.
+			 */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_WFIFO_EMPTY)) {
+				dev_err(&spi->dev, "wait wfifo empty timed out\n");
+				return -ETIMEDOUT;
+			}
+		} else {
+			/*
+			 * If the instruction in SPI_INSTR does not require data
+			 * to be written to the SPI device, wait until SPI_RDY
+			 * is 1 for the SPI interface to be in idle.
+			 */
+			if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
+				dev_err(&spi->dev, "wait xfer ready timed out\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val |= A3700_SPI_XFER_STOP;
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	}
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_XFER_START))
+			break;
+		udelay(1);
+	}
+
+	if (timeout == 0) {
+		dev_err(&spi->dev, "wait transfer start clear timed out\n");
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	val &= ~A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	goto out;
+
+error:
+	a3700_spi_transfer_abort_fifo(a3700_spi);
+out:
+	spi_finalize_current_transfer(master);
+
+	return ret;
+}
+
+static int a3700_spi_unprepare_message(struct spi_master *master,
+				       struct spi_message *message)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+
+	clk_disable(a3700_spi->clk);
+
+	return 0;
+}
+
+static const struct of_device_id a3700_spi_dt_ids[] = {
+	{ .compatible = "marvell,armada-3700-spi", .data = NULL },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, a3700_spi_dt_ids);
+
+static int a3700_spi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *of_node = dev->of_node;
+	struct resource *res;
+	struct spi_master *master;
+	struct a3700_spi *spi;
+	u32 num_cs = 0;
+	int ret = 0;
+
+	master = spi_alloc_master(dev, sizeof(*spi));
+	if (!master) {
+		dev_err(dev, "master allocation failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (of_property_read_u32(of_node, "num-cs", &num_cs)) {
+		dev_err(dev, "could not find num-cs\n");
+		ret = -ENXIO;
+		goto error;
+	}
+
+	master->bus_num = pdev->id;
+	master->dev.of_node = of_node;
+	master->mode_bits = SPI_MODE_3;
+	master->num_chipselect = num_cs;
+	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
+	master->prepare_message =  a3700_spi_prepare_message;
+	master->transfer_one = a3700_spi_transfer_one;
+	master->unprepare_message = a3700_spi_unprepare_message;
+	master->set_cs = a3700_spi_set_cs;
+	master->flags = SPI_MASTER_HALF_DUPLEX;
+	master->mode_bits |= (SPI_RX_DUAL | SPI_RX_DUAL |
+			      SPI_RX_QUAD | SPI_TX_QUAD);
+
+	platform_set_drvdata(pdev, master);
+
+	spi = spi_master_get_devdata(master);
+	memset(spi, 0, sizeof(struct a3700_spi));
+
+	spi->master = master;
+	spi->instr_cnt = A3700_INSTR_CNT;
+	spi->addr_cnt = A3700_ADDR_CNT;
+	spi->hdr_cnt = A3700_INSTR_CNT + A3700_ADDR_CNT +
+		       A3700_DUMMY_CNT;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	spi->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(spi->base)) {
+		ret = PTR_ERR(spi->base);
+		goto error;
+	}
+
+	spi->irq = platform_get_irq(pdev, 0);
+	if (spi->irq < 0) {
+		dev_err(dev, "could not get irq: %d\n", spi->irq);
+		ret = -ENXIO;
+		goto error;
+	}
+
+	init_completion(&spi->done);
+
+	spi->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(spi->clk)) {
+		dev_err(dev, "could not find clk: %ld\n", PTR_ERR(spi->clk));
+		goto error;
+	}
+
+	ret = clk_prepare(spi->clk);
+	if (ret) {
+		dev_err(dev, "could not prepare clk: %d\n", ret);
+		goto error;
+	}
+
+	ret = a3700_spi_init(spi);
+	if (ret)
+		goto error_clk;
+
+	ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0,
+			       dev_name(dev), master);
+	if (ret) {
+		dev_err(dev, "could not request IRQ: %d\n", ret);
+		goto error_clk;
+	}
+
+	ret = devm_spi_register_master(dev, master);
+	if (ret) {
+		dev_err(dev, "Failed to register master\n");
+		goto error_clk;
+	}
+
+	return 0;
+
+error_clk:
+	clk_disable_unprepare(spi->clk);
+error:
+	spi_master_put(master);
+out:
+	return ret;
+}
+
+static int a3700_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct a3700_spi *spi = spi_master_get_devdata(master);
+
+	clk_unprepare(spi->clk);
+	spi_master_put(master);
+
+	return 0;
+}
+
+static struct platform_driver a3700_spi_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(a3700_spi_dt_ids),
+	},
+	.probe		= a3700_spi_probe,
+	.remove		= a3700_spi_remove,
+};
+
+module_platform_driver(a3700_spi_driver);
+
+MODULE_DESCRIPTION("Armada-3700 SPI driver");
+MODULE_AUTHOR("Wilson Ding <dingwei-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
2.10.2

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

^ permalink raw reply related

* Re: [PATCH v2] mtd/spi-nor: Add SPI memory controllers for Aspeed SoCs
From: Cédric Le Goater @ 2016-12-08 16:36 UTC (permalink / raw)
  To: Marek Vasut, linux-mtd
  Cc: Mark Rutland, Boris Brezillon, devicetree, Richard Weinberger,
	Rob Herring, Joel Stanley, Cyrille Pitchen, Brian Norris,
	David Woodhouse
In-Reply-To: <bc14b6ba-800c-bf69-763e-65ead8d4efa7@gmail.com>

Hello Marek,

On 11/20/2016 10:43 PM, Marek Vasut wrote:
> On 11/09/2016 11:42 AM, Cédric Le Goater wrote:
>> This driver adds mtd support for spi-nor attached to either or both of
>> the Firmware Memory Controller or the SPI Flash Controller (AST2400
>> only).
>>
>> The SMC controllers on the Aspeed AST2500 SoC are very similar to the
>> ones found on the AST2400. The differences are on the number of
>> supported flash modules and their default mappings in the SoC address
>> space.
>>
>> The Aspeed AST2500 has one SPI controller for the BMC firmware and two
>> for the host firmware. All controllers have now the same set of
>> registers compatible with the AST2400 FMC controller and the legacy
>> 'SMC' controller is fully gone.
>>
>> Each controller has a memory range on which it maps its flash module
>> slaves. Each slave is assigned a memory window for its mapping that
>> can be changed at bootime with the Segment Address Register.
>>
>> Each SPI flash slave can then be accessed in two modes: Command and
>> User. When in User mode, accesses to the memory segment of the slaves
>> are translated in SPI transfers. When in Command mode, the HW
>> generates the SPI commands automatically and the memory segment is
>> accessed as if doing a MMIO.
>>
>> Currently, only the User mode is supported. Command mode needs a
>> little more work to check that the memory window on the AHB bus fits
>> the module size.
>>
>> Based on previous work from Milton D. Miller II <miltonm@us.ibm.com>
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
>> ---
>>  Tested on:
>>
>>  * OpenPOWER Palmetto (AST2400) with
>>  	FMC controller : n25q256a
>> 	SPI controller : mx25l25635e and n25q512ax3
>>
>>  * Evaluation board (AST2500) with
>>  	FMC controller : w25q256 
>> 	SPI controller : w25q256
>>
>>  * OpenPOWER Witherspoon (AST2500) with
>>  	FMC controller : mx25l25635e * 2
>> 	SPI controller : mx66l1g45g
>>
>>  Changes since v2:
>>
>>  - added a set4b ops to handle difference in the controllers
>>  - simplified the IO routines
>>  - prepared for fast read using dummy cycles
>>
>>  Work in progress:
>>
>>  - read optimization using higher SPI clock frequencies
>>  - command mode to direct reads from AHB
>>  - DMA support
>>
>>  .../devicetree/bindings/mtd/aspeed-smc.txt         |  72 ++
>>  drivers/mtd/spi-nor/Kconfig                        |  12 +
>>  drivers/mtd/spi-nor/Makefile                       |   1 +
>>  drivers/mtd/spi-nor/aspeed-smc.c                   | 783 +++++++++++++++++++++
>>  4 files changed, 868 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>>  create mode 100644 drivers/mtd/spi-nor/aspeed-smc.c
>>
>> diff --git a/Documentation/devicetree/bindings/mtd/aspeed-smc.txt b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>> new file mode 100644
>> index 000000000000..7516b0c01fcf
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mtd/aspeed-smc.txt
>> @@ -0,0 +1,72 @@
>> +* Aspeed Static Memory controller
>> +* Aspeed SPI Flash Controller
>> +
>> +The Static memory controller in the ast2400 supports 5 chip selects
>> +each can be attached to NAND, parallel NOR, or SPI NOR attached flash.
> 
> So this controller is supported by this driver, which behaves like a SPI
> controller driver, yet the block can also do NAND and parallel NOR ?

I think that was answered in a previous email.

>> +The Firmware Memory Controller in the ast2500 supports 3 chip selects,
>> +two of which are always in SPI-NOR mode and the third can be SPI-NOR
>> +or parallel flash. The SPI flash controller in the ast2400 supports
>> +one of 2 chip selects selected by pinmux. The two SPI flash
>> +controllers in the ast2500 each support two chip selects.
> 
> This paragraph is confusing, it's hard to grok down how many different
> controllers does this driver support and what are their properties from
> it. It is all there, it's just hard to read.

I will start with the AST2500 controllers only, which are consistent.

> Also, please split the DT bindings into separate patch and send them to
> DT list for review.

ok.

>> +Required properties:
>> +  - compatible : Should be one of
>> +	"aspeed,ast2400-fmc" for the AST2400 Static Memory Controller
>> +	"aspeed,ast2400-smc" for the AST2400 SPI Flash Controller
>> +	"aspeed,ast2500-fmc" for the AST2500 Firmware SPI Memory Controller
>> +	"aspeed,ast2500-smc" for the AST2500 SPI Flash Controllers
>> +  - reg : the first contains the control register location and length,
>> +          the second contains the memory window mapping address and length
>> +  - #address-cells : must be 1 corresponding to chip select child binding
>> +  - #size-cells : must be 0 corresponding to chip select child binding
>> +
>> +Optional properties:
>> +  - interrupts : Should contain the interrupt for the dma device if an fmc
>> +
>> +The child nodes are the SPI Flash modules which must have a compatible
>> +property as specified in bindings/mtd/jedec,spi-nor.txt
>> +
>> +Optionally, the child node can contain properties for SPI mode (may be
>> +ignored):
>> +  - spi-max-frequency - (optional) max frequency of spi bus
> 
> You don't need to add the (optional) here again.
> 
>> +Example:
>> +fmc: fmc@1e620000 {
> 
> I'd suggest to keep the example minimal -- drop the partitions etc.

ok

>> +	compatible = "aspeed,ast2400-fmc";
>> +	reg = < 0x1e620000 0x94
>> +		0x20000000 0x02000000
>> +		0x22000000 0x02000000 >;
>> +	#address-cells = <1>;
>> +	#size-cells = <0>;
>> +	interrupts = <19>;
>> +	flash@0 {
>> +		reg = < 0 >;
>> +		compatible = "jedec,spi-nor" ;
>> +		/* spi-max-frequency = <>; */
>> +		/* m25p,fast-read; */
>> +		#address-cells = <1>;
>> +		#size-cells = <1>;
>> +		partitions {
>> +			compatible = "fixed-partitions";
>> +			#address-cells = <1>;
>> +			#size-cells = <1>;
>> +			boot@0 {
>> +				label = "boot-loader";
>> +				reg = < 0 0x8000 >;
>> +			};
>> +			image@8000 {
>> +				label = "kernel-image";
>> +				reg = < 0x8000 0x1f8000 >;
>> +			};
>> +		};
>> +	};
>> +	flash@1 {
>> +		reg = < 1 >;
>> +		compatible = "jedec,spi-nor" ;
>> +		label = "alt";
>> +		/* spi-max-frequency = <>; */
>> +		status = "fail";
>> +		/* m25p,fast-read; */
>> +	};
>> +};
>> diff --git a/drivers/mtd/spi-nor/Kconfig b/drivers/mtd/spi-nor/Kconfig
>> index 4a682ee0f632..96148600fdab 100644
>> --- a/drivers/mtd/spi-nor/Kconfig
>> +++ b/drivers/mtd/spi-nor/Kconfig
>> @@ -76,4 +76,16 @@ config SPI_NXP_SPIFI
>>  	  Flash. Enable this option if you have a device with a SPIFI
>>  	  controller and want to access the Flash as a mtd device.
>>  
>> +config ASPEED_FLASH_SPI
> 
> Should be SPI_ASPEED , see the other controllers and keep the list sorted.

ok

>> +	tristate "Aspeed flash controllers in SPI mode"
>> +	depends on HAS_IOMEM && OF
>> +	depends on ARCH_ASPEED || COMPILE_TEST
>> +	# IO_SPACE_LIMIT must be equivalent to (~0UL)
>> +	depends on !NEED_MACH_IO_H
> 
> Why?

Some left over from the patch we have been keeping for too long (+1year)
in our tree.
 
>> +	help
>> +	  This enables support for the New Static Memory Controller
>> +	  (FMC) in the Aspeed SoCs (AST2400 and AST2500) when attached
>> +	  to SPI nor chips, and support for the SPI Memory controller
>> +	  (SPI) for the BIOS.
> 
> I think there is a naming chaos between FMC, SMC (as in Static MC) and
> SMC (as in SPI MC).

I agree, I will try to clarify the naming in the next version. I will keep 
the smc suffix for the driver name though.

>>  endif # MTD_SPI_NOR
>> diff --git a/drivers/mtd/spi-nor/Makefile b/drivers/mtd/spi-nor/Makefile
>> index 121695e83542..c3174ebc45c2 100644
>> --- a/drivers/mtd/spi-nor/Makefile
>> +++ b/drivers/mtd/spi-nor/Makefile
>> @@ -4,4 +4,5 @@ obj-$(CONFIG_SPI_CADENCE_QUADSPI)	+= cadence-quadspi.o
>>  obj-$(CONFIG_SPI_FSL_QUADSPI)	+= fsl-quadspi.o
>>  obj-$(CONFIG_SPI_HISI_SFC)	+= hisi-sfc.o
>>  obj-$(CONFIG_MTD_MT81xx_NOR)    += mtk-quadspi.o
>> +obj-$(CONFIG_ASPEED_FLASH_SPI)	+= aspeed-smc.o
>>  obj-$(CONFIG_SPI_NXP_SPIFI)	+= nxp-spifi.o
>> diff --git a/drivers/mtd/spi-nor/aspeed-smc.c b/drivers/mtd/spi-nor/aspeed-smc.c
>> new file mode 100644
>> index 000000000000..30662daf89ca
>> --- /dev/null
>> +++ b/drivers/mtd/spi-nor/aspeed-smc.c
>> @@ -0,0 +1,783 @@
>> +/*
>> + * ASPEED Static Memory Controller driver
>> + *
>> + * Copyright (c) 2015-2016, IBM Corporation.
>> + *
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License
>> + * as published by the Free Software Foundation; either version
>> + * 2 of the License, or (at your option) any later version.
>> + */
>> +
>> +#include <linux/bug.h>
>> +#include <linux/device.h>
>> +#include <linux/io.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/mtd/mtd.h>
>> +#include <linux/mtd/partitions.h>
>> +#include <linux/mtd/spi-nor.h>
>> +#include <linux/of.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/sysfs.h>
>> +
>> +#define DEVICE_NAME	"aspeed-smc"
>> +
>> +/*
>> + * In user mode all data bytes read or written to the chip decode address
>> + * range are transferred to or from the SPI bus. The range is treated as a
>> + * fifo of arbitratry 1, 2, or 4 byte width but each write has to be aligned
>> + * to its size.  The address within the multiple 8kB range is ignored when
>> + * sending bytes to the SPI bus.
>> + *
>> + * On the arm architecture, as of Linux version 4.3, memcpy_fromio and
>> + * memcpy_toio on little endian targets use the optimized memcpy routines
>> + * that were designed for well behavied memory storage.  These routines
>> + * have a stutter if the source and destination are not both word aligned,
>> + * once with a duplicate access to the source after aligning to the
>> + * destination to a word boundary, and again with a duplicate access to
>> + * the source when the final byte count is not word aligned.
>> + *
>> + * When writing or reading the fifo this stutter discards data or sends
>> + * too much data to the fifo and can not be used by this driver.
>> + *
>> + * While the low level io string routines that implement the insl family do
>> + * the desired accesses and memory increments, the cross architecture io
>> + * macros make them essentially impossible to use on a memory mapped address
>> + * instead of a a token from the call to iomap of an io port.
>> + *
>> + * These fifo routines use readl and friends to a constant io port and update
>> + * the memory buffer pointer and count via explicit code. The final updates
>> + * to len are optimistically suppressed.
>> + */
>> +static int aspeed_smc_read_from_ahb(void *buf, const void __iomem *src,
>> +				    size_t len)
>> +{
> 
> What if start of buf is unaligned ?
> 
>> +	if ((((unsigned long)src | (unsigned long)buf | len) & 3) == 0) {
> 
> Uh, should use boolean OR, not bitwise or. Also, if you're testing
> pointer for NULL, do if (!ptr) .
> 
> if (!src || !buf || !len)
>    return;
> 
> while (...)

I have added a bunch of IS_ALIGNED() in the next version to clarify what 
these tests are for.

>> +		while (len > 3) {
>> +			*(u32 *)buf = readl(src);
>> +			buf += 4;
>> +			src += 4;
>> +			len -= 4;
>> +		}
>> +	}
>> +
>> +	while (len--) {
>> +		*(u8 *)buf = readb(src);
>> +		buf += 1;
>> +		src += 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +static int aspeed_smc_write_to_ahb(void __iomem *dst, const void *buf,
>> +				   size_t len)
>> +{
>> +	if ((((unsigned long)dst | (unsigned long)buf | len) & 3) == 0) {
> 
> DTTO
> 
>> +		while (len > 3) {
>> +			u32 val = *(u32 *)buf;
>> +
>> +			writel(val, dst);
>> +			buf += 4;
>> +			dst += 4;
>> +			len -= 4;
>> +		}
>> +	}
>> +
>> +	while (len--) {
>> +		u8 val = *(u8 *)buf;
>> +
>> +		writeb(val, dst);
>> +		buf += 1;
>> +		dst += 1;
>> +	}
>> +	return 0;
>> +}
>> +
>> +enum smc_flash_type {
>> +	smc_type_nor = 0,	/* controller connected to nor flash */
>> +	smc_type_nand = 1,	/* controller connected to nand flash */
>> +	smc_type_spi = 2,	/* controller connected to spi flash */
>> +};
>> +
>> +struct aspeed_smc_chip;
>> +
>> +struct aspeed_smc_info {
>> +	u32 maxsize;		/* maximum size of 1 chip window */
>> +	u8 nce;			/* number of chip enables */
>> +	u8 maxwidth;		/* max width of spi bus */
>> +	bool hastype;		/* flash type field exists in cfg reg */
>> +	u8 we0;			/* shift for write enable bit for ce 0 */
>> +	u8 ctl0;		/* offset in regs of ctl for ce 0 */
>> +	u8 time;		/* offset in regs of timing */
>> +	u8 misc;		/* offset in regs of misc settings */
>> +
>> +	void (*set_4b)(struct aspeed_smc_chip *chip);
>> +};
>> +
>> +static void aspeed_smc_chip_set_4b_smc_2400(struct aspeed_smc_chip *chip);
>> +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip);
>> +
>> +static const struct aspeed_smc_info fmc_2400_info = {
>> +	.maxsize = 64 * 1024 * 1024,
>> +	.nce = 5,
>> +	.maxwidth = 4,
>> +	.hastype = true,
> 
> Shouldn't all this be specified in DT ?

I am not sure, these values are not configurable. I will remove a few 
of them in the next version as they are unused.

>> +	.we0 = 16,
>> +	.ctl0 = 0x10,
>> +	.time = 0x94,
>> +	.misc = 0x54,
>> +	.set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +static const struct aspeed_smc_info smc_2400_info = {
>> +	.maxsize = 64 * 1024 * 1024,
>> +	.nce = 1,
>> +	.maxwidth = 2,
>> +	.hastype = false,
>> +	.we0 = 0,
>> +	.ctl0 = 0x04,
>> +	.time = 0x14,
>> +	.misc = 0x10,
>> +	.set_4b = aspeed_smc_chip_set_4b_smc_2400,
>> +};
>> +
>> +static const struct aspeed_smc_info fmc_2500_info = {
>> +	.maxsize = 256 * 1024 * 1024,
>> +	.nce = 3,
>> +	.maxwidth = 2,
>> +	.hastype = true,
>> +	.we0 = 16,
>> +	.ctl0 = 0x10,
>> +	.time = 0x94,
>> +	.misc = 0x54,
>> +	.set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +static const struct aspeed_smc_info smc_2500_info = {
>> +	.maxsize = 128 * 1024 * 1024,
>> +	.nce = 2,
>> +	.maxwidth = 2,
>> +	.hastype = false,
>> +	.we0 = 16,
>> +	.ctl0 = 0x10,
>> +	.time = 0x94,
>> +	.misc = 0x54,
>> +	.set_4b = aspeed_smc_chip_set_4b,
>> +};
>> +
>> +enum smc_ctl_reg_value {
>> +	smc_base,		/* base value without mode for other commands */
>> +	smc_read,		/* command reg for (maybe fast) reads */
>> +	smc_write,		/* command reg for writes with timings */
>> +	smc_num_ctl_reg_values	/* last value to get count of commands */
>> +};
>> +
>> +struct aspeed_smc_controller;
>> +
>> +struct aspeed_smc_chip {
>> +	int cs;
>> +	struct aspeed_smc_controller *controller;
>> +	__le32 __iomem *ctl;			/* control register */
> 
> Why do you use __le32* here and void* below ?

arg. this is left over rust. 

> 
>> +	void __iomem *base;			/* base of chip window */
>> +	__le32 ctl_val[smc_num_ctl_reg_values];	/* controls with timing */
>> +	enum smc_flash_type type;		/* what type of flash */
>> +	struct spi_nor nor;
>> +};
>> +
>> +struct aspeed_smc_controller {
>> +	struct device *dev;
>> +
>> +	struct mutex mutex;			/* controller access mutex */
>> +	const struct aspeed_smc_info *info;	/* type info of controller */
>> +	void __iomem *regs;			/* controller registers */
>> +	void __iomem *windows;			/* per-chip windows resource */
>> +
>> +	struct aspeed_smc_chip *chips[0];	/* pointers to attached chips */
>> +};
>> +
>> +/*
>> + * SPI Flash Configuration Register (AST2400 SPI)
>> + */
>> +#define CONFIG_REG			0x0
>> +#define    CONFIG_ENABLE_CE_INACTIVE	    BIT(1)
>> +#define    CONFIG_WRITE			    BIT(0)
> 
> #define[space]FOO[tab]BIT(bar)

ok. I don't have a strong preference for the indent.

> 
>> +/*
>> + * SPI Flash Configuration Register (AST2500 SPI)
>> + * Type setting Register (AST2500 FMC and AST2400 FMC)
>> + */
>> +#define TYPE_SETTING_REG		0x0
>> +#define    CONFIG_DISABLE_LEGACY	    BIT(31) /* 1 on AST2500 FMC */
>> +
>> +#define    CONFIG_CE2_WRITE		    BIT(18)
>> +#define    CONFIG_CE1_WRITE		    BIT(17)
>> +#define    CONFIG_CE0_WRITE		    BIT(16)
>> +
>> +#define    CONFIG_CE2_TYPE		    BIT(4) /* FMC only */
>> +#define    CONFIG_CE1_TYPE		    BIT(2) /* FMC only */
>> +#define    CONFIG_CE0_TYPE		    BIT(0) /* FMC only */
>> +
>> +/*
>> + * CE Control Register (AST2500 SPI,FMC and AST2400 FMC)
>> + */
>> +#define CE_CONTROL_REG			0x4
>> +#define    CE2_ENABLE_CE_INACTIVE           BIT(10)
>> +#define    CE1_ENABLE_CE_INACTIVE           BIT(9)
>> +#define    CE0_ENABLE_CE_INACTIVE           BIT(8)
>> +#define    CE2_CONTROL_EXTENDED		    BIT(2)
>> +#define    CE1_CONTROL_EXTENDED		    BIT(1)
>> +#define    CE0_CONTROL_EXTENDED		    BIT(0)
>> +
>> +/* CE0 Control Register (depends on the controller type) */
>> +#define CONTROL_SPI_AAF_MODE BIT(31)
>> +#define CONTROL_SPI_IO_MODE_MASK GENMASK(30, 28)
>> +#define CONTROL_SPI_IO_DUAL_DATA BIT(29)
>> +#define CONTROL_SPI_IO_DUAL_ADDR_DATA (BIT(29) | BIT(28))
>> +#define CONTROL_SPI_IO_QUAD_DATA BIT(30)
>> +#define CONTROL_SPI_IO_QUAD_ADDR_DATA (BIT(30) | BIT(28))
>> +#define CONTROL_SPI_CE_INACTIVE_SHIFT 24
>> +#define CONTROL_SPI_CE_INACTIVE_MASK GENMASK(27, CONTROL_SPI_CE_INACTIVE_SHIFT)
>> +/* 0 = 16T ... 15 = 1T   T=HCLK */
>> +#define CONTROL_SPI_COMMAND_SHIFT 16
>> +#define CONTROL_SPI_DUMMY_CYCLE_COMMAND_OUTPUT BIT(15)
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_HI BIT(14)
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_HI_SHIFT 14
>> +#define CONTROL_SPI_IO_ADDRESS_4B BIT(13) /* AST2400 SPI */
>> +#define CONTROL_SPI_CLK_DIV4 BIT(13) /* others */
>> +#define CONTROL_SPI_RW_MERGE BIT(12)
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_LO_SHIFT 6
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_LO GENMASK(7, \
>> +				       CONTROL_SPI_IO_DUMMY_CYCLES_LO_SHIFT)
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_MASK (CONTROL_SPI_IO_DUMMY_CYCLES_HI | \
>> +					  CONTROL_SPI_IO_DUMMY_CYCLES_LO)
>> +#define CONTROL_SPI_IO_DUMMY_CYCLES_SET(dummy)				\
>> +	(((((dummy) >> 2) & 0x1) << CONTROL_SPI_IO_DUMMY_CYCLES_HI_SHIFT) | \
>> +	(((dummy) & 0x3) << CONTROL_SPI_IO_DUMMY_CYCLES_LO_SHIFT))
>> +
>> +#define CONTROL_SPI_CLOCK_FREQ_SEL_SHIFT 8
>> +#define CONTROL_SPI_CLOCK_FREQ_SEL_MASK GENMASK(11, \
>> +					CONTROL_SPI_CLOCK_FREQ_SEL_SHIFT)
>> +#define CONTROL_SPI_LSB_FIRST BIT(5)
>> +#define CONTROL_SPI_CLOCK_MODE_3 BIT(4)
>> +#define CONTROL_SPI_IN_DUAL_DATA BIT(3)
>> +#define CONTROL_SPI_CE_STOP_ACTIVE_CONTROL BIT(2)
>> +#define CONTROL_SPI_COMMAND_MODE_MASK GENMASK(1, 0)
>> +#define CONTROL_SPI_COMMAND_MODE_NORMAL (0)
>> +#define CONTROL_SPI_COMMAND_MODE_FREAD (1)
>> +#define CONTROL_SPI_COMMAND_MODE_WRITE (2)
>> +#define CONTROL_SPI_COMMAND_MODE_USER (3)
>> +
>> +#define CONTROL_SPI_KEEP_MASK (CONTROL_SPI_AAF_MODE | \
>> +	CONTROL_SPI_CE_INACTIVE_MASK | CONTROL_SPI_CLK_DIV4 | \
>> +	CONTROL_SPI_IO_DUMMY_CYCLES_MASK | CONTROL_SPI_CLOCK_FREQ_SEL_MASK | \
>> +	CONTROL_SPI_LSB_FIRST | CONTROL_SPI_CLOCK_MODE_3)
>> +
>> +/* Segment Address Registers */
>> +#define SEGMENT_ADDR_REG0		0x30
>> +#define     SEGMENT_ADDR_START(_r)	    ((((_r) >> 16) & 0xFF) << 23)
>> +#define     SEGMENT_ADDR_END(_r)	    ((((_r) >> 24) & 0xFF) << 23)
>> +
>> +static u32 spi_control_fill_opcode(u8 opcode)
>> +{
>> +	return ((u32)(opcode)) << CONTROL_SPI_COMMAND_SHIFT;
> 
> return opcode << CONTROL... , fix these horrible casts and parenthesis
> globally.

I killed the helper. 

>> +}
>> +
>> +static inline u32 aspeed_smc_chip_write_bit(struct aspeed_smc_chip *chip)
>> +{
>> +	return ((u32)1 << (chip->controller->info->we0 + chip->cs));
> 
> return BIT(...)
> 
> I'm not sure these microfunctions are even needed.

well, this one is used in a couple of places.
 
>> +}
>> +
>> +static void aspeed_smc_chip_check_config(struct aspeed_smc_chip *chip)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	u32 reg;
>> +
>> +	reg = readl(controller->regs + CONFIG_REG);
>> +
>> +	if (!(reg & aspeed_smc_chip_write_bit(chip))) {
> 
> Invert the logic and return here, ie if (reg & BIT()) return , to trim
> the indent.

ok.

>> +		dev_dbg(controller->dev,
>> +			"config write is not set ! @%p: 0x%08x\n",
>> +			controller->regs + CONFIG_REG, reg);
>> +		reg |= aspeed_smc_chip_write_bit(chip);
>> +		writel(reg, controller->regs + CONFIG_REG);
>> +	}
>> +}
>> +
>> +static void aspeed_smc_start_user(struct spi_nor *nor)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +	u32 ctl = chip->ctl_val[smc_base];
>> +
>> +	/*
>> +	 * When the chip is controlled in user mode, we need write
>> +	 * access to send the opcodes to it. So check the config.
>> +	 */
>> +	aspeed_smc_chip_check_config(chip);
>> +
>> +	ctl |= CONTROL_SPI_COMMAND_MODE_USER |
>> +		CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
>> +	writel(ctl, chip->ctl);
>> +
>> +	ctl &= ~CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
>> +	writel(ctl, chip->ctl);
>> +}
>> +
>> +static void aspeed_smc_stop_user(struct spi_nor *nor)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	u32 ctl = chip->ctl_val[smc_read];
>> +	u32 ctl2 = ctl | CONTROL_SPI_COMMAND_MODE_USER |
>> +		CONTROL_SPI_CE_STOP_ACTIVE_CONTROL;
>> +
>> +	writel(ctl2, chip->ctl);	/* stop user CE control */
>> +	writel(ctl, chip->ctl);		/* default to fread or read */
>> +}
>> +
>> +static int aspeed_smc_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	mutex_lock(&chip->controller->mutex);
> 
> Won't this have a horrid overhead ?

Shall I use the prepare() and unprepare() ops instead ? 

>> +	aspeed_smc_start_user(nor);
>> +	aspeed_smc_write_to_ahb(chip->base, &opcode, 1);
>> +	aspeed_smc_read_from_ahb(buf, chip->base, len);
>> +	aspeed_smc_stop_user(nor);
>> +
>> +	mutex_unlock(&chip->controller->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static int aspeed_smc_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
>> +				int len)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	mutex_lock(&chip->controller->mutex);
>> +
>> +	aspeed_smc_start_user(nor);
>> +	aspeed_smc_write_to_ahb(chip->base, &opcode, 1);
>> +	aspeed_smc_write_to_ahb(chip->base, buf, len);
>> +	aspeed_smc_stop_user(nor);
>> +
>> +	mutex_unlock(&chip->controller->mutex);
>> +
>> +	return 0;
>> +}
>> +
>> +static void aspeed_smc_send_cmd_addr(struct spi_nor *nor, u8 cmd, u32 addr)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +	__be32 temp;
>> +	u32 cmdaddr;
>> +
>> +	switch (nor->addr_width) {
>> +	default:
>> +		WARN_ONCE(1, "Unexpected address width %u, defaulting to 3\n",
>> +			  nor->addr_width);
>> +		/* FALLTHROUGH */
>> +	case 3:
>> +		cmdaddr = addr & 0xFFFFFF;
>> +
>> +		cmdaddr |= (u32)cmd << 24;
> 
> Drop the cast.

sure.

> 
>> +		temp = cpu_to_be32(cmdaddr);
>> +		aspeed_smc_write_to_ahb(chip->base, &temp, 4);
>> +		break;
>> +	case 4:
>> +		temp = cpu_to_be32(addr);
>> +		aspeed_smc_write_to_ahb(chip->base, &cmd, 1);
>> +		aspeed_smc_write_to_ahb(chip->base, &temp, 4);
>> +		break;
>> +	}
>> +}
>> +
>> +static ssize_t aspeed_smc_read_user(struct spi_nor *nor, loff_t from,
>> +				    size_t len, u_char *read_buf)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	mutex_lock(&chip->controller->mutex);
>> +
>> +	aspeed_smc_start_user(nor);
>> +	aspeed_smc_send_cmd_addr(nor, nor->read_opcode, from);
>> +	aspeed_smc_read_from_ahb(read_buf, chip->base, len);
>> +	aspeed_smc_stop_user(nor);
>> +
>> +	mutex_unlock(&chip->controller->mutex);
>> +
>> +	return len;
>> +}
>> +
>> +static ssize_t aspeed_smc_write_user(struct spi_nor *nor, loff_t to, size_t len,
>> +				     const u_char *write_buf)
>> +{
>> +	struct aspeed_smc_chip *chip = nor->priv;
>> +
>> +	mutex_lock(&chip->controller->mutex);
>> +
>> +	aspeed_smc_start_user(nor);
>> +	aspeed_smc_send_cmd_addr(nor, nor->program_opcode, to);
>> +	aspeed_smc_write_to_ahb(chip->base, write_buf, len);
>> +	aspeed_smc_stop_user(nor);
>> +
>> +	mutex_unlock(&chip->controller->mutex);
>> +
>> +	return len;
>> +}
>> +
>> +static int aspeed_smc_remove(struct platform_device *dev)
>> +{
>> +	struct aspeed_smc_chip *chip;
>> +	struct aspeed_smc_controller *controller = platform_get_drvdata(dev);
>> +	int n;
>> +
>> +	for (n = 0; n < controller->info->nce; n++) {
>> +		chip = controller->chips[n];
>> +		if (chip)
>> +			mtd_device_unregister(&chip->nor.mtd);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static const struct of_device_id aspeed_smc_matches[] = {
>> +	{ .compatible = "aspeed,ast2400-fmc", .data = &fmc_2400_info },
>> +	{ .compatible = "aspeed,ast2400-smc", .data = &smc_2400_info },
>> +	{ .compatible = "aspeed,ast2500-fmc", .data = &fmc_2500_info },
>> +	{ .compatible = "aspeed,ast2500-smc", .data = &smc_2500_info },
>> +	{ }
>> +};
>> +MODULE_DEVICE_TABLE(of, aspeed_smc_matches);
>> +
>> +static struct platform_device *
>> +of_platform_device_create_or_find(struct device_node *child,
>> +				  struct device *parent)
>> +{
>> +	struct platform_device *cdev;
>> +
>> +	cdev = of_platform_device_create(child, NULL, parent);
>> +	if (!cdev)
>> +		cdev = of_find_device_by_node(child);
>> +	return cdev;
>> +}
>> +
>> +static void __iomem *window_start(struct aspeed_smc_controller *controller,
>> +				  struct resource *r, unsigned int n)
>> +{
>> +	u32 offset = 0;
>> +	u32 reg;
>> +
>> +	if (controller->info->nce > 1) {
>> +		reg = readl(controller->regs + SEGMENT_ADDR_REG0 + n * 4);
>> +
>> +		if (SEGMENT_ADDR_START(reg) >= SEGMENT_ADDR_END(reg))
>> +			return NULL;
>> +
>> +		offset = SEGMENT_ADDR_START(reg) - r->start;
>> +	}
>> +
>> +	return controller->windows + offset;
>> +}
>> +
>> +static void aspeed_smc_chip_enable_write(struct aspeed_smc_chip *chip)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	u32 reg;
>> +
>> +	reg = readl(controller->regs + CONFIG_REG);
>> +
>> +	reg |= aspeed_smc_chip_write_bit(chip);
>> +	writel(reg, controller->regs + CONFIG_REG);
>> +}
>> +
>> +static void aspeed_smc_chip_set_type(struct aspeed_smc_chip *chip, int type)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	u32 reg;
>> +
>> +	reg = readl(controller->regs + CONFIG_REG);
>> +
>> +	chip->type = type;
> 
> You can move this above the readl() to make the RMW block consistent.

ok


>> +	reg &= ~(3 << (chip->cs * 2));
>> +	reg |= chip->type << (chip->cs * 2);
>> +	writel(reg, controller->regs + CONFIG_REG);
>> +}
>> +
>> +/*
>> + * The AST2500 FMC and AST2400 FMC flash controllers should be
>> + * strapped by hardware, or autodetected, but the AST2500 SPI flash
>> + * needs to be set.
>> + */
>> +static void aspeed_smc_chip_set_4b(struct aspeed_smc_chip *chip)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	u32 reg;
>> +
>> +	if (chip->controller->info == &smc_2500_info) {
>> +		reg = readl(controller->regs + CE_CONTROL_REG);
>> +		reg |= 1 << chip->cs;
>> +		writel(reg, controller->regs + CE_CONTROL_REG);
>> +	}
>> +}
>> +
>> +/*
>> + * The AST2400 SPI flash controller does not have a CE Control
>> + * register. It uses the CE0 control register to set 4Byte mode at the
>> + * controller level.
>> + */
>> +static void aspeed_smc_chip_set_4b_smc_2400(struct aspeed_smc_chip *chip)
>> +{
>> +	chip->ctl_val[smc_base] |= CONTROL_SPI_IO_ADDRESS_4B;
>> +	chip->ctl_val[smc_read] |= CONTROL_SPI_IO_ADDRESS_4B;
>> +}
>> +
>> +static int aspeed_smc_chip_setup_init(struct aspeed_smc_chip *chip,
>> +				      struct resource *r)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	const struct aspeed_smc_info *info = controller->info;
>> +	u32 reg, base_reg;
>> +
>> +	/*
>> +	 * Always turn on the write enable bit to allow opcodes to be
>> +	 * sent in user mode.
>> +	 */
>> +	aspeed_smc_chip_enable_write(chip);
>> +
>> +	/* The driver only supports SPI type flash for the moment */
>> +	if (info->hastype)
>> +		aspeed_smc_chip_set_type(chip, smc_type_spi);
>> +
>> +	/*
>> +	 * Configure chip base address in memory
>> +	 */
>> +	chip->base = window_start(controller, r, chip->cs);
>> +	if (!chip->base) {
>> +		dev_warn(chip->nor.dev, "CE segment window closed.\n");
>> +		return -1;
>> +	}
>> +
>> +	/*
>> +	 * Read the existing control register to get basic values.
>> +	 *
>> +	 * XXX This register probably needs more sanitation.
> 
> What's this comment about ?

This is an initial comment about settings being done by U-Boot
before the kernel is loaded, and some optimisations should be 
nice to keep, for the FMC controller. I will rephrase.

>> +	 * Do we need support for mode 3 vs mode 0 clock phasing?
>> +	 */
>> +	reg = readl(chip->ctl);
>> +	dev_dbg(controller->dev, "control register: %08x\n", reg);
>> +
>> +	base_reg = reg & CONTROL_SPI_KEEP_MASK;
>> +	if (base_reg != reg) {
>> +		dev_info(controller->dev,
>> +			 "control register changed to: %08x\n",
>> +			 base_reg);
>> +	}
>> +	chip->ctl_val[smc_base] = base_reg;
>> +
>> +	/*
>> +	 * Retain the prior value of the control register as the
>> +	 * default if it was normal access mode. Otherwise start with
>> +	 * the sanitized base value set to read mode.
>> +	 */
>> +	if ((reg & CONTROL_SPI_COMMAND_MODE_MASK) ==
>> +	    CONTROL_SPI_COMMAND_MODE_NORMAL)
>> +		chip->ctl_val[smc_read] = reg;
>> +	else
>> +		chip->ctl_val[smc_read] = chip->ctl_val[smc_base] |
>> +			CONTROL_SPI_COMMAND_MODE_NORMAL;
>> +
>> +	dev_dbg(controller->dev, "default control register: %08x\n",
>> +		chip->ctl_val[smc_read]);
>> +	return 0;
>> +}
>> +
>> +static int aspeed_smc_chip_setup_finish(struct aspeed_smc_chip *chip)
>> +{
>> +	struct aspeed_smc_controller *controller = chip->controller;
>> +	const struct aspeed_smc_info *info = controller->info;
>> +	u32 cmd;
>> +
>> +	if (chip->nor.addr_width == 4 && info->set_4b)
>> +		info->set_4b(chip);
>> +
>> +	/*
>> +	 * base mode has not been optimized yet. use it for writes.
>> +	 */
>> +	chip->ctl_val[smc_write] = chip->ctl_val[smc_base] |
>> +		spi_control_fill_opcode(chip->nor.program_opcode) |
>> +		CONTROL_SPI_COMMAND_MODE_WRITE;
>> +
>> +	dev_dbg(controller->dev, "write control register: %08x\n",
>> +		chip->ctl_val[smc_write]);
>> +
>> +	/*
>> +	 * XXX TODO
>> +	 * Adjust clocks if fast read and write are supported.
>> +	 * Interpret spi-nor flags to adjust controller settings.
>> +	 * Check if resource size big enough for detected chip and
>> +	 * add support assisted (normal or fast-) read and dma.
>> +	 */
>> +	switch (chip->nor.flash_read) {
>> +	case SPI_NOR_NORMAL:
>> +		cmd = CONTROL_SPI_COMMAND_MODE_NORMAL;
>> +		break;
>> +	case SPI_NOR_FAST:
>> +		cmd = CONTROL_SPI_COMMAND_MODE_FREAD;
>> +		break;
>> +	default:
>> +		dev_err(chip->nor.dev, "unsupported SPI read mode\n");
>> +		return -EINVAL;
>> +	}
>> +
>> +	chip->ctl_val[smc_read] |= cmd |
>> +		CONTROL_SPI_IO_DUMMY_CYCLES_SET(chip->nor.read_dummy / 8);
>> +
>> +	dev_dbg(controller->dev, "base control register: %08x\n",
>> +		chip->ctl_val[smc_read]);
>> +	return 0;
>> +}
>> +
>> +static int aspeed_smc_probe(struct platform_device *pdev)
>> +{
>> +	struct aspeed_smc_controller *controller;
>> +	const struct of_device_id *match;
>> +	const struct aspeed_smc_info *info;
>> +	struct resource *r;
>> +	struct device_node *child;
>> +	int err = 0;
>> +	unsigned int n;
>> +
>> +	match = of_match_device(aspeed_smc_matches, &pdev->dev);
>> +	if (!match || !match->data)
>> +		return -ENODEV;
>> +	info = match->data;
>> +
>> +	controller = devm_kzalloc(&pdev->dev, sizeof(*controller) +
>> +		info->nce * sizeof(controller->chips[0]), GFP_KERNEL);
>> +	if (!controller)
>> +		return -ENOMEM;
>> +	controller->info = info;
>> +
>> +	mutex_init(&controller->mutex);
>> +	platform_set_drvdata(pdev, controller);
>> +
>> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +	controller->regs = devm_ioremap_resource(&pdev->dev, r);
>> +	if (IS_ERR(controller->regs))
>> +		return PTR_ERR(controller->regs);
>> +
>> +	r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
>> +	controller->windows = devm_ioremap_resource(&pdev->dev, r);
>> +	if (IS_ERR(controller->windows))
>> +		return PTR_ERR(controller->windows);
>> +
>> +	controller->dev = &pdev->dev;
>> +
>> +	/* The pinmux or bootloader will disable the legacy mode controller */
>> +
>> +	/*
>> +	 * XXX Need to add arbitration to the SMC (BIOS) controller if access
>> +	 * is shared by the host.
>> +	 */
>> +	for_each_available_child_of_node(controller->dev->of_node, child) {
>> +		struct platform_device *cdev;
>> +		struct aspeed_smc_chip *chip;
> 
> Pull this into separate function, ie. like cadence_qspi.c , so we can
> identify the developing boilerplate easily.

yes. I have reworked the code to follow the same pattern.


> 
>> +		/* This version does not support nand or nor flash devices. */
>> +		if (!of_device_is_compatible(child, "jedec,spi-nor"))
>> +			continue;
>> +
>> +		/*
>> +		 * create a platform device from the of node.  If the device
>> +		 * already was created (eg from a prior bind/unbind cycle)
>> +		 * reuse it.
>> +		 *
>> +		 * The creating the device node for the child here allows its
>> +		 * use for error reporting via dev_err below.
>> +		 */
>> +		cdev = of_platform_device_create_or_find(child,
>> +							 controller->dev);
>> +		if (!cdev)
>> +			continue;
>> +
>> +		err = of_property_read_u32(child, "reg", &n);
>> +		if (err == -EINVAL && info->nce == 1)
>> +			n = 0;
>> +		else if (err || n >= info->nce)
>> +			continue;
>> +		if (controller->chips[n]) {
>> +			dev_err(&cdev->dev,
>> +				"chip-id %u already in use in use by %s\n",
>> +				n, dev_name(controller->chips[n]->nor.dev));
>> +			continue;
>> +		}
>> +
>> +		chip = devm_kzalloc(controller->dev, sizeof(*chip), GFP_KERNEL);
>> +		if (!chip)
>> +			continue;
>> +		chip->controller = controller;
>> +		chip->ctl = controller->regs + info->ctl0 + n * 4;
>> +		chip->cs = n;
>> +
>> +		chip->nor.dev = &cdev->dev;
>> +		chip->nor.priv = chip;
>> +		spi_nor_set_flash_node(&chip->nor, child);
>> +		chip->nor.mtd.name = of_get_property(child, "label", NULL);
>> +		chip->nor.read = aspeed_smc_read_user;
>> +		chip->nor.write = aspeed_smc_write_user;
>> +		chip->nor.read_reg = aspeed_smc_read_reg;
>> +		chip->nor.write_reg = aspeed_smc_write_reg;
>> +
>> +		err = aspeed_smc_chip_setup_init(chip, r);
>> +		if (err)
>> +			continue;
>> +
>> +		/*
>> +		 * XXX Add support for SPI_NOR_QUAD and SPI_NOR_DUAL attach
>> +		 * when board support is present as determined by of property.
>> +		 */
>> +		err = spi_nor_scan(&chip->nor, NULL, SPI_NOR_NORMAL);
>> +		if (err)
>> +			continue;
>> +
>> +		err = aspeed_smc_chip_setup_finish(chip);
>> +		if (err)
>> +			continue;
>> +
>> +		err = mtd_device_register(&chip->nor.mtd, NULL, 0);
>> +		if (err)
>> +			continue;
> 
> What happens if some chip fails to register ?

That's not correctly handled ... I have a fix for it.

Thanks,

C. 


> 
>> +		controller->chips[n] = chip;
>> +	}
>> +
>> +	/* Were any children registered? */
>> +	for (n = 0; n < info->nce; n++)
>> +		if (controller->chips[n])
>> +			break;
>> +
>> +	if (n == info->nce)
>> +		return -ENODEV;
>> +
>> +	return 0;
>> +}
>> +
>> +static struct platform_driver aspeed_smc_driver = {
>> +	.probe = aspeed_smc_probe,
>> +	.remove = aspeed_smc_remove,
>> +	.driver = {
>> +		.name = DEVICE_NAME,
>> +		.of_match_table = aspeed_smc_matches,
>> +	}
>> +};
>> +
>> +module_platform_driver(aspeed_smc_driver);
>> +
>> +MODULE_DESCRIPTION("ASPEED Static Memory Controller Driver");
>> +MODULE_AUTHOR("Milton Miller");
>> +MODULE_LICENSE("GPL v2");
>>
> 
> 


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

^ permalink raw reply

* Re: [RESEND PATCH 1/3] bindings: net: stmmac: correct note about TSO
From: David Miller @ 2016-12-08 16:35 UTC (permalink / raw)
  To: niklas.cassel-VrBV9hrLPhE
  Cc: robh+dt-DgEjT+Ai2ygdnm+yROfE0A, mark.rutland-5wv7dgnIgG8,
	peppe.cavallaro-qxv4g6HH51o, alexandre.torgue-qxv4g6HH51o,
	preid-qgqNFa1JUf/o2iN0hyhwsIdd74u8MsAO,
	eric-op+oiCINJLTt9jDmeYuA0g, niklass-VrBV9hrLPhE,
	netdev-u79uwXL29TY76Z2rM5mHXA, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1481114469-4788-1-git-send-email-niklass-VrBV9hrLPhE@public.gmane.org>

From: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>
Date: Wed, 7 Dec 2016 13:41:06 +0100

> From: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>
> 
> snps,tso was previously placed under AXI BUS Mode parameters,
> suggesting that the property should be in the stmmac-axi-config node.
> 
> TSO (TCP Segmentation Offloading) has nothing to do with AXI BUS Mode
> parameters, and the parser actually expects it to be in the root node,
> not in the stmmac-axi-config.
> 
> Also added a note about snps,tso only being available on GMAC4 and newer.
> 
> Signed-off-by: Niklas Cassel <niklas.cassel-VrBV9hrLPhE@public.gmane.org>
> Acked-by: Alexandre TORGUE <alexandre.torgue-qxv4g6HH51o@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Acked-by: Giuseppe Cavallaro <peppe.cavallaro-qxv4g6HH51o@public.gmane.org>

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

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Rob Herring @ 2016-12-08 16:26 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: Benjamin Tissoires, Doug Anderson, Brian Norris, Jiri Kosina,
	Caesar Wang, open list:ARM/Rockchip SoC...,
	linux-input@vger.kernel.org, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org, Mark Rutland
In-Reply-To: <E409F66F-1E4B-4A63-9977-69DF44ACAB0A@gmail.com>

On Thu, Dec 8, 2016 at 10:13 AM, Dmitry Torokhov
<dmitry.torokhov@gmail.com> wrote:
> On December 8, 2016 8:03:06 AM PST, Rob Herring <robh@kernel.org> wrote:
>>On Thu, Dec 8, 2016 at 9:41 AM, Benjamin Tissoires
>><benjamin.tissoires@redhat.com> wrote:
>>> On Dec 06 2016 or thereabouts, Doug Anderson wrote:
>>>> Hi,
>>>>
>>>> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh@kernel.org> wrote:
>>>> > On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
>>>> > <benjamin.tissoires@redhat.com> wrote:
>>>> >> On Dec 05 2016 or thereabouts, Rob Herring wrote:
>>>> >>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
>>>> >>> > Hi Benjamin and Rob,
>>>> >>> >
>>>> >>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires
>>wrote:
>>>> >>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
>>>> >>> > > > From: Caesar Wang <wxt@rock-chips.com>
>>>> >>> > > >
>>>> >>> > > > Add a compatible string and regulator property for Wacom
>>W9103
>>>> >>> > > > digitizer. Its VDD supply may need to be enabled before
>>using it.
>>>> >>> > > >
>>>> >>> > > > Signed-off-by: Caesar Wang <wxt@rock-chips.com>
>>>> >>> > > > Cc: Rob Herring <robh+dt@kernel.org>
>>>> >>> > > > Cc: Jiri Kosina <jikos@kernel.org>
>>>> >>> > > > Cc: linux-input@vger.kernel.org
>>>> >>> > > > Signed-off-by: Brian Norris <briannorris@chromium.org>
>>>> >>> > > > ---
>>>> >>> > > > v1 was a few months back. I finally got around to
>>rewriting it based on
>>>> >>> > > > DT binding feedback.
>>>> >>> > > >
>>>> >>> > > > v2:
>>>> >>> > > >  * add compatible property for wacom
>>>> >>> > > >  * name the regulator property specifically (VDD)
>>>> >>> > > >
>>>> >>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>| 6 +++++-
>>>> >>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
>>>> >>> > > >
>>>> >>> > > > diff --git
>>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> >>> > > > index 488edcb264c4..eb98054e60c9 100644
>>>> >>> > > > ---
>>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> >>> > > > +++
>>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> >>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel
>>module i2c-hid will handle the communication
>>>> >>> > > >  with the device and the generic hid core layer will
>>handle the protocol.
>>>> >>> > > >
>>>> >>> > > >  Required properties:
>>>> >>> > > > -- compatible: must be "hid-over-i2c"
>>>> >>> > > > +- compatible: must be "hid-over-i2c", or a
>>device-specific string like:
>>>> >>> > > > +    * "wacom,w9013"
>>>> >>> > >
>>>> >>> > > NACK on this one.
>>>> >>> > >
>>>> >>> > > After re-reading the v1 submission I realized Rob asked for
>>this change,
>>>> >>> > > but I strongly disagree.
>>>> >>> > >
>>>> >>> > > HID over I2C is a generic protocol, in the same way HID over
>>USB is. We
>>>> >>> > > can not start adding device specifics here, this is opening
>>the can of
>>>> >>> > > worms. If the device is a HID one, nothing else should
>>matter. The rest
>>>> >>> > > (description of the device, name, etc...) is all provided by
>>the
>>>> >>> > > protocol.
>>>> >>> >
>>>> >>> > I should have spoken up when Rob made the suggestion, because
>>I more or
>>>> >>> > less agree with Benjamin here. I don't really see why this
>>needs to have
>>>> >>> > a specialized compatible string, as the property is still
>>fairly
>>>> >>> > generic, and the entire device handling is via a generic
>>protocol. The
>>>> >>> > fact that we manage its power via a regulator is not very
>>>> >>> > device-specific.
>>>> >>>
>>>> >>> It doesn't matter that the protocol is generic. The device
>>attached and
>>>> >>> the implementation is not. Implementations have been known to
>>have
>>>> >>> bugs/quirks (generally speaking, not HID over I2C in
>>particular). There
>>>> >>> are also things outside the scope of what is 'hid-over-i2c' like
>>what's
>>>> >>> needed to power-on the device which this patch clearly show.
>>>> >>
>>>> >> Yes, there are bugs, quirks, even with HID. But the HID declares
>>within
>>>> >> the protocol the Vendor ID and the Product ID, which means once
>>we pass
>>>> >> the initial "device is ready" step and can do a single i2c
>>write/read,
>>>> >> we don't give a crap about device tree anymore.
>>>> >>
>>>> >> This is just about setting the device in shape so that it can
>>answer a
>>>> >> single write/read.
>>>> >>
>>>> >>>
>>>> >>> This is no different than a panel attached via LVDS, eDP, etc.,
>>or
>>>> >>> USB/PCIe device hard-wired on a board. They all use standard
>>protocols
>>>> >>> and all need additional data to describe them. Of course, adding
>>a
>>>> >>> single property for a delay would not be a big deal, but it's
>>never
>>>> >>> ending. Next you need multiple supplies, GPIO controls, mutiple
>>>> >>> delays... This has been discussed to death already. As Thierry
>>Reding
>>>> >>> said, you're not special[1].
>>>> >>
>>>> >> I can somewhat understand what you mean. The official
>>specification is
>>>> >> for ACPI. And ACPI allows to calls various settings while
>>querying the
>>>> >> _STA method for instance. So in the ACPI world, we don't need to
>>care
>>>> >> about regulators or GPIOs because the OEM deals with this in its
>>own
>>>> >> blob.
>>>> >>
>>>> >> Now, coming back to our issue. We are not special, maybe, if he
>>says so.
>>>> >> But this really feels like a design choice between putting the
>>burden on
>>>> >> device tree and OEMs or in the module maintainers. And I'd rather
>>have
>>>> >> the OEM deal with their device than me having to update the
>>module for
>>>> >> each generations of hardware. Indeed, this looks like an
>>"endless"
>>>> >> amount of quirks, but I'd rather have this endless amount of
>>quirks than
>>>> >> having to maintain an endless amount of list of new devices that
>>behaves
>>>> >> the same way. We are talking here about "wacom,w9013", but then
>>comes
>>>> >> "wacom,w9014" and we need to upgrade the kernel.
>>>> >
>>>> > No. If the w9014 can claim compatibility with then w9013, then you
>>>> > don't need a kernel change. The DT should list the w9014 AND
>>w9013,
>>>> > but the kernel only needs to know about the w9013. That is until
>>there
>>>> > is some difference which is why the DT should list w9014 to start
>>>> > with.
>>>> >
>>>> > If you don't have any power control to deal with, then the kernel
>>can
>>>> > always just match on "hid-over-i2c" compatible.
>>>>
>>>> Just my $0.02.  Feel free to ignore.
>>>>
>>>> One thought is that I would say that the need to power on the device
>>>> explicitly seems more like a board level difference and less like a
>>>> difference associated with a particular digitizer.  Said another
>>way,
>>>> it seems likely there will be boards with a w9013 without explicit
>>>> control of the regulator in software and it seems like there will be
>>>> boards with other digitizers where suddenly a new board will come
>>out
>>>> that needs explicit control of the regulator.
>>>>
>>>> In this particular case I feel like we can draw a lot of parallels
>>to
>>>> an SDIO bus.
>>>>
>>>> When you specify an SDIO bus you don't specify what kind of card
>>will
>>>> be present, you just say "I've got an SDIO bus" and then the
>>specific
>>>> device underneath is probed.  Here we've say "I've got an i2c
>>>> connection intended for HID" and then you probe for the HID device
>>>> that's on the connection.
>>>>
>>>> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
>>>> resets that need to be controlled, but the specific details of these
>>>> regulator / GPIOs / resets are specific to a given board and not
>>>> necessarily a given SDIO device.
>>>>
>>>
>>> Thanks Doug for this. I had the feeling this wasn't right, but you
>>> actually managed to put the words on it. If it's a board problem (if
>>> you switch the wacom device with an other HID over I2C device and you
>>> still need the same regulator/timing parameters), then this should
>>> simply be mentioned on the patch.
>>>
>>> So Brian, could you please respin the series and remve the Wacom
>>> mentions and explain that it is required for the board itself?
>>
>>In advance, NAK.
>>
>>This is not how DT works. Either this binding needs a Wacom compatible
>>or don't use DT.
>>
>
> And if tomorrow there is Elan device that is drop-in compatible (same connector, etc) with Wacom i2c-hid, will you ask for Elan-specific binding? Atmel? Weida? They all need to be powered up ultimately.

Yes, I will. Anyone who's worked on drop-in or pin compatible parts
knows there's no such thing.

That in no way means the OS driver has to know about each and every
one. If they can all claim compatibility with Wacom (including power
control), then they can have a Wacom compatible string too. Or you can
just never tell me that there's a different manufacturer and I won't
care as long you don't need different control. But soon as a device
needs another power rail, GPIO or different timing, then you'd better
have a new compatible string.

Rob

^ permalink raw reply

* Re: [PATCH 1/2] ASoC: Add support for CS43130 codec
From: Mark Brown @ 2016-12-08 16:23 UTC (permalink / raw)
  To: Li Xu
  Cc: alsa-devel-K7yf7f+aM1XWsZ/bQMPhNw,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, robh+dt-DgEjT+Ai2ygdnm+yROfE0A,
	mark.rutland-5wv7dgnIgG8, perex-/Fr2/VpizcU, tiwai-IBi9RG/b67k,
	brian.austin-jGc1dHjMKG3QT0dZR+AlfA,
	Paul.Handrigan-jGc1dHjMKG3QT0dZR+AlfA
In-Reply-To: <09a77398-831b-4be7-9089-f7ac4fcfc16a-k7YZYYsDncjfk+Ne4bZl5AC/G2K4zDHf@public.gmane.org>

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

On Wed, Dec 07, 2016 at 02:17:27PM -0600, Li Xu wrote:

Overall this looks pretty good - there's a fair number of issues below
but they're all fairly simple stylistic things rather than anything
majorly wrong so hopefully should be easy to correct.

>  	select SND_SOC_CS53L30 if I2C
> +	select SND_SOC_CS43130 if I2C
>  	select SND_SOC_CX20442 if TTY

Please keep Kconfig and Makefile sorted.

> +static bool cs43130_volatile_register(struct device *dev, unsigned int reg)
> +{
> +	switch (reg) {
> +	case CS43130_DEVID_AB ... CS43130_SUBREV_ID:
> +	case CS43130_INT_STATUS_1 ... CS43130_INT_STATUS_5:
> +		return true;

You don't need to mark the device ID volatile, just don't provide
defaults and regmap will cache it the first time it reads it.  If the
device ID is volatile you've got bigger problems.

> +			/*PDN_PLL= 0,enable*/

Please use the standard kernel coding style, need spaces here.

> +			regmap_update_bits(cs43130->regmap, CS43130_PLL_SET_9,
> +					    CS43130_PLL_REF_PREDIV_MASK,
> +						pll_ratio_table[i].sclk_prediv
> +						);

There's no need for the ); to be on a new line here, nor for the extra
indentation on the line before.  There are lots more coding style
issues, checkpatch will probably pick up many of them.

> +	case SND_SOC_DAPM_PRE_PMU:
> +		if (cs43130->pll_bypass)
> +			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_XTAL);
> +		else
> +			cs43130_change_clksrc(codec, CS43130_MCLK_SRC_PLL);
> +
> +		usleep_range(10000, 10050);
> +		/*ASP_3ST = 0 in master mode*/
> +		if (cs43130->dai_mode)
> +			regmap_update_bits(cs43130->regmap, CS43130_PAD_INT_CFG,
> +						    0x01, 0x00);

No need to undo this in slave mode?

> +	if (stickies[0] & CS43130_XTAL_ERR_INT)
> +		pr_debug("%s: Crystal err\n", __func__);

dev_ prints and shouldn't this one be an error?

> +	/* Enable HP detect */
> +	regmap_update_bits(cs43130->regmap, CS43130_HP_DETECT,
> +		CS43130_HP_DETECT_CTRL_MASK, CS43130_HP_DETECT_CTRL_MASK);

Why enable this when the only handling is a couple of log messages?

> +#ifdef CONFIG_PM
> +static int cs43130_runtime_suspend(struct device *dev)
> +{
> +	return 0;
> +}

Remove empty functions, they don't serve any purpose.

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

^ permalink raw reply

* Re: [PATCH v4 2/2] mmc: sdhci-cadence: add Cadence SD4HC support
From: Masahiro Yamada @ 2016-12-08 16:16 UTC (permalink / raw)
  To: Ulf Hansson
  Cc: linux-mmc@vger.kernel.org, Adrian Hunter, Douglas Anderson,
	devicetree@vger.kernel.org, Al Cooper,
	linux-kernel@vger.kernel.org, Stefan Wahren, Rob Herring,
	Andrei Pistirica, Wolfram Sang, Joshua Henderson, Mark Rutland,
	Simon Horman, Eric Anholt
In-Reply-To: <CAPDyKFpFmBnydazS0pYOYajN1-QOiw=Sxid6Uuxn8z4RMVO3KA@mail.gmail.com>

Hi Ulf,

2016-12-08 23:05 GMT+09:00 Ulf Hansson <ulf.hansson@linaro.org>:
> On 8 December 2016 at 13:52, Masahiro Yamada
> <yamada.masahiro@socionext.com> wrote:
>> Hi Ulf,
>>
>> 2016-12-08 21:32 GMT+09:00 Ulf Hansson <ulf.hansson@linaro.org>:
>>> On 5 December 2016 at 03:10, Masahiro Yamada
>>> <yamada.masahiro@socionext.com> wrote:
>>>> Add a driver for the Cadence SD4HC SD/SDIO/eMMC Controller.
>>>>
>>>> For SD, it basically relies on the SDHCI standard code.
>>>> For eMMC, this driver provides some callbacks to support the
>>>> hardware part that is specific to this IP design.
>>>>
>>>> Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
>>>
>>> Thanks, applied for next!
>>>
>>
>>
>> Very sorry for my fix at the last minute.
>>
>> I've just posted v5.
>>
>> Please make sure to apply v5.
>
> Okay, I have replaced v4 with v5.
>
> Perhaps you should have a look at my next branch to make sure it's all okay.
>


Yes. Everything looks fine.

Thank you!


-- 
Best Regards
Masahiro Yamada

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Dmitry Torokhov @ 2016-12-08 16:13 UTC (permalink / raw)
  To: Rob Herring, Benjamin Tissoires
  Cc: Doug Anderson, Brian Norris, Jiri Kosina, Caesar Wang,
	open list:ARM/Rockchip SoC..., linux-input@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	Mark Rutland
In-Reply-To: <CAL_Jsq+fdoFnarXYkPv6FjVue3v31ry-Ddfkq9fQk9Ek+AjETw@mail.gmail.com>

On December 8, 2016 8:03:06 AM PST, Rob Herring <robh@kernel.org> wrote:
>On Thu, Dec 8, 2016 at 9:41 AM, Benjamin Tissoires
><benjamin.tissoires@redhat.com> wrote:
>> On Dec 06 2016 or thereabouts, Doug Anderson wrote:
>>> Hi,
>>>
>>> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh@kernel.org> wrote:
>>> > On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
>>> > <benjamin.tissoires@redhat.com> wrote:
>>> >> On Dec 05 2016 or thereabouts, Rob Herring wrote:
>>> >>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
>>> >>> > Hi Benjamin and Rob,
>>> >>> >
>>> >>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires
>wrote:
>>> >>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
>>> >>> > > > From: Caesar Wang <wxt@rock-chips.com>
>>> >>> > > >
>>> >>> > > > Add a compatible string and regulator property for Wacom
>W9103
>>> >>> > > > digitizer. Its VDD supply may need to be enabled before
>using it.
>>> >>> > > >
>>> >>> > > > Signed-off-by: Caesar Wang <wxt@rock-chips.com>
>>> >>> > > > Cc: Rob Herring <robh+dt@kernel.org>
>>> >>> > > > Cc: Jiri Kosina <jikos@kernel.org>
>>> >>> > > > Cc: linux-input@vger.kernel.org
>>> >>> > > > Signed-off-by: Brian Norris <briannorris@chromium.org>
>>> >>> > > > ---
>>> >>> > > > v1 was a few months back. I finally got around to
>rewriting it based on
>>> >>> > > > DT binding feedback.
>>> >>> > > >
>>> >>> > > > v2:
>>> >>> > > >  * add compatible property for wacom
>>> >>> > > >  * name the regulator property specifically (VDD)
>>> >>> > > >
>>> >>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt
>| 6 +++++-
>>> >>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
>>> >>> > > >
>>> >>> > > > diff --git
>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>> >>> > > > index 488edcb264c4..eb98054e60c9 100644
>>> >>> > > > ---
>a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>> >>> > > > +++
>b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>> >>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel
>module i2c-hid will handle the communication
>>> >>> > > >  with the device and the generic hid core layer will
>handle the protocol.
>>> >>> > > >
>>> >>> > > >  Required properties:
>>> >>> > > > -- compatible: must be "hid-over-i2c"
>>> >>> > > > +- compatible: must be "hid-over-i2c", or a
>device-specific string like:
>>> >>> > > > +    * "wacom,w9013"
>>> >>> > >
>>> >>> > > NACK on this one.
>>> >>> > >
>>> >>> > > After re-reading the v1 submission I realized Rob asked for
>this change,
>>> >>> > > but I strongly disagree.
>>> >>> > >
>>> >>> > > HID over I2C is a generic protocol, in the same way HID over
>USB is. We
>>> >>> > > can not start adding device specifics here, this is opening
>the can of
>>> >>> > > worms. If the device is a HID one, nothing else should
>matter. The rest
>>> >>> > > (description of the device, name, etc...) is all provided by
>the
>>> >>> > > protocol.
>>> >>> >
>>> >>> > I should have spoken up when Rob made the suggestion, because
>I more or
>>> >>> > less agree with Benjamin here. I don't really see why this
>needs to have
>>> >>> > a specialized compatible string, as the property is still
>fairly
>>> >>> > generic, and the entire device handling is via a generic
>protocol. The
>>> >>> > fact that we manage its power via a regulator is not very
>>> >>> > device-specific.
>>> >>>
>>> >>> It doesn't matter that the protocol is generic. The device
>attached and
>>> >>> the implementation is not. Implementations have been known to
>have
>>> >>> bugs/quirks (generally speaking, not HID over I2C in
>particular). There
>>> >>> are also things outside the scope of what is 'hid-over-i2c' like
>what's
>>> >>> needed to power-on the device which this patch clearly show.
>>> >>
>>> >> Yes, there are bugs, quirks, even with HID. But the HID declares
>within
>>> >> the protocol the Vendor ID and the Product ID, which means once
>we pass
>>> >> the initial "device is ready" step and can do a single i2c
>write/read,
>>> >> we don't give a crap about device tree anymore.
>>> >>
>>> >> This is just about setting the device in shape so that it can
>answer a
>>> >> single write/read.
>>> >>
>>> >>>
>>> >>> This is no different than a panel attached via LVDS, eDP, etc.,
>or
>>> >>> USB/PCIe device hard-wired on a board. They all use standard
>protocols
>>> >>> and all need additional data to describe them. Of course, adding
>a
>>> >>> single property for a delay would not be a big deal, but it's
>never
>>> >>> ending. Next you need multiple supplies, GPIO controls, mutiple
>>> >>> delays... This has been discussed to death already. As Thierry
>Reding
>>> >>> said, you're not special[1].
>>> >>
>>> >> I can somewhat understand what you mean. The official
>specification is
>>> >> for ACPI. And ACPI allows to calls various settings while
>querying the
>>> >> _STA method for instance. So in the ACPI world, we don't need to
>care
>>> >> about regulators or GPIOs because the OEM deals with this in its
>own
>>> >> blob.
>>> >>
>>> >> Now, coming back to our issue. We are not special, maybe, if he
>says so.
>>> >> But this really feels like a design choice between putting the
>burden on
>>> >> device tree and OEMs or in the module maintainers. And I'd rather
>have
>>> >> the OEM deal with their device than me having to update the
>module for
>>> >> each generations of hardware. Indeed, this looks like an
>"endless"
>>> >> amount of quirks, but I'd rather have this endless amount of
>quirks than
>>> >> having to maintain an endless amount of list of new devices that
>behaves
>>> >> the same way. We are talking here about "wacom,w9013", but then
>comes
>>> >> "wacom,w9014" and we need to upgrade the kernel.
>>> >
>>> > No. If the w9014 can claim compatibility with then w9013, then you
>>> > don't need a kernel change. The DT should list the w9014 AND
>w9013,
>>> > but the kernel only needs to know about the w9013. That is until
>there
>>> > is some difference which is why the DT should list w9014 to start
>>> > with.
>>> >
>>> > If you don't have any power control to deal with, then the kernel
>can
>>> > always just match on "hid-over-i2c" compatible.
>>>
>>> Just my $0.02.  Feel free to ignore.
>>>
>>> One thought is that I would say that the need to power on the device
>>> explicitly seems more like a board level difference and less like a
>>> difference associated with a particular digitizer.  Said another
>way,
>>> it seems likely there will be boards with a w9013 without explicit
>>> control of the regulator in software and it seems like there will be
>>> boards with other digitizers where suddenly a new board will come
>out
>>> that needs explicit control of the regulator.
>>>
>>> In this particular case I feel like we can draw a lot of parallels
>to
>>> an SDIO bus.
>>>
>>> When you specify an SDIO bus you don't specify what kind of card
>will
>>> be present, you just say "I've got an SDIO bus" and then the
>specific
>>> device underneath is probed.  Here we've say "I've got an i2c
>>> connection intended for HID" and then you probe for the HID device
>>> that's on the connection.
>>>
>>> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
>>> resets that need to be controlled, but the specific details of these
>>> regulator / GPIOs / resets are specific to a given board and not
>>> necessarily a given SDIO device.
>>>
>>
>> Thanks Doug for this. I had the feeling this wasn't right, but you
>> actually managed to put the words on it. If it's a board problem (if
>> you switch the wacom device with an other HID over I2C device and you
>> still need the same regulator/timing parameters), then this should
>> simply be mentioned on the patch.
>>
>> So Brian, could you please respin the series and remve the Wacom
>> mentions and explain that it is required for the board itself?
>
>In advance, NAK.
>
>This is not how DT works. Either this binding needs a Wacom compatible
>or don't use DT.
>

And if tomorrow there is Elan device that is drop-in compatible (same connector, etc) with Wacom i2c-hid, will you ask for Elan-specific binding? Atmel? Weida? They all need to be powered up ultimately.


Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] PM / Domains: Fix compatible for domain idle state
From: Rob Herring @ 2016-12-08 16:07 UTC (permalink / raw)
  To: Rafael J. Wysocki
  Cc: Ulf Hansson, Lina Iyer, Kevin Hilman, linux-pm@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org, Andy Gross, Stephen Boyd,
	linux-arm-msm@vger.kernel.org, Brendan Jackman, Lorenzo Pieralisi,
	Sudeep Holla, Juri Lelli, devicetree@vger.kernel.org
In-Reply-To: <1526421.aCsca4sLnR@aspire.rjw.lan>

On Wed, Dec 7, 2016 at 6:13 PM, Rafael J. Wysocki <rjw@rjwysocki.net> wrote:
> On Thursday, December 01, 2016 10:21:59 PM Rafael J. Wysocki wrote:
>> On Tuesday, November 29, 2016 09:47:03 AM Ulf Hansson wrote:
>> > On 10 November 2016 at 20:58, Rob Herring <robh@kernel.org> wrote:
>> > > On Mon, Nov 07, 2016 at 12:14:28PM +0100, Ulf Hansson wrote:
>> > >> On 3 November 2016 at 22:54, Lina Iyer <lina.iyer@linaro.org> wrote:
>> > >> > Re-using idle state definition provided by arm,idle-state for domain
>> > >> > idle states creates a lot of confusion and limits further evolution of
>> > >> > the domain idle definition. To keep things clear and simple, define a
>> > >> > idle states for domain using a new compatible "domain-idle-state".
>> > >> >
>> > >> > Fix existing PM domains code to look for the newly defined compatible.
>> > >> >
>> > >> > Cc: <devicetree@vger.kernel.org>
>> > >> > Cc: Rob Herring <robh@kernel.org>
>> > >> > Signed-off-by: Lina Iyer <lina.iyer@linaro.org>
>> > >> > ---
>> > >> >  .../bindings/power/domain-idle-state.txt           | 33 ++++++++++++++++++++++
>> > >> >  .../devicetree/bindings/power/power_domain.txt     |  8 +++---
>> > >> >  drivers/base/power/domain.c                        |  2 +-
>> > >> >  3 files changed, 38 insertions(+), 5 deletions(-)
>> > >> >  create mode 100644 Documentation/devicetree/bindings/power/domain-idle-state.txt
>> > >> >
>> > >> > diff --git a/Documentation/devicetree/bindings/power/domain-idle-state.txt b/Documentation/devicetree/bindings/power/domain-idle-state.txt
>> > >> > new file mode 100644
>> > >> > index 0000000..eefc7ed
>> > >> > --- /dev/null
>> > >> > +++ b/Documentation/devicetree/bindings/power/domain-idle-state.txt
>> > >> > @@ -0,0 +1,33 @@
>> > >> > +PM Domain Idle State Node:
>> > >> > +
>> > >> > +A domain idle state node represents the state parameters that will be used to
>> > >> > +select the state when there are no active components in the domain.
>> > >> > +
>> > >> > +The state node has the following parameters -
>> > >> > +
>> > >> > +- compatible:
>> > >> > +       Usage: Required
>> > >> > +       Value type: <string>
>> > >> > +       Definition: Must be "domain-idle-state".
>> > >> > +
>> > >> > +- entry-latency-us
>> > >> > +       Usage: Required
>> > >> > +       Value type: <prop-encoded-array>
>> > >> > +       Definition: u32 value representing worst case latency in
>> > >> > +                   microseconds required to enter the idle state.
>> > >> > +                   The exit-latency-us duration may be guaranteed
>> > >> > +                   only after entry-latency-us has passed.
>> > >>
>> > >> As we anyway are going to change this, why not use an u64 and have the
>> > >> value in ns instead of us?
>> > >
>> > > I can't imagine that you would need more resolution or range. For times
>> > > less than 1us, s/w and register access times are going to dominate the
>> > > time.
>> > >
>> > > Unless there is a real need, I'd keep alignment with the existing
>> > > binding.
>> >
>> > Rob, are you fine with this? I thought it would be great to get this
>> > in for 4.10 rc1.
>>
>> Rob, any objections here?
>
> Well, no objections, so applied.

Sorry, just found my ack sitting in my drafts. Thought I had sent it.

Rob

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Rob Herring @ 2016-12-08 16:03 UTC (permalink / raw)
  To: Benjamin Tissoires
  Cc: Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Brian Norris, Jiri Kosina, Doug Anderson,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	open list:ARM/Rockchip SoC...,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Dmitry Torokhov, Caesar Wang
In-Reply-To: <20161208154145.GA30888-/m+UfqrgI5QNLKR9yMNcA1aTQe2KTcn/@public.gmane.org>

On Thu, Dec 8, 2016 at 9:41 AM, Benjamin Tissoires
<benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> On Dec 06 2016 or thereabouts, Doug Anderson wrote:
>> Hi,
>>
>> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>> > On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
>> > <benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>> >> On Dec 05 2016 or thereabouts, Rob Herring wrote:
>> >>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
>> >>> > Hi Benjamin and Rob,
>> >>> >
>> >>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires wrote:
>> >>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
>> >>> > > > From: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> >>> > > >
>> >>> > > > Add a compatible string and regulator property for Wacom W9103
>> >>> > > > digitizer. Its VDD supply may need to be enabled before using it.
>> >>> > > >
>> >>> > > > Signed-off-by: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>> >>> > > > Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> >>> > > > Cc: Jiri Kosina <jikos-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>> >>> > > > Cc: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>> >>> > > > Signed-off-by: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>> >>> > > > ---
>> >>> > > > v1 was a few months back. I finally got around to rewriting it based on
>> >>> > > > DT binding feedback.
>> >>> > > >
>> >>> > > > v2:
>> >>> > > >  * add compatible property for wacom
>> >>> > > >  * name the regulator property specifically (VDD)
>> >>> > > >
>> >>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt | 6 +++++-
>> >>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
>> >>> > > >
>> >>> > > > diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>> >>> > > > index 488edcb264c4..eb98054e60c9 100644
>> >>> > > > --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>> >>> > > > +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>> >>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel module i2c-hid will handle the communication
>> >>> > > >  with the device and the generic hid core layer will handle the protocol.
>> >>> > > >
>> >>> > > >  Required properties:
>> >>> > > > -- compatible: must be "hid-over-i2c"
>> >>> > > > +- compatible: must be "hid-over-i2c", or a device-specific string like:
>> >>> > > > +    * "wacom,w9013"
>> >>> > >
>> >>> > > NACK on this one.
>> >>> > >
>> >>> > > After re-reading the v1 submission I realized Rob asked for this change,
>> >>> > > but I strongly disagree.
>> >>> > >
>> >>> > > HID over I2C is a generic protocol, in the same way HID over USB is. We
>> >>> > > can not start adding device specifics here, this is opening the can of
>> >>> > > worms. If the device is a HID one, nothing else should matter. The rest
>> >>> > > (description of the device, name, etc...) is all provided by the
>> >>> > > protocol.
>> >>> >
>> >>> > I should have spoken up when Rob made the suggestion, because I more or
>> >>> > less agree with Benjamin here. I don't really see why this needs to have
>> >>> > a specialized compatible string, as the property is still fairly
>> >>> > generic, and the entire device handling is via a generic protocol. The
>> >>> > fact that we manage its power via a regulator is not very
>> >>> > device-specific.
>> >>>
>> >>> It doesn't matter that the protocol is generic. The device attached and
>> >>> the implementation is not. Implementations have been known to have
>> >>> bugs/quirks (generally speaking, not HID over I2C in particular). There
>> >>> are also things outside the scope of what is 'hid-over-i2c' like what's
>> >>> needed to power-on the device which this patch clearly show.
>> >>
>> >> Yes, there are bugs, quirks, even with HID. But the HID declares within
>> >> the protocol the Vendor ID and the Product ID, which means once we pass
>> >> the initial "device is ready" step and can do a single i2c write/read,
>> >> we don't give a crap about device tree anymore.
>> >>
>> >> This is just about setting the device in shape so that it can answer a
>> >> single write/read.
>> >>
>> >>>
>> >>> This is no different than a panel attached via LVDS, eDP, etc., or
>> >>> USB/PCIe device hard-wired on a board. They all use standard protocols
>> >>> and all need additional data to describe them. Of course, adding a
>> >>> single property for a delay would not be a big deal, but it's never
>> >>> ending. Next you need multiple supplies, GPIO controls, mutiple
>> >>> delays... This has been discussed to death already. As Thierry Reding
>> >>> said, you're not special[1].
>> >>
>> >> I can somewhat understand what you mean. The official specification is
>> >> for ACPI. And ACPI allows to calls various settings while querying the
>> >> _STA method for instance. So in the ACPI world, we don't need to care
>> >> about regulators or GPIOs because the OEM deals with this in its own
>> >> blob.
>> >>
>> >> Now, coming back to our issue. We are not special, maybe, if he says so.
>> >> But this really feels like a design choice between putting the burden on
>> >> device tree and OEMs or in the module maintainers. And I'd rather have
>> >> the OEM deal with their device than me having to update the module for
>> >> each generations of hardware. Indeed, this looks like an "endless"
>> >> amount of quirks, but I'd rather have this endless amount of quirks than
>> >> having to maintain an endless amount of list of new devices that behaves
>> >> the same way. We are talking here about "wacom,w9013", but then comes
>> >> "wacom,w9014" and we need to upgrade the kernel.
>> >
>> > No. If the w9014 can claim compatibility with then w9013, then you
>> > don't need a kernel change. The DT should list the w9014 AND w9013,
>> > but the kernel only needs to know about the w9013. That is until there
>> > is some difference which is why the DT should list w9014 to start
>> > with.
>> >
>> > If you don't have any power control to deal with, then the kernel can
>> > always just match on "hid-over-i2c" compatible.
>>
>> Just my $0.02.  Feel free to ignore.
>>
>> One thought is that I would say that the need to power on the device
>> explicitly seems more like a board level difference and less like a
>> difference associated with a particular digitizer.  Said another way,
>> it seems likely there will be boards with a w9013 without explicit
>> control of the regulator in software and it seems like there will be
>> boards with other digitizers where suddenly a new board will come out
>> that needs explicit control of the regulator.
>>
>> In this particular case I feel like we can draw a lot of parallels to
>> an SDIO bus.
>>
>> When you specify an SDIO bus you don't specify what kind of card will
>> be present, you just say "I've got an SDIO bus" and then the specific
>> device underneath is probed.  Here we've say "I've got an i2c
>> connection intended for HID" and then you probe for the HID device
>> that's on the connection.
>>
>> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
>> resets that need to be controlled, but the specific details of these
>> regulator / GPIOs / resets are specific to a given board and not
>> necessarily a given SDIO device.
>>
>
> Thanks Doug for this. I had the feeling this wasn't right, but you
> actually managed to put the words on it. If it's a board problem (if
> you switch the wacom device with an other HID over I2C device and you
> still need the same regulator/timing parameters), then this should
> simply be mentioned on the patch.
>
> So Brian, could you please respin the series and remve the Wacom
> mentions and explain that it is required for the board itself?

In advance, NAK.

This is not how DT works. Either this binding needs a Wacom compatible
or don't use DT.

Rob

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Rob Herring @ 2016-12-08 16:01 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Benjamin Tissoires, Brian Norris, Jiri Kosina, Caesar Wang,
	open list:ARM/Rockchip SoC...,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Dmitry Torokhov, Mark Rutland
In-Reply-To: <CAD=FV=UMonRe8WJ1feDv3Nh9g8hEGAwwFT5NYLbzXADBqhTf-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Tue, Dec 6, 2016 at 10:18 AM, Doug Anderson <dianders-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org> wrote:
> Hi,
>
> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
>> On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
>> <benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
>>> On Dec 05 2016 or thereabouts, Rob Herring wrote:
>>>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
>>>> > Hi Benjamin and Rob,
>>>> >
>>>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires wrote:
>>>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
>>>> > > > From: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>>> > > >
>>>> > > > Add a compatible string and regulator property for Wacom W9103
>>>> > > > digitizer. Its VDD supply may need to be enabled before using it.
>>>> > > >
>>>> > > > Signed-off-by: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
>>>> > > > Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>>> > > > Cc: Jiri Kosina <jikos-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>>>> > > > Cc: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
>>>> > > > Signed-off-by: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
>>>> > > > ---
>>>> > > > v1 was a few months back. I finally got around to rewriting it based on
>>>> > > > DT binding feedback.
>>>> > > >
>>>> > > > v2:
>>>> > > >  * add compatible property for wacom
>>>> > > >  * name the regulator property specifically (VDD)
>>>> > > >
>>>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt | 6 +++++-
>>>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
>>>> > > >
>>>> > > > diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> > > > index 488edcb264c4..eb98054e60c9 100644
>>>> > > > --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> > > > +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
>>>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel module i2c-hid will handle the communication
>>>> > > >  with the device and the generic hid core layer will handle the protocol.
>>>> > > >
>>>> > > >  Required properties:
>>>> > > > -- compatible: must be "hid-over-i2c"
>>>> > > > +- compatible: must be "hid-over-i2c", or a device-specific string like:
>>>> > > > +    * "wacom,w9013"
>>>> > >
>>>> > > NACK on this one.
>>>> > >
>>>> > > After re-reading the v1 submission I realized Rob asked for this change,
>>>> > > but I strongly disagree.
>>>> > >
>>>> > > HID over I2C is a generic protocol, in the same way HID over USB is. We
>>>> > > can not start adding device specifics here, this is opening the can of
>>>> > > worms. If the device is a HID one, nothing else should matter. The rest
>>>> > > (description of the device, name, etc...) is all provided by the
>>>> > > protocol.
>>>> >
>>>> > I should have spoken up when Rob made the suggestion, because I more or
>>>> > less agree with Benjamin here. I don't really see why this needs to have
>>>> > a specialized compatible string, as the property is still fairly
>>>> > generic, and the entire device handling is via a generic protocol. The
>>>> > fact that we manage its power via a regulator is not very
>>>> > device-specific.
>>>>
>>>> It doesn't matter that the protocol is generic. The device attached and
>>>> the implementation is not. Implementations have been known to have
>>>> bugs/quirks (generally speaking, not HID over I2C in particular). There
>>>> are also things outside the scope of what is 'hid-over-i2c' like what's
>>>> needed to power-on the device which this patch clearly show.
>>>
>>> Yes, there are bugs, quirks, even with HID. But the HID declares within
>>> the protocol the Vendor ID and the Product ID, which means once we pass
>>> the initial "device is ready" step and can do a single i2c write/read,
>>> we don't give a crap about device tree anymore.
>>>
>>> This is just about setting the device in shape so that it can answer a
>>> single write/read.
>>>
>>>>
>>>> This is no different than a panel attached via LVDS, eDP, etc., or
>>>> USB/PCIe device hard-wired on a board. They all use standard protocols
>>>> and all need additional data to describe them. Of course, adding a
>>>> single property for a delay would not be a big deal, but it's never
>>>> ending. Next you need multiple supplies, GPIO controls, mutiple
>>>> delays... This has been discussed to death already. As Thierry Reding
>>>> said, you're not special[1].
>>>
>>> I can somewhat understand what you mean. The official specification is
>>> for ACPI. And ACPI allows to calls various settings while querying the
>>> _STA method for instance. So in the ACPI world, we don't need to care
>>> about regulators or GPIOs because the OEM deals with this in its own
>>> blob.
>>>
>>> Now, coming back to our issue. We are not special, maybe, if he says so.
>>> But this really feels like a design choice between putting the burden on
>>> device tree and OEMs or in the module maintainers. And I'd rather have
>>> the OEM deal with their device than me having to update the module for
>>> each generations of hardware. Indeed, this looks like an "endless"
>>> amount of quirks, but I'd rather have this endless amount of quirks than
>>> having to maintain an endless amount of list of new devices that behaves
>>> the same way. We are talking here about "wacom,w9013", but then comes
>>> "wacom,w9014" and we need to upgrade the kernel.
>>
>> No. If the w9014 can claim compatibility with then w9013, then you
>> don't need a kernel change. The DT should list the w9014 AND w9013,
>> but the kernel only needs to know about the w9013. That is until there
>> is some difference which is why the DT should list w9014 to start
>> with.
>>
>> If you don't have any power control to deal with, then the kernel can
>> always just match on "hid-over-i2c" compatible.
>
> Just my $0.02.  Feel free to ignore.
>
> One thought is that I would say that the need to power on the device
> explicitly seems more like a board level difference and less like a
> difference associated with a particular digitizer.  Said another way,
> it seems likely there will be boards with a w9013 without explicit
> control of the regulator in software and it seems like there will be
> boards with other digitizers where suddenly a new board will come out
> that needs explicit control of the regulator.

Then either the regulator is optional or you don't say it is a w9013
for that board. But if you do need to initialize the device and
therefore know what type of device it is, then you need a compatible
for the device. It's when things really vary by board that we add DT
properties.

> In this particular case I feel like we can draw a lot of parallels to
> an SDIO bus.
>
> When you specify an SDIO bus you don't specify what kind of card will
> be present, you just say "I've got an SDIO bus" and then the specific
> device underneath is probed.  Here we've say "I've got an i2c
> connection intended for HID" and then you probe for the HID device
> that's on the connection.

No, the soldered down devices require all sorts of extra non-SDIO
connections and we do specify the device in those cases.

> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
> resets that need to be controlled, but the specific details of these
> regulator / GPIOs / resets are specific to a given board and not
> necessarily a given SDIO device.

It's both. The device defines what is needed and the specs to control
them (active states of GPIOs, de/assertion times of resets, supply
voltages, etc.). The board only determines what the connections are
and if you can control them.

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

^ permalink raw reply

* Re: [PATCH] i2c: rk3x: keep i2c irq ON in suspend
From: David.Wu @ 2016-12-08 15:50 UTC (permalink / raw)
  To: Grygorii Strashko, Doug Anderson
  Cc: Heiko Stuebner, Wolfram Sang,
	linux-arm-kernel@lists.infradead.org,
	open list:ARM/Rockchip SoC..., linux-i2c@vger.kernel.org,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <e34bab0d-b4b1-ff0d-3a27-c3701b8206c1@ti.com>

Hi Grygorii, Doug and Heiko,

Thanks for your replies.
I will do 2 steps:

1. Add "suspended" flag in suspend_noirq()/resume_noirq() callback to 
prevent new i2c started, and use i2c_lock_adapter() to wait for current 
i2c transfer finished.

2. IRQF_NO_SUSPEND added could make i2c work well during the time 
between suspend_device_irqs() and i2c_suspend_noirq() callback. In the 
other side, it is the the time between resume_device_irqs() and 
i2c_resume_noirq() callback.

If any i2c client try to access I2C after suspend_noirq() or before 
resume_noirq() callback, print the warning, and they should fix it, not 
to start i2c access and the moment.

在 2016/12/8 0:27, Grygorii Strashko 写道:
>
>
> On 12/06/2016 09:37 PM, David.Wu wrote:
>> Hi Doug,
>>
>> 在 2016/12/7 0:31, Doug Anderson 写道:
>>> Hi,
>>>
>>> On Tue, Dec 6, 2016 at 12:12 AM, David.Wu <david.wu@rock-chips.com>
>>> wrote:
>>>> Hi Heiko,
>>>>
>>>> 在 2016/12/5 18:54, Heiko Stuebner 写道:
>>>>>
>>>>> Hi David,
>>>>>
>>>>> Am Montag, 5. Dezember 2016, 16:02:59 CET schrieb David Wu:
>>>>>>
>>>>>> During suspend there may still be some i2c access happening.
>>>>>> And if we don't keep i2c irq ON, there may be i2c access timeout if
>>>>>> i2c is in irq mode of operation.
>>>>>
>>>>>
>>>>> can you describe the issue you're trying to fix a bit more please?
>>>>
>>>>
>>>> Sometimes we could see the i2c timeout errors during suspend/resume,
>>>> which
>>>> makes the duration of suspend/resume too longer.
>>>>
>>>> [  484.171541] CPU4: Booted secondary processor [410fd082]
>>>> [  485.172777] rk3x-i2c ff3c0000.i2c: timeout, ipd: 0x10, state: 1
>>>> [  486.172760] rk3x-i2c ff3c0000.i2c: timeout, ipd: 0x10, state: 1
>>>> [  487.172759] rk3x-i2c ff3c0000.i2c: timeout, ipd: 0x10, state: 1
>>>> [  487.172840] cpu cpu4: _set_opp_voltage: failed to set voltage (800000
>>>> 800000 800000 mV): -110
>>>> [  487.172874] cpu cpu4: failed to set volt 800000
>>>>
>>>>>
>>>>> I.e. I'd think the i2c-core does suspend i2c-client devices first,
>>>>> so that
>>>>> these should be able to finish up their ongoing transfers and not start
>>>>> any
>>>>> new ones instead?
>>>>>
>>>>> Your irq can still happen slightly after the system started going to
>>>>> actually
>>>>> sleep, so to me it looks like you just widened the window where irqs
>>>>> can
>>>>> be
>>>>> handled. Especially as your irq could also just simply stem from the
>>>>> start
>>>>> state, so you cannot even be sure if your transaction actually is
>>>>> finished.
>>>>
>>>>
>>>> Okay, you are right. I want to give it a double insurance at first,
>>>> but it
>>>> may hide the unhappend issue.
>>>>
>>>>>
>>>>> So to me it looks like the i2c-connected device driver should be fixed
>>>>> instead?
>>>>
>>>>
>>>> I tell them to fix it in rk808 driver.
>>>
>>> To me it seems like perhaps cpufreq should not be changing frequencies
>>> until it is resumed properly.  Presumably if all the ordering is done
>>> right then cpufreq should be resumed _after_ the i2c regulator so you
>>> should be OK.  ...or am I somehow confused about that?
>>
>> yes,the cpufreq and regulator should start i2c job after they resume
>> properly.
>>
>>>
>>> Also note that previous i2c busses I worked with simply returned -EIO
>>> in the case where they were called when suspended.  See
>>> "i2c-exynos5.c" and "i2c-s3c2410.c".
>>
>> In "i2c-exynos5.c", it seems that using the "i2c->suspended" to protect
>> i2c transfer works most of the time. Of course it could prevent the next
>> new i2c transfer to start. But in one case, if the current i2c job was
>> not finished until the i2c irq was disabled by system suspend, the i2c
>> timeout error would also happen, as the current i2c job may have a large
>> data to transfer and it lasts from a long time.
>
> And this means you have bug in some of I2C client drivers which do not stop
> their activities during suspend properly (most usual case - driver uses work
> and this work still active during suspend and can run on one CPU while suspend
> runs on another).
>
> At the moment .suspend_noirq() callback is called there should be no active
> I2C transactions in general.
>
>>
>> So is it necessary to add a mutex lock to wait the current job to be
>> finished before the "i2c->suspended" is changed in i2c_suspend_noirq()?
>>
>
> You need to catch and fix all driver who will try to access I2C after your
> I2C bus driver passes suspend_noirq stage. Smth, like [1], uses i2c_lock_adapter().
>
>
> [1] https://git.ti.com/android-sdk/kernel-omap/commit/125ef8f7016e7b205886f93862288a45a312b1d8
>

^ permalink raw reply

* Re: [PATCH 1/2] Documentation: sample averaging for imx6ul_tsc
From: Rob Herring @ 2016-12-08 15:45 UTC (permalink / raw)
  To: Guy Shapiro
  Cc: Fabio Estevam, Mark Rutland, devicetree@vger.kernel.org,
	Haibo Chen, Dmitry Torokhov, linux-input@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <82b04890-692d-4e22-36c1-a21affad5126@mobi-wize.com>

On Thu, Dec 8, 2016 at 9:15 AM, Guy Shapiro <guy.shapiro@mobi-wize.com> wrote:
> On 01/12/2016 18:13, Rob Herring wrote:
>>
>> On Sun, Nov 27, 2016 at 09:44:57AM +0200, Guy Shapiro wrote:
>>>
>>> The i.MX6UL internal touchscreen controller contains an option to
>>> average upon samples. This feature reduces noise from the produced
>>> touch locations.
>>>
>>> This patch introduces a new device tree optional property for this
>>> feature. It provides control over the amount of averaged samples per
>>> touch event.
>>>
>>> The property was inspired by a similar property on the
>>> "brcm,iproc-touchscreen" binding.
>>>
>>> Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
>>> ---
>>>   .../devicetree/bindings/input/touchscreen/imx6ul_tsc.txt          | 8
>>
>> ++++++++
>>>
>>>   1 file changed, 8 insertions(+)
>>>
>>> diff --git
>>
>> a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>> b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>>>
>>> index 853dff9..a66069f 100644
>>> --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>>> +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>>> @@ -17,6 +17,13 @@ Optional properties:
>>>     This value depends on the touch screen.
>>>   - pre-charge-time: the touch screen need some time to precharge.
>>>     This value depends on the touch screen.
>>> +- average-samples: Number of data samples which are averaged for each
>>
>> read.
>>>
>>> +       Valid values 0-4
>>> +       0 =  1 sample
>>> +       1 =  4 samples
>>> +       2 =  8 samples
>>> +       3 = 16 samples
>>> +       4 = 32 samples
>>
>> Either this needs a vendor prefix or should be documented as a generic
>> property. In the latter case, you should use actual number of samples
>> (1-32) for the values.
>
> In the term "generic property", do you mean to document it on
> bindings/input/touchscreen/touchscreen.txt ?

Yes.

> If so, should I add the "touchscreen-" prefix like all the other properties
> in that file?

Yes.

> Grepping bindings/input/touchscreen/, I found two other device drivers that
> implement a
> similar property - "ti-tsc-adc" and "brcm,iproc-touchscreen" (The latter,
> BTW, uses a non
> vendor prefixed property name).

Unfortunately, the brcm one doesn't look directly usable.

> Do we want to move from per-vendor properties to a generic one?

No. Those are set already. I just don't want to get more vendor properties.

Rob

^ permalink raw reply

* Re: [PATCH v2 1/2] devicetree: i2c-hid: Add Wacom digitizer + regulator support
From: Benjamin Tissoires @ 2016-12-08 15:41 UTC (permalink / raw)
  To: Doug Anderson
  Cc: Rob Herring, Brian Norris, Jiri Kosina, Caesar Wang,
	open list:ARM/Rockchip SoC...,
	linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	Dmitry Torokhov, Mark Rutland
In-Reply-To: <CAD=FV=UMonRe8WJ1feDv3Nh9g8hEGAwwFT5NYLbzXADBqhTf-A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Dec 06 2016 or thereabouts, Doug Anderson wrote:
> Hi,
> 
> On Tue, Dec 6, 2016 at 6:56 AM, Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> wrote:
> > On Tue, Dec 6, 2016 at 2:48 AM, Benjamin Tissoires
> > <benjamin.tissoires-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org> wrote:
> >> On Dec 05 2016 or thereabouts, Rob Herring wrote:
> >>> On Thu, Dec 01, 2016 at 09:24:50AM -0800, Brian Norris wrote:
> >>> > Hi Benjamin and Rob,
> >>> >
> >>> > On Thu, Dec 01, 2016 at 03:34:34PM +0100, Benjamin Tissoires wrote:
> >>> > > On Nov 30 2016 or thereabouts, Brian Norris wrote:
> >>> > > > From: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> >>> > > >
> >>> > > > Add a compatible string and regulator property for Wacom W9103
> >>> > > > digitizer. Its VDD supply may need to be enabled before using it.
> >>> > > >
> >>> > > > Signed-off-by: Caesar Wang <wxt-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
> >>> > > > Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>> > > > Cc: Jiri Kosina <jikos-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> >>> > > > Cc: linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> >>> > > > Signed-off-by: Brian Norris <briannorris-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
> >>> > > > ---
> >>> > > > v1 was a few months back. I finally got around to rewriting it based on
> >>> > > > DT binding feedback.
> >>> > > >
> >>> > > > v2:
> >>> > > >  * add compatible property for wacom
> >>> > > >  * name the regulator property specifically (VDD)
> >>> > > >
> >>> > > >  Documentation/devicetree/bindings/input/hid-over-i2c.txt | 6 +++++-
> >>> > > >  1 file changed, 5 insertions(+), 1 deletion(-)
> >>> > > >
> >>> > > > diff --git a/Documentation/devicetree/bindings/input/hid-over-i2c.txt b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>> > > > index 488edcb264c4..eb98054e60c9 100644
> >>> > > > --- a/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>> > > > +++ b/Documentation/devicetree/bindings/input/hid-over-i2c.txt
> >>> > > > @@ -11,12 +11,16 @@ If this binding is used, the kernel module i2c-hid will handle the communication
> >>> > > >  with the device and the generic hid core layer will handle the protocol.
> >>> > > >
> >>> > > >  Required properties:
> >>> > > > -- compatible: must be "hid-over-i2c"
> >>> > > > +- compatible: must be "hid-over-i2c", or a device-specific string like:
> >>> > > > +    * "wacom,w9013"
> >>> > >
> >>> > > NACK on this one.
> >>> > >
> >>> > > After re-reading the v1 submission I realized Rob asked for this change,
> >>> > > but I strongly disagree.
> >>> > >
> >>> > > HID over I2C is a generic protocol, in the same way HID over USB is. We
> >>> > > can not start adding device specifics here, this is opening the can of
> >>> > > worms. If the device is a HID one, nothing else should matter. The rest
> >>> > > (description of the device, name, etc...) is all provided by the
> >>> > > protocol.
> >>> >
> >>> > I should have spoken up when Rob made the suggestion, because I more or
> >>> > less agree with Benjamin here. I don't really see why this needs to have
> >>> > a specialized compatible string, as the property is still fairly
> >>> > generic, and the entire device handling is via a generic protocol. The
> >>> > fact that we manage its power via a regulator is not very
> >>> > device-specific.
> >>>
> >>> It doesn't matter that the protocol is generic. The device attached and
> >>> the implementation is not. Implementations have been known to have
> >>> bugs/quirks (generally speaking, not HID over I2C in particular). There
> >>> are also things outside the scope of what is 'hid-over-i2c' like what's
> >>> needed to power-on the device which this patch clearly show.
> >>
> >> Yes, there are bugs, quirks, even with HID. But the HID declares within
> >> the protocol the Vendor ID and the Product ID, which means once we pass
> >> the initial "device is ready" step and can do a single i2c write/read,
> >> we don't give a crap about device tree anymore.
> >>
> >> This is just about setting the device in shape so that it can answer a
> >> single write/read.
> >>
> >>>
> >>> This is no different than a panel attached via LVDS, eDP, etc., or
> >>> USB/PCIe device hard-wired on a board. They all use standard protocols
> >>> and all need additional data to describe them. Of course, adding a
> >>> single property for a delay would not be a big deal, but it's never
> >>> ending. Next you need multiple supplies, GPIO controls, mutiple
> >>> delays... This has been discussed to death already. As Thierry Reding
> >>> said, you're not special[1].
> >>
> >> I can somewhat understand what you mean. The official specification is
> >> for ACPI. And ACPI allows to calls various settings while querying the
> >> _STA method for instance. So in the ACPI world, we don't need to care
> >> about regulators or GPIOs because the OEM deals with this in its own
> >> blob.
> >>
> >> Now, coming back to our issue. We are not special, maybe, if he says so.
> >> But this really feels like a design choice between putting the burden on
> >> device tree and OEMs or in the module maintainers. And I'd rather have
> >> the OEM deal with their device than me having to update the module for
> >> each generations of hardware. Indeed, this looks like an "endless"
> >> amount of quirks, but I'd rather have this endless amount of quirks than
> >> having to maintain an endless amount of list of new devices that behaves
> >> the same way. We are talking here about "wacom,w9013", but then comes
> >> "wacom,w9014" and we need to upgrade the kernel.
> >
> > No. If the w9014 can claim compatibility with then w9013, then you
> > don't need a kernel change. The DT should list the w9014 AND w9013,
> > but the kernel only needs to know about the w9013. That is until there
> > is some difference which is why the DT should list w9014 to start
> > with.
> >
> > If you don't have any power control to deal with, then the kernel can
> > always just match on "hid-over-i2c" compatible.
> 
> Just my $0.02.  Feel free to ignore.
> 
> One thought is that I would say that the need to power on the device
> explicitly seems more like a board level difference and less like a
> difference associated with a particular digitizer.  Said another way,
> it seems likely there will be boards with a w9013 without explicit
> control of the regulator in software and it seems like there will be
> boards with other digitizers where suddenly a new board will come out
> that needs explicit control of the regulator.
> 
> In this particular case I feel like we can draw a lot of parallels to
> an SDIO bus.
> 
> When you specify an SDIO bus you don't specify what kind of card will
> be present, you just say "I've got an SDIO bus" and then the specific
> device underneath is probed.  Here we've say "I've got an i2c
> connection intended for HID" and then you probe for the HID device
> that's on the connection.
> 
> Also for an SDIO bus, you've possibly got a regulators / GPIOs /
> resets that need to be controlled, but the specific details of these
> regulator / GPIOs / resets are specific to a given board and not
> necessarily a given SDIO device.
>

Thanks Doug for this. I had the feeling this wasn't right, but you
actually managed to put the words on it. If it's a board problem (if
you switch the wacom device with an other HID over I2C device and you
still need the same regulator/timing parameters), then this should
simply be mentioned on the patch.

So Brian, could you please respin the series and remve the Wacom
mentions and explain that it is required for the board itself?

Cheers,
Benjamin
--
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 6/6] net: smmac: allow configuring lower pbl values
From: David Miller @ 2016-12-08 15:18 UTC (permalink / raw)
  To: alexandre.torgue
  Cc: niklas.cassel, robh+dt, mark.rutland, corbet, peppe.cavallaro,
	preid, eric, pavel, afaerber, manabian, vpalatin,
	gabriel.fernandez, niklass, netdev, devicetree, linux-kernel,
	linux-doc
In-Reply-To: <4d43479f-8373-308b-8c7d-cfed5346dc53@st.com>

From: Alexandre Torgue <alexandre.torgue@st.com>
Date: Thu, 8 Dec 2016 11:42:56 +0100

> Thanks for this patch, you can add my Acked-by.

Please simply state:

Acked-by: Alexandre Torgue <alexandre.torgue@st.com>

in your reply and it will automatically appear when the patch is
applied.  You don't have to ask the patch submitter or the person who
applies it to do it as you are doing here.

^ permalink raw reply

* Re: [PATCH 1/2] Documentation: sample averaging for imx6ul_tsc
From: Guy Shapiro @ 2016-12-08 15:15 UTC (permalink / raw)
  To: Rob Herring
  Cc: fabio.estevam, mark.rutland, devicetree, haibo.chen,
	dmitry.torokhov, linux-input, linux-arm-kernel
In-Reply-To: <20161201161343.g7p2maxiatp4m5di@rob-hp-laptop>

On 01/12/2016 18:13, Rob Herring wrote:
> On Sun, Nov 27, 2016 at 09:44:57AM +0200, Guy Shapiro wrote:
>> The i.MX6UL internal touchscreen controller contains an option to
>> average upon samples. This feature reduces noise from the produced
>> touch locations.
>>
>> This patch introduces a new device tree optional property for this
>> feature. It provides control over the amount of averaged samples per
>> touch event.
>>
>> The property was inspired by a similar property on the
>> "brcm,iproc-touchscreen" binding.
>>
>> Signed-off-by: Guy Shapiro <guy.shapiro@mobi-wize.com>
>> ---
>>   .../devicetree/bindings/input/touchscreen/imx6ul_tsc.txt          | 8
> ++++++++
>>   1 file changed, 8 insertions(+)
>>
>> diff --git
> a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
> b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>> index 853dff9..a66069f 100644
>> --- a/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>> +++ b/Documentation/devicetree/bindings/input/touchscreen/imx6ul_tsc.txt
>> @@ -17,6 +17,13 @@ Optional properties:
>>     This value depends on the touch screen.
>>   - pre-charge-time: the touch screen need some time to precharge.
>>     This value depends on the touch screen.
>> +- average-samples: Number of data samples which are averaged for each
> read.
>> +	Valid values 0-4
>> +	0 =  1 sample
>> +	1 =  4 samples
>> +	2 =  8 samples
>> +	3 = 16 samples
>> +	4 = 32 samples
> Either this needs a vendor prefix or should be documented as a generic
> property. In the latter case, you should use actual number of samples
> (1-32) for the values.
In the term "generic property", do you mean to document it on 
bindings/input/touchscreen/touchscreen.txt ?
If so, should I add the "touchscreen-" prefix like all the other 
properties in that file?

Grepping bindings/input/touchscreen/, I found two other device drivers 
that implement a
similar property - "ti-tsc-adc" and "brcm,iproc-touchscreen" (The 
latter, BTW, uses a non
vendor prefixed property name).

Do we want to move from per-vendor properties to a generic one?
If we do, should we deprecate the existing vendor specific properties?

^ permalink raw reply

* [PATCH v4 4/4] arm64: dts: marvell: Enable spi0 on the board Armada-3720-db
From: Romain Perier @ 2016-12-08 14:58 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory Clement,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Ian Campbell,
	Pawel Moll, Mark Rutland, Kumar Gala,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Nadav Haklai, xigu-eYqpPyKDWXRBDgjK7y7TUQ,
	dingwei-eYqpPyKDWXRBDgjK7y7TUQ, Romain Perier
In-Reply-To: <20161208145847.7794-1-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

This commit enables the device node spi0 on the official development
board for the Marvell Armada 3700. It also adds sub-node for the 128Mb
SPI-NOR present on the board.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---

Changes in v3:
 - Added tag "Tested-by" by Gregory

 arch/arm64/boot/dts/marvell/armada-3720-db.dts | 30 ++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-3720-db.dts b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
index 1372e9a6..0c4eb98 100644
--- a/arch/arm64/boot/dts/marvell/armada-3720-db.dts
+++ b/arch/arm64/boot/dts/marvell/armada-3720-db.dts
@@ -67,6 +67,36 @@
 	status = "okay";
 };
 
+&spi0 {
+	status = "okay";
+
+	m25p80@0 {
+		compatible = "jedec,spi-nor";
+		reg = <0>;
+		spi-max-frequency = <108000000>;
+		spi-rx-bus-width = <4>;
+		spi-tx-bus-width = <4>;
+
+		partitions {
+			compatible = "fixed-partitions";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			partition@0 {
+				label = "bootloader";
+				reg = <0x0 0x200000>;
+			};
+			partition@200000 {
+				label = "U-boot Env";
+				reg = <0x200000 0x10000>;
+			};
+			partition@210000 {
+				label = "Linux";
+				reg = <0x210000 0xDF0000>;
+			};
+		};
+	};
+};
+
 /* Exported on the micro USB connector CON32 through an FTDI */
 &uart0 {
 	status = "okay";
-- 
2.9.3

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

^ permalink raw reply related

* [PATCH v4 3/4] arm64: dts: marvell: Add definition of SPI controller for Armada 3700
From: Romain Perier @ 2016-12-08 14:58 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory Clement,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Ian Campbell,
	Pawel Moll, Mark Rutland, Kumar Gala,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Nadav Haklai, xigu-eYqpPyKDWXRBDgjK7y7TUQ,
	dingwei-eYqpPyKDWXRBDgjK7y7TUQ, Romain Perier
In-Reply-To: <20161208145847.7794-1-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Armada 3700 SoC has an SPI Controller, this commit adds the definition
of the SPI device node at the SoC level.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---

Changes in v3:
 - Fixed wrong register size for spi0, as suggested by the maintainer
   on the ML.
 - Added tag "Tested-by" by Gregory

Changes in v2:
 - Removed properties max-frequency and clock-frequency, it is no
   longer required and not used by the DT-bindings.

 arch/arm64/boot/dts/marvell/armada-37xx.dtsi | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
index e9bd587..fcef9a5 100644
--- a/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
+++ b/arch/arm64/boot/dts/marvell/armada-37xx.dtsi
@@ -98,6 +98,17 @@
 			/* 32M internal register @ 0xd000_0000 */
 			ranges = <0x0 0x0 0xd0000000 0x2000000>;
 
+			spi0: spi@10600 {
+				compatible = "marvell,armada-3700-spi";
+				#address-cells = <1>;
+				#size-cells = <0>;
+				reg = <0x10600 0xA00>;
+				clocks = <&nb_periph_clk 7>;
+				interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+				num-cs = <4>;
+				status = "disabled";
+			};
+
 			uart0: serial@12000 {
 				compatible = "marvell,armada-3700-uart";
 				reg = <0x12000 0x400>;
-- 
2.9.3

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

^ permalink raw reply related

* [PATCH v4 2/4] spi: armada-3700: Add documentation for the Armada 3700 SPI Controller
From: Romain Perier @ 2016-12-08 14:58 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory Clement,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Ian Campbell,
	Pawel Moll, Mark Rutland, Kumar Gala,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Nadav Haklai, xigu-eYqpPyKDWXRBDgjK7y7TUQ,
	dingwei-eYqpPyKDWXRBDgjK7y7TUQ, Romain Perier
In-Reply-To: <20161208145847.7794-1-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

This adds the devicetree bindings documentation for the SPI controller
present in the Marvell Armada 3700 SoCs.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
---

Changes in v4:
 - Added tag "Acked-by" by Rob Herring

Changes in v3:
 - Added tag "Tested-by" by Gregory
 - Fixed commit title, as requested by Mark Brown

 .../devicetree/bindings/spi/spi-armada-3700.txt    | 25 ++++++++++++++++++++++
 1 file changed, 25 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/spi/spi-armada-3700.txt

diff --git a/Documentation/devicetree/bindings/spi/spi-armada-3700.txt b/Documentation/devicetree/bindings/spi/spi-armada-3700.txt
new file mode 100644
index 0000000..1564aa8
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-armada-3700.txt
@@ -0,0 +1,25 @@
+* Marvell Armada 3700 SPI Controller
+
+Required Properties:
+
+- compatible: should be "marvell,armada-3700-spi"
+- reg: physical base address of the controller and length of memory mapped
+       region.
+- interrupts: The interrupt number. The interrupt specifier format depends on
+	      the interrupt controller and of its driver.
+- clocks: Must contain the clock source, usually from the North Bridge clocks.
+- num-cs: The number of chip selects that is supported by this SPI Controller
+- #address-cells: should be 1.
+- #size-cells: should be 0.
+
+Example:
+
+	spi0: spi@10600 {
+		compatible = "marvell,armada-3700-spi";
+		#address-cells = <1>;
+		#size-cells = <0>;
+		reg = <0x10600 0x5d>;
+		clocks = <&nb_perih_clk 7>;
+		interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
+		num-cs = <4>;
+	};
-- 
2.9.3

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

^ permalink raw reply related

* [PATCH v4 1/4] spi: Add support for Armada 3700 SPI Controller
From: Romain Perier @ 2016-12-08 14:58 UTC (permalink / raw)
  To: Mark Brown, linux-spi-u79uwXL29TY76Z2rM5mHXA
  Cc: Jason Cooper, Andrew Lunn, Sebastian Hesselbarth, Gregory Clement,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring, Ian Campbell,
	Pawel Moll, Mark Rutland, Kumar Gala,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Thomas Petazzoni, Nadav Haklai, xigu-eYqpPyKDWXRBDgjK7y7TUQ,
	dingwei-eYqpPyKDWXRBDgjK7y7TUQ, Romain Perier
In-Reply-To: <20161208145847.7794-1-romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>

Marvell Armada 3700 SoC comprises an SPI Controller. This Controller
supports up to 4 SPI slave devices, with dedicated chip selects,supports
SPI mode 0/1/2 and 3, CPIO or Fifo mode with DMA transfers and different
SPI transfer mode (Single, Dual or Quad).

This commit adds basic driver support for FIFO mode. In this mode,
dedicated registers are used to store the instruction, the address, the
read mode and the data. Write and Read FIFO are used to store the
outcoming or incoming data. The data FIFOs are accessible via DMA or by
the CPU. Only the CPU is supported for now.

Signed-off-by: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
Tested-by: Gregory CLEMENT <gregory.clement-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
---

Changes in v4:
 - Added missing COMPILE_TEST in KConfig
 - Replaced the busy wait for loop by a single busy wait in spi_init()
 - Handle IRQ_NONE in the interrupt handler 
 - Assign pdev->id to master->cs_num directly (no conditionnal operator)
 - Moved clock gating into prepare/unprepare callbacks
 - Removed dev_info() in the end of the probe() function
 - Added flag to the spi master for single duplex transfers
 - Squashed patch 1/5 and 2/5 together: remove the non-fifo mode, just keep
   the more efficient mode
 - So removed the module parameter

Changes in v3:
 - Don't enable the fifo mode based on the compatible string, we introduce
   a module parameter "pio_mode". By default this option is set to zero, so
   the fifo mode is enabled. Pass pio_mode=1 to the driver enables the PIO
   mode.
 - Added tag "Tested-by" by Gregory
 - Fixed wrong variable passed as MODULE_DEVICE_TABLE
 - Added missing null terminated entry in a3700_spi_dt_ids 

Changes in v2:
 - Removed a3700_spi_bytelen_set from the setup function, it was accidentally
   let here and not required, as it is configured in the prepare callback now
   (defaults to 4 for fifo mode). It solves unrecognized spi-nor flash memory
   detection with jedec.

 drivers/spi/Kconfig           |   7 +
 drivers/spi/Makefile          |   1 +
 drivers/spi/spi-armada-3700.c | 923 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 931 insertions(+)
 create mode 100644 drivers/spi/spi-armada-3700.c

diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b799547..1faad2ce 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -67,6 +67,13 @@ config SPI_ATH79
 	  This enables support for the SPI controller present on the
 	  Atheros AR71XX/AR724X/AR913X SoCs.
 
+config SPI_ARMADA_3700
+	tristate "Marvell Armada 3700 SPI Controller"
+	depends on (ARCH_MVEBU && OF) || COMPILE_TEST
+	help
+	  This enables support for the SPI controller present on the
+	  Marvell Armada 3700 SoCs.
+
 config SPI_ATMEL
 	tristate "Atmel SPI Controller"
 	depends on HAS_DMA
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index aa939d9..140ca45 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SPI_LOOPBACK_TEST)		+= spi-loopback-test.o
 
 # SPI master controller drivers (bus)
 obj-$(CONFIG_SPI_ALTERA)		+= spi-altera.o
+obj-$(CONFIG_SPI_ARMADA_3700)		+= spi-armada-3700.o
 obj-$(CONFIG_SPI_ATMEL)			+= spi-atmel.o
 obj-$(CONFIG_SPI_ATH79)			+= spi-ath79.o
 obj-$(CONFIG_SPI_AU1550)		+= spi-au1550.o
diff --git a/drivers/spi/spi-armada-3700.c b/drivers/spi/spi-armada-3700.c
new file mode 100644
index 0000000..e89da0a
--- /dev/null
+++ b/drivers/spi/spi-armada-3700.c
@@ -0,0 +1,923 @@
+/*
+ * Marvell Armada-3700 SPI controller driver
+ *
+ * Copyright (C) 2016 Marvell Ltd.
+ *
+ * Author: Wilson Ding <dingwei-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>
+ * Author: Romain Perier <romain.perier-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/spi/spi.h>
+
+#define DRIVER_NAME			"armada_3700_spi"
+
+#define A3700_SPI_TIMEOUT		10
+
+/* SPI Register Offest */
+#define A3700_SPI_IF_CTRL_REG		0x00
+#define A3700_SPI_IF_CFG_REG		0x04
+#define A3700_SPI_DATA_OUT_REG		0x08
+#define A3700_SPI_DATA_IN_REG		0x0C
+#define A3700_SPI_IF_INST_REG		0x10
+#define A3700_SPI_IF_ADDR_REG		0x14
+#define A3700_SPI_IF_RMODE_REG		0x18
+#define A3700_SPI_IF_HDR_CNT_REG	0x1C
+#define A3700_SPI_IF_DIN_CNT_REG	0x20
+#define A3700_SPI_IF_TIME_REG		0x24
+#define A3700_SPI_INT_STAT_REG		0x28
+#define A3700_SPI_INT_MASK_REG		0x2C
+
+/* A3700_SPI_IF_CTRL_REG */
+#define A3700_SPI_EN			BIT(16)
+#define A3700_SPI_ADDR_NOT_CONFIG	BIT(12)
+#define A3700_SPI_WFIFO_OVERFLOW	BIT(11)
+#define A3700_SPI_WFIFO_UNDERFLOW	BIT(10)
+#define A3700_SPI_RFIFO_OVERFLOW	BIT(9)
+#define A3700_SPI_RFIFO_UNDERFLOW	BIT(8)
+#define A3700_SPI_WFIFO_FULL		BIT(7)
+#define A3700_SPI_WFIFO_EMPTY		BIT(6)
+#define A3700_SPI_RFIFO_FULL		BIT(5)
+#define A3700_SPI_RFIFO_EMPTY		BIT(4)
+#define A3700_SPI_WFIFO_RDY		BIT(3)
+#define A3700_SPI_RFIFO_RDY		BIT(2)
+#define A3700_SPI_XFER_RDY		BIT(1)
+#define A3700_SPI_XFER_DONE		BIT(0)
+
+/* A3700_SPI_IF_CFG_REG */
+#define A3700_SPI_WFIFO_THRS		BIT(28)
+#define A3700_SPI_RFIFO_THRS		BIT(24)
+#define A3700_SPI_AUTO_CS		BIT(20)
+#define A3700_SPI_DMA_RD_EN		BIT(18)
+#define A3700_SPI_FIFO_MODE		BIT(17)
+#define A3700_SPI_SRST			BIT(16)
+#define A3700_SPI_XFER_START		BIT(15)
+#define A3700_SPI_XFER_STOP		BIT(14)
+#define A3700_SPI_INST_PIN		BIT(13)
+#define A3700_SPI_ADDR_PIN		BIT(12)
+#define A3700_SPI_DATA_PIN1		BIT(11)
+#define A3700_SPI_DATA_PIN0		BIT(10)
+#define A3700_SPI_FIFO_FLUSH		BIT(9)
+#define A3700_SPI_RW_EN			BIT(8)
+#define A3700_SPI_CLK_POL		BIT(7)
+#define A3700_SPI_CLK_PHA		BIT(6)
+#define A3700_SPI_BYTE_LEN		BIT(5)
+#define A3700_SPI_CLK_PRESCALE		BIT(0)
+#define A3700_SPI_CLK_PRESCALE_MASK	(0x1f)
+
+#define A3700_SPI_WFIFO_THRS_BIT	28
+#define A3700_SPI_RFIFO_THRS_BIT	24
+#define A3700_SPI_FIFO_THRS_MASK	0x7
+
+#define A3700_SPI_DATA_PIN_MASK		0x3
+
+/* A3700_SPI_IF_HDR_CNT_REG */
+#define A3700_SPI_DUMMY_CNT_BIT		12
+#define A3700_SPI_DUMMY_CNT_MASK	0x7
+#define A3700_SPI_RMODE_CNT_BIT		8
+#define A3700_SPI_RMODE_CNT_MASK	0x3
+#define A3700_SPI_ADDR_CNT_BIT		4
+#define A3700_SPI_ADDR_CNT_MASK		0x7
+#define A3700_SPI_INSTR_CNT_BIT		0
+#define A3700_SPI_INSTR_CNT_MASK	0x3
+
+/* A3700_SPI_IF_TIME_REG */
+#define A3700_SPI_CLK_CAPT_EDGE		BIT(7)
+
+/* Flags and macros for struct a3700_spi */
+#define A3700_INSTR_CNT			1
+#define A3700_ADDR_CNT			3
+#define A3700_DUMMY_CNT			1
+
+struct a3700_spi {
+	struct spi_master *master;
+	void __iomem *base;
+	struct clk *clk;
+	unsigned int irq;
+	unsigned int flags;
+	bool xmit_data;
+	const u8 *tx_buf;
+	u8 *rx_buf;
+	size_t buf_len;
+	u8 byte_len;
+	u32 wait_mask;
+	struct completion done;
+	u32 addr_cnt;
+	u32 instr_cnt;
+	size_t hdr_cnt;
+};
+
+static u32 spireg_read(struct a3700_spi *a3700_spi, u32 offset)
+{
+	return readl(a3700_spi->base + offset);
+}
+
+static void spireg_write(struct a3700_spi *a3700_spi, u32 offset, u32 data)
+{
+	writel(data, a3700_spi->base + offset);
+}
+
+static void a3700_spi_auto_cs_unset(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~A3700_SPI_AUTO_CS;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_activate_cs(struct a3700_spi *a3700_spi, unsigned int cs)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	val |= (A3700_SPI_EN << cs);
+	spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val);
+}
+
+static void a3700_spi_deactivate_cs(struct a3700_spi *a3700_spi,
+				    unsigned int cs)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	val &= ~(A3700_SPI_EN << cs);
+	spireg_write(a3700_spi, A3700_SPI_IF_CTRL_REG, val);
+}
+
+static int a3700_spi_pin_mode_set(struct a3700_spi *a3700_spi,
+				  unsigned int pin_mode)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_INST_PIN | A3700_SPI_ADDR_PIN);
+	val &= ~(A3700_SPI_DATA_PIN0 | A3700_SPI_DATA_PIN1);
+
+	switch (pin_mode) {
+	case 1:
+		break;
+	case 2:
+		val |= A3700_SPI_DATA_PIN0;
+		break;
+	case 4:
+		val |= A3700_SPI_DATA_PIN1;
+		break;
+	default:
+		dev_err(&a3700_spi->master->dev, "wrong pin mode %u", pin_mode);
+		return -EINVAL;
+	}
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	return 0;
+}
+
+static void a3700_spi_fifo_mode_set(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_FIFO_MODE;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_mode_set(struct a3700_spi *a3700_spi,
+			       unsigned int mode_bits)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+
+	if (mode_bits & SPI_CPOL)
+		val |= A3700_SPI_CLK_POL;
+	else
+		val &= ~A3700_SPI_CLK_POL;
+
+	if (mode_bits & SPI_CPHA)
+		val |= A3700_SPI_CLK_PHA;
+	else
+		val &= ~A3700_SPI_CLK_PHA;
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_clock_set(struct a3700_spi *a3700_spi,
+				unsigned int speed_hz, u16 mode)
+{
+	u32 val;
+	u32 prescale;
+
+	prescale = DIV_ROUND_UP(clk_get_rate(a3700_spi->clk), speed_hz);
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val = val & ~A3700_SPI_CLK_PRESCALE_MASK;
+
+	val = val | (prescale & A3700_SPI_CLK_PRESCALE_MASK);
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	if (prescale <= 2) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_TIME_REG);
+		val |= A3700_SPI_CLK_CAPT_EDGE;
+		spireg_write(a3700_spi, A3700_SPI_IF_TIME_REG, val);
+	}
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_CLK_POL | A3700_SPI_CLK_PHA);
+
+	if (mode & SPI_CPOL)
+		val |= A3700_SPI_CLK_POL;
+
+	if (mode & SPI_CPHA)
+		val |= A3700_SPI_CLK_PHA;
+
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_bytelen_set(struct a3700_spi *a3700_spi, unsigned int len)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	if (len == 4)
+		val |= A3700_SPI_BYTE_LEN;
+	else
+		val &= ~A3700_SPI_BYTE_LEN;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	a3700_spi->byte_len = len;
+}
+
+static int a3700_spi_fifo_flush(struct a3700_spi *a3700_spi)
+{
+	int timeout = A3700_SPI_TIMEOUT;
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_FIFO_FLUSH;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_FIFO_FLUSH))
+			return 0;
+		udelay(1);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static int a3700_spi_init(struct a3700_spi *a3700_spi)
+{
+	struct spi_master *master = a3700_spi->master;
+	u32 val;
+	int i, ret = 0;
+
+	/* Reset SPI unit */
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_SRST;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	udelay(A3700_SPI_TIMEOUT);
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~A3700_SPI_SRST;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	/* Disable AUTO_CS and deactivate all chip-selects */
+	a3700_spi_auto_cs_unset(a3700_spi);
+	for (i = 0; i < master->num_chipselect; i++)
+		a3700_spi_deactivate_cs(a3700_spi, i);
+
+	/* Enable FIFO mode */
+	a3700_spi_fifo_mode_set(a3700_spi);
+
+	/* Set SPI mode */
+	a3700_spi_mode_set(a3700_spi, master->mode_bits);
+
+	/* Reset counters */
+	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG, 0);
+
+	/* Mask the interrupts and clear cause bits */
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, ~0U);
+
+	return ret;
+}
+
+static irqreturn_t a3700_spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_master *master = dev_id;
+	struct a3700_spi *a3700_spi;
+	u32 cause;
+
+	a3700_spi = spi_master_get_devdata(master);
+
+	/* Get interrupt causes */
+	cause = spireg_read(a3700_spi, A3700_SPI_INT_STAT_REG);
+
+	if (!cause || !(a3700_spi->wait_mask & cause))
+		return IRQ_NONE;
+
+	/* mask and acknowledge the SPI interrupts */
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_INT_STAT_REG, cause);
+
+	/* Wake up the transfer */
+	if (a3700_spi->wait_mask & cause)
+		complete(&a3700_spi->done);
+
+	return IRQ_HANDLED;
+}
+
+static bool a3700_spi_wait_completion(struct spi_device *spi)
+{
+	struct a3700_spi *a3700_spi;
+	unsigned int timeout;
+	unsigned int ctrl_reg;
+	unsigned long timeout_jiffies;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+
+	/* SPI interrupt is edge-triggered, which means an interrupt will
+	 * be generated only when detecting a specific status bit changed
+	 * from '0' to '1'. So when we start waiting for a interrupt, we
+	 * need to check status bit in control reg first, if it is already 1,
+	 * then we do not need to wait for interrupt
+	 */
+	ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	if (a3700_spi->wait_mask & ctrl_reg)
+		return true;
+
+	reinit_completion(&a3700_spi->done);
+
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG,
+		     a3700_spi->wait_mask);
+
+	timeout_jiffies = msecs_to_jiffies(A3700_SPI_TIMEOUT);
+	timeout = wait_for_completion_timeout(&a3700_spi->done,
+					      timeout_jiffies);
+
+	a3700_spi->wait_mask = 0;
+
+	if (timeout)
+		return true;
+
+	/* there might be the case that right after we checked the
+	 * status bits in this routine and before start to wait for
+	 * interrupt by wait_for_completion_timeout, the interrupt
+	 * happens, to avoid missing it we need to double check
+	 * status bits in control reg, if it is already 1, then
+	 * consider that we have the interrupt successfully and
+	 * return true.
+	 */
+	ctrl_reg = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	if (a3700_spi->wait_mask & ctrl_reg)
+		return true;
+
+	spireg_write(a3700_spi, A3700_SPI_INT_MASK_REG, 0);
+
+	return true;
+}
+
+static bool a3700_spi_transfer_wait(struct spi_device *spi,
+				    unsigned int bit_mask)
+{
+	struct a3700_spi *a3700_spi;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+	a3700_spi->wait_mask = bit_mask;
+
+	return a3700_spi_wait_completion(spi);
+}
+
+static void a3700_spi_fifo_thres_set(struct a3700_spi *a3700_spi,
+				     unsigned int bytes)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_RFIFO_THRS_BIT);
+	val |= (bytes - 1) << A3700_SPI_RFIFO_THRS_BIT;
+	val &= ~(A3700_SPI_FIFO_THRS_MASK << A3700_SPI_WFIFO_THRS_BIT);
+	val |= (7 - bytes) << A3700_SPI_WFIFO_THRS_BIT;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static void a3700_spi_transfer_setup(struct spi_device *spi,
+				    struct spi_transfer *xfer)
+{
+	struct a3700_spi *a3700_spi;
+	unsigned int byte_len;
+
+	a3700_spi = spi_master_get_devdata(spi->master);
+
+	a3700_spi_clock_set(a3700_spi, xfer->speed_hz, spi->mode);
+
+	byte_len = xfer->bits_per_word >> 3;
+
+	a3700_spi_fifo_thres_set(a3700_spi, byte_len);
+}
+
+static void a3700_spi_set_cs(struct spi_device *spi, bool enable)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(spi->master);
+
+	if (!enable)
+		a3700_spi_activate_cs(a3700_spi, spi->chip_select);
+	else
+		a3700_spi_deactivate_cs(a3700_spi, spi->chip_select);
+}
+
+static void a3700_spi_header_set(struct a3700_spi *a3700_spi)
+{
+	u32 instr_cnt = 0, addr_cnt = 0, dummy_cnt = 0;
+	u32 val = 0;
+
+	/* Clear the header registers */
+	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, 0);
+	spireg_write(a3700_spi, A3700_SPI_IF_RMODE_REG, 0);
+
+	/* Set header counters */
+	if (a3700_spi->tx_buf) {
+		if (a3700_spi->buf_len <= a3700_spi->instr_cnt) {
+			instr_cnt = a3700_spi->buf_len;
+		} else if (a3700_spi->buf_len <= (a3700_spi->instr_cnt +
+						  a3700_spi->addr_cnt)) {
+			instr_cnt = a3700_spi->instr_cnt;
+			addr_cnt = a3700_spi->buf_len - instr_cnt;
+		} else if (a3700_spi->buf_len <= a3700_spi->hdr_cnt) {
+			instr_cnt = a3700_spi->instr_cnt;
+			addr_cnt = a3700_spi->addr_cnt;
+			/* Need to handle the normal write case with 1 byte
+			 * data
+			 */
+			if (!a3700_spi->tx_buf[instr_cnt + addr_cnt])
+				dummy_cnt = a3700_spi->buf_len - instr_cnt -
+					    addr_cnt;
+		}
+		val |= ((instr_cnt & A3700_SPI_INSTR_CNT_MASK)
+			<< A3700_SPI_INSTR_CNT_BIT);
+		val |= ((addr_cnt & A3700_SPI_ADDR_CNT_MASK)
+			<< A3700_SPI_ADDR_CNT_BIT);
+		val |= ((dummy_cnt & A3700_SPI_DUMMY_CNT_MASK)
+			<< A3700_SPI_DUMMY_CNT_BIT);
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_HDR_CNT_REG, val);
+
+	/* Update the buffer length to be transferred */
+	a3700_spi->buf_len -= (instr_cnt + addr_cnt + dummy_cnt);
+
+	/* Set Instruction */
+	val = 0;
+	while (instr_cnt--) {
+		val = (val << 8) | a3700_spi->tx_buf[0];
+		a3700_spi->tx_buf++;
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_INST_REG, val);
+
+	/* Set Address */
+	val = 0;
+	while (addr_cnt--) {
+		val = (val << 8) | a3700_spi->tx_buf[0];
+		a3700_spi->tx_buf++;
+	}
+	spireg_write(a3700_spi, A3700_SPI_IF_ADDR_REG, val);
+}
+
+static int a3700_is_wfifo_full(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+	return (val & A3700_SPI_WFIFO_FULL);
+}
+
+static int a3700_spi_fifo_write(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+	int i = 0;
+
+	while (!a3700_is_wfifo_full(a3700_spi) && a3700_spi->buf_len) {
+		val = 0;
+		if (a3700_spi->buf_len >= 4) {
+			val = cpu_to_le32(*(u32 *)a3700_spi->tx_buf);
+			spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG, val);
+
+			a3700_spi->buf_len -= 4;
+			a3700_spi->tx_buf += 4;
+		} else {
+			/*
+			 * If the remained buffer length is less than 4-bytes,
+			 * we should pad the write buffer with all ones. So that
+			 * it avoids overwrite the unexpected bytes following
+			 * the last one.
+			 */
+			val = GENMASK(31, 0);
+			while (a3700_spi->buf_len) {
+				val &= ~(0xff << (8 * i));
+				val |= *a3700_spi->tx_buf++ << (8 * i);
+				i++;
+				a3700_spi->buf_len--;
+
+				spireg_write(a3700_spi, A3700_SPI_DATA_OUT_REG,
+					     val);
+			}
+			break;
+		}
+	}
+
+	return 0;
+}
+
+static int a3700_is_rfifo_empty(struct a3700_spi *a3700_spi)
+{
+	u32 val = spireg_read(a3700_spi, A3700_SPI_IF_CTRL_REG);
+
+	return (val & A3700_SPI_RFIFO_EMPTY);
+}
+
+static int a3700_spi_fifo_read(struct a3700_spi *a3700_spi)
+{
+	u32 val;
+
+	while (!a3700_is_rfifo_empty(a3700_spi) && a3700_spi->buf_len) {
+		val = spireg_read(a3700_spi, A3700_SPI_DATA_IN_REG);
+		if (a3700_spi->buf_len >= 4) {
+			u32 data = le32_to_cpu(val);
+			memcpy(a3700_spi->rx_buf, &data, 4);
+
+			a3700_spi->buf_len -= 4;
+			a3700_spi->rx_buf += 4;
+		} else {
+			/*
+			 * When remain bytes is not larger than 4, we should
+			 * avoid memory overwriting and just write the left rx
+			 * buffer bytes.
+			 */
+			while (a3700_spi->buf_len) {
+				*a3700_spi->rx_buf = val & 0xff;
+				val >>= 8;
+
+				a3700_spi->buf_len--;
+				a3700_spi->rx_buf++;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static void a3700_spi_transfer_abort_fifo(struct a3700_spi *a3700_spi)
+{
+	int timeout = A3700_SPI_TIMEOUT;
+	u32 val;
+
+	val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+	val |= A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_XFER_START))
+			break;
+		udelay(1);
+	}
+
+	a3700_spi_fifo_flush(a3700_spi);
+
+	val &= ~A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+}
+
+static int a3700_spi_prepare_message(struct spi_master *master,
+				     struct spi_message *message)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+	struct spi_device *spi = message->spi;
+	int ret;
+
+	ret = clk_enable(a3700_spi->clk);
+	if (ret) {
+		dev_err(&spi->dev, "failed to enable clk with error %d\n", ret);
+		return ret;
+	}
+
+	/* Flush the FIFOs */
+	ret = a3700_spi_fifo_flush(a3700_spi);
+	if (ret)
+		return ret;
+
+	a3700_spi_bytelen_set(a3700_spi, 4);
+
+	return 0;
+}
+
+static int a3700_spi_transfer_one(struct spi_master *master,
+				  struct spi_device *spi,
+				  struct spi_transfer *xfer)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+	int ret = 0, timeout = A3700_SPI_TIMEOUT;
+	unsigned int nbits = 0;
+	u32 val;
+
+	a3700_spi_transfer_setup(spi, xfer);
+
+	a3700_spi->tx_buf  = xfer->tx_buf;
+	a3700_spi->rx_buf  = xfer->rx_buf;
+	a3700_spi->buf_len = xfer->len;
+
+	/* SPI transfer headers */
+	a3700_spi_header_set(a3700_spi);
+
+	if (xfer->tx_buf)
+		nbits = xfer->tx_nbits;
+	else if (xfer->rx_buf)
+		nbits = xfer->rx_nbits;
+
+	a3700_spi_pin_mode_set(a3700_spi, nbits);
+
+	if (xfer->rx_buf) {
+		/* Set read data length */
+		spireg_write(a3700_spi, A3700_SPI_IF_DIN_CNT_REG,
+			     a3700_spi->buf_len);
+		/* Start READ transfer */
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val &= ~A3700_SPI_RW_EN;
+		val |= A3700_SPI_XFER_START;
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	} else if (xfer->tx_buf) {
+		/* Start Write transfer */
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val |= (A3700_SPI_XFER_START | A3700_SPI_RW_EN);
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+
+		/*
+		 * If there are data to be written to the SPI device, xmit_data
+		 * flag is set true; otherwise the instruction in SPI_INSTR does
+		 * not require data to be written to the SPI device, then
+		 * xmit_data flag is set false.
+		 */
+		a3700_spi->xmit_data = (a3700_spi->buf_len != 0);
+	}
+
+	while (a3700_spi->buf_len) {
+		if (a3700_spi->tx_buf) {
+			/* Wait wfifo ready */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_WFIFO_RDY)) {
+				dev_err(&spi->dev,
+					"wait wfifo ready timed out\n");
+				ret = -ETIMEDOUT;
+				goto error;
+			}
+			/* Fill up the wfifo */
+			ret = a3700_spi_fifo_write(a3700_spi);
+			if (ret)
+				goto error;
+		} else if (a3700_spi->rx_buf) {
+			/* Wait rfifo ready */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_RFIFO_RDY)) {
+				dev_err(&spi->dev,
+					"wait rfifo ready timed out\n");
+				ret = -ETIMEDOUT;
+				goto error;
+			}
+			/* Drain out the rfifo */
+			ret = a3700_spi_fifo_read(a3700_spi);
+			if (ret)
+				goto error;
+		}
+	}
+
+	/*
+	 * Stop a write transfer in fifo mode:
+	 *	- wait all the bytes in wfifo to be shifted out
+	 *	 - set XFER_STOP bit
+	 *	- wait XFER_START bit clear
+	 *	- clear XFER_STOP bit
+	 * Stop a read transfer in fifo mode:
+	 *	- the hardware is to reset the XFER_START bit
+	 *	   after the number of bytes indicated in DIN_CNT
+	 *	   register
+	 *	- just wait XFER_START bit clear
+	 */
+	if (a3700_spi->tx_buf) {
+		if (a3700_spi->xmit_data) {
+			/*
+			 * If there are data written to the SPI device, wait
+			 * until SPI_WFIFO_EMPTY is 1 to wait for all data to
+			 * transfer out of write FIFO.
+			 */
+			if (!a3700_spi_transfer_wait(spi,
+						     A3700_SPI_WFIFO_EMPTY)) {
+				dev_err(&spi->dev, "wait wfifo empty timed out\n");
+				return -ETIMEDOUT;
+			}
+		} else {
+			/*
+			 * If the instruction in SPI_INSTR does not require data
+			 * to be written to the SPI device, wait until SPI_RDY
+			 * is 1 for the SPI interface to be in idle.
+			 */
+			if (!a3700_spi_transfer_wait(spi, A3700_SPI_XFER_RDY)) {
+				dev_err(&spi->dev, "wait xfer ready timed out\n");
+				return -ETIMEDOUT;
+			}
+		}
+
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		val |= A3700_SPI_XFER_STOP;
+		spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	}
+
+	while (--timeout) {
+		val = spireg_read(a3700_spi, A3700_SPI_IF_CFG_REG);
+		if (!(val & A3700_SPI_XFER_START))
+			break;
+		udelay(1);
+	}
+
+	if (timeout == 0) {
+		dev_err(&spi->dev, "wait transfer start clear timed out\n");
+		ret = -ETIMEDOUT;
+		goto error;
+	}
+
+	val &= ~A3700_SPI_XFER_STOP;
+	spireg_write(a3700_spi, A3700_SPI_IF_CFG_REG, val);
+	goto out;
+
+error:
+	a3700_spi_transfer_abort_fifo(a3700_spi);
+out:
+	spi_finalize_current_transfer(master);
+
+	return ret;
+}
+
+static int a3700_spi_unprepare_message(struct spi_master *master,
+				       struct spi_message *message)
+{
+	struct a3700_spi *a3700_spi = spi_master_get_devdata(master);
+
+	clk_disable(a3700_spi->clk);
+
+	return 0;
+}
+
+static const struct of_device_id a3700_spi_dt_ids[] = {
+	{ .compatible = "marvell,armada-3700-spi", .data = NULL },
+	{},
+};
+
+MODULE_DEVICE_TABLE(of, a3700_spi_dt_ids);
+
+static int a3700_spi_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *of_node = dev->of_node;
+	struct resource *res;
+	struct spi_master *master;
+	struct a3700_spi *spi;
+	u32 num_cs = 0;
+	int ret = 0;
+
+	master = spi_alloc_master(dev, sizeof(*spi));
+	if (!master) {
+		dev_err(dev, "master allocation failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (of_property_read_u32(of_node, "num-cs", &num_cs)) {
+		dev_err(dev, "could not find num-cs\n");
+		ret = -ENXIO;
+		goto error;
+	}
+
+	master->bus_num = pdev->id;
+	master->dev.of_node = of_node;
+	master->mode_bits = SPI_MODE_3;
+	master->num_chipselect = num_cs;
+	master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(32);
+	master->prepare_message =  a3700_spi_prepare_message;
+	master->transfer_one = a3700_spi_transfer_one;
+	master->unprepare_message = a3700_spi_unprepare_message;
+	master->set_cs = a3700_spi_set_cs;
+	master->flags = SPI_MASTER_HALF_DUPLEX;
+	master->mode_bits |= (SPI_RX_DUAL | SPI_RX_DUAL |
+			      SPI_RX_QUAD | SPI_TX_QUAD);
+
+	platform_set_drvdata(pdev, master);
+
+	spi = spi_master_get_devdata(master);
+	memset(spi, 0, sizeof(struct a3700_spi));
+
+	spi->master = master;
+	spi->instr_cnt = A3700_INSTR_CNT;
+	spi->addr_cnt = A3700_ADDR_CNT;
+	spi->hdr_cnt = A3700_INSTR_CNT + A3700_ADDR_CNT +
+		       A3700_DUMMY_CNT;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	spi->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(spi->base)) {
+		ret = PTR_ERR(spi->base);
+		goto error;
+	}
+
+	spi->irq = platform_get_irq(pdev, 0);
+	if (spi->irq < 0) {
+		dev_err(dev, "could not get irq: %d\n", spi->irq);
+		ret = -ENXIO;
+		goto error;
+	}
+
+	init_completion(&spi->done);
+
+	spi->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(spi->clk)) {
+		dev_err(dev, "could not find clk: %ld\n", PTR_ERR(spi->clk));
+		goto error;
+	}
+
+	ret = clk_prepare(spi->clk);
+	if (ret) {
+		dev_err(dev, "could not prepare clk: %d\n", ret);
+		goto error;
+	}
+
+	ret = a3700_spi_init(spi);
+	if (ret)
+		goto error_clk;
+
+	ret = devm_request_irq(dev, spi->irq, a3700_spi_interrupt, 0,
+			       dev_name(dev), master);
+	if (ret) {
+		dev_err(dev, "could not request IRQ: %d\n", ret);
+		goto error_clk;
+	}
+
+	ret = devm_spi_register_master(dev, master);
+	if (ret) {
+		dev_err(dev, "Failed to register master\n");
+		goto error_clk;
+	}
+
+	return 0;
+
+error_clk:
+	clk_disable_unprepare(spi->clk);
+error:
+	spi_master_put(master);
+out:
+	return ret;
+}
+
+static int a3700_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master *master = platform_get_drvdata(pdev);
+	struct a3700_spi *spi = spi_master_get_devdata(master);
+
+	clk_unprepare(spi->clk);
+	spi_master_put(master);
+
+	return 0;
+}
+
+static struct platform_driver a3700_spi_driver = {
+	.driver = {
+		.name	= DRIVER_NAME,
+		.owner	= THIS_MODULE,
+		.of_match_table = of_match_ptr(a3700_spi_dt_ids),
+	},
+	.probe		= a3700_spi_probe,
+	.remove		= a3700_spi_remove,
+};
+
+module_platform_driver(a3700_spi_driver);
+
+MODULE_DESCRIPTION("Armada-3700 SPI driver");
+MODULE_AUTHOR("Wilson Ding <dingwei-eYqpPyKDWXRBDgjK7y7TUQ@public.gmane.org>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRIVER_NAME);
-- 
2.9.3

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

^ permalink raw reply related


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