Devicetree
 help / color / mirror / Atom feed
* Re: [PATCH v2 4/4] pci: Add support for creating a generic host_bridge from device tree
From: Benjamin Herrenschmidt @ 2014-02-27 23:32 UTC (permalink / raw)
  To: Arnd Bergmann
  Cc: devicetree@vger.kernel.org, linaro-kernel, linux-pci, Liviu Dudau,
	LKML, Will Deacon, Catalin Marinas, Bjorn Helgaas, LAKML
In-Reply-To: <18746655.qWHLpMg2Yy@wuerfel>

On Thu, 2014-02-27 at 14:38 +0100, Arnd Bergmann wrote:
> On Thursday 27 February 2014 13:06:42 Liviu Dudau wrote:
> > Several platforms use a rather generic version of parsing
> > the device tree to find the host bridge ranges. Move the common code
> > into the generic PCI code and use it to create a pci_host_bridge
> > structure that can be used by arch code.
> > 
> > Based on early attempts by Andrew Murray to unify the code.
> > Used powerpc and microblaze PCI code as starting point.

So that is only going to work for archs that don't have any special
twist. For example it won't work for powerpc which is why Andrew
original approach didn't fly.

The range walk helpers do help though, I need to review in more details
and test Andrew powerpc patch here and will merge it.

> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> 
> Please add Benjamin Herrenschmidt to Cc here, I think it would be helpful
> to get his input so we can make this work on powerpc as well.

Tricky... We would need hooks which would turn the whole thing into a
pile of spaghetti. I think we should stick to using the range helpers
(Andrew latest patch), which makes the powerpc code a lot smaller,
and leave it at that.

> > diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
> > index 06ace62..feb8436 100644
> > --- a/drivers/pci/host-bridge.c
> > +++ b/drivers/pci/host-bridge.c
> > @@ -6,9 +6,13 @@
> >  #include <linux/init.h>
> >  #include <linux/pci.h>
> >  #include <linux/module.h>
> > +#include <linux/of_address.h>
> > +#include <linux/of_pci.h>
> >  
> >  #include "pci.h"
> >  
> > +static int domain_nr;
> > +
> 
> For correctness, I think you want an 'atomic_t' here and use
> atomic_inc_return() to get a new value.
> 
> >  static struct pci_bus *find_pci_root_bus(struct pci_bus *bus)
> >  {
> >  	while (bus->parent)
> > @@ -91,3 +95,133 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
> >  	res->end = region->end + offset;
> >  }
> >  EXPORT_SYMBOL(pcibios_bus_to_resource);
> > +
> > +/**
> > + * pci_host_bridge_of_get_ranges - Parse PCI host bridge resources from DT
> > + * @dev: device node of the host bridge having the range property
> > + * @resources: list where the range of resources will be added after DT parsing
> > + * @io_base: pointer to a variable that will contain the physical address for
> > + * the start of the I/O range.
> > + *
> > + * If this function returns an error then the @resources list will be freed.
> > + *
> > + * This function will parse the "ranges" property of a PCI host bridge device
> > + * node and setup the resource mapping based on its content. It is expected
> > + * that the property conforms with the Power ePAPR document.
> > + *
> > + * Each architecture is then offered the chance of applying their own
> > + * filtering of pci_host_bridge_windows based on their own restrictions by
> > + * calling pcibios_fixup_bridge_ranges(). The filtered list of windows
> > + * can then be used when creating a pci_host_bridge structure.
> > + */
> > +static int pci_host_bridge_of_get_ranges(struct device_node *dev,
> > +		struct list_head *resources, resource_size_t *io_base)
> > +{
> > +	struct resource *res;
> > +	struct of_pci_range range;
> > +	struct of_pci_range_parser parser;
> > +	int err;
> > +
> > +	pr_info("PCI host bridge %s ranges:\n", dev->full_name);
> > +
> > +	/* Check for ranges property */
> > +	err = of_pci_range_parser_init(&parser, dev);
> > +	if (err)
> > +		return err;
> > +
> > +	pr_debug("Parsing ranges property...\n");
> > +	for_each_of_pci_range(&parser, &range) {
> > +		/* Read next ranges element */
> > +		pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > +				range.pci_space, range.pci_addr);
> > +		pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > +					range.cpu_addr, range.size);
> > +
> > +		/*
> > +		 * If we failed translation or got a zero-sized region
> > +		 * then skip this range
> > +		 */
> > +		if (range.cpu_addr == OF_BAD_ADDR || range.size == 0)
> > +			continue;

Shouldn't that test move into the parsing helper ?

> > +		res = kzalloc(sizeof(struct resource), GFP_KERNEL);
> > +		if (!res) {
> > +			err = -ENOMEM;
> > +			goto bridge_ranges_nomem;
> > +		}
> > +
> > +		of_pci_range_to_resource(&range, dev, res);
> > +
> > +		if (resource_type(res) == IORESOURCE_IO)
> > +			*io_base = range.cpu_addr;

You don't care about the size of the IO space ?

> > +		pci_add_resource_offset(resources, res,
> > +				res->start - range.pci_addr);
> > +	}
> 
> This is not the correct resource for I/O space at all. Please talk
> to Will, I've been over this with him in detail and he probably
> understands it now. I assume you are both working in the same
> building.

Yes, the IO offsets work differently on powerpc as well

> Since this is common PCI code, you could also decide to open-code
> the pci_add_resource_offset() function. If you don't do that, I
> think you have a memory leak for the resources that you can avoid
> by allocating the resource and pci_host_bridge_window structures
> together with a single kzalloc.
> 
> > +	/* Apply architecture specific fixups for the ranges */
> > +	pcibios_fixup_bridge_ranges(resources);
> > +
> > +	return 0;
> > +
> > +bridge_ranges_nomem:
> > +	pci_free_resource_list(resources);
> > +	return err;
> > +}
> > +
> > +/**
> > + * of_create_pci_host_bridge - Create a PCI host bridge structure using
> > + * information passed in the DT.
> > + * @parent: device owning this host bridge
> > + * @ops: pci_ops associated with the host controller
> > + * @host_data: opaque data structure used by the host controller.
> > + *
> > + * returns a pointer to the newly created pci_host_bridge structure, or
> > + * NULL if the call failed.
> > + *
> > + * This function will try to obtain the host bridge domain number by
> > + * using of_alias_get_id() call with "pci-domain" as a stem. If that
> > + * fails, a local allocator will be used that will put each host bridge
> > + * in a new domain.
> > + */
> > +struct pci_host_bridge *
> > +of_create_pci_host_bridge(struct device *parent, struct pci_ops *ops, void *host_data)
> > +{
> > +	int err, domain, busno;
> > +	struct resource bus_range;
> > +	struct pci_bus *root_bus;
> > +	struct pci_host_bridge *bridge;
> > +	resource_size_t io_base;
> > +	LIST_HEAD(res);
> > +
> > +	domain = of_alias_get_id(parent->of_node, "pci-domain");
> > +	if (domain == -ENODEV)
> > +		domain = domain_nr++;
> >
We probably want some uniqueness testing here.

> > +	err = of_pci_parse_bus_range(parent->of_node, &bus_range);
> > +	if (err) {
> > +		dev_info(parent, "No bus range for %s, using default [0-255]\n",
> > +			parent->of_node->full_name);
> > +		bus_range.start = 0;
> > +		bus_range.end = 255;
> > +		bus_range.flags = IORESOURCE_BUS;
> > +	}
> > +	busno = bus_range.start;
> > +	pci_add_resource(&res, &bus_range);
> > +
> > +	/* now parse the rest of host bridge bus ranges */
> > +	if (pci_host_bridge_of_get_ranges(parent->of_node, &res, &io_base))
> > +		return NULL;
> > +
> > +	/* then create the root bus */
> > +	root_bus = pci_create_root_bus_in_domain(parent, domain, busno,
> > +						ops, host_data, &res);
> > +	if (!root_bus)
> > +		return NULL;
> 
> Do we have any code that checks for conflicting domain/bus numbers here?
> I guess pci_create_root_bus_in_domain() will fail if you have that.
> 
> Since pci_create_root_bus_in_domain() is a new function that you just
> introduced, it would be helpful to change the calling conventions
> so it returns an error pointer instead of NULL upon failing.
> of_create_pci_host_bridge() can do the same, but pci_create_root_bus()
> should keep returning NULL so we don't have to change all the
> callers.
> 
> > +	bridge = to_pci_host_bridge(root_bus->bridge);
> > +	bridge->io_base = io_base;
> > +
> > +	return bridge;
> > +}
> > +EXPORT_SYMBOL_GPL(of_create_pci_host_bridge);
> > diff --git a/include/linux/pci.h b/include/linux/pci.h
> > index 1eed009..0c5e269 100644
> > --- a/include/linux/pci.h
> > +++ b/include/linux/pci.h
> > @@ -395,6 +395,7 @@ struct pci_host_bridge {
> >  	struct device dev;
> >  	struct pci_bus *bus;		/* root bus */
> >  	int domain_nr;
> > +	resource_size_t io_base;	/* physical address for the start of I/O area */
> >  	struct list_head windows;	/* pci_host_bridge_windows */
> >  	void (*release_fn)(struct pci_host_bridge *);
> >  	void *release_data;
> 
> What is the io_base used for here?
> 
> > @@ -1786,11 +1787,23 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
> >  	return bus ? bus->dev.of_node : NULL;
> >  }
> >  
> > +struct pci_host_bridge *
> > +of_create_pci_host_bridge(struct device *parent, struct pci_ops *ops,
> > +			void *host_data);
> > +
> > +void pcibios_fixup_bridge_ranges(struct list_head *resources);
> >  #else /* CONFIG_OF */
> >  static inline void pci_set_of_node(struct pci_dev *dev) { }
> >  static inline void pci_release_of_node(struct pci_dev *dev) { }
> >  static inline void pci_set_bus_of_node(struct pci_bus *bus) { }
> >  static inline void pci_release_bus_of_node(struct pci_bus *bus) { }
> > +
> > +static inline struct pci_host_bridge *
> > +pci_host_bridge_of_init(struct device *parent, struct pci_ops *ops,
> > +			void *host_data)
> > +{
> > +	return NULL;
> > +}
> >  #endif  /* CONFIG_OF */
> >  
> >  #ifdef CONFIG_EEH
> > 
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH] checkpatch: fix spurious vendor compatible warnings
From: Joe Perches @ 2014-02-27 23:53 UTC (permalink / raw)
  To: florian.vaussard-p8DiymsW2f8
  Cc: Andy Whitcroft, Rob Herring, devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <530F9F03.40803-p8DiymsW2f8@public.gmane.org>

On Thu, 2014-02-27 at 21:24 +0100, Florian Vaussard wrote:
> On 02/27/2014 09:10 PM, Joe Perches wrote:
> > On Thu, 2014-02-27 at 20:56 +0100, Florian Vaussard wrote:
> >> With a compatible string like
> >> compatible = "foo";
> >> checkpatch will currently try to find "foo" in  vendor-prefixes.txt,
> >> which is wrong since the vendor prefix is empty in this specific case.
[]
> > Some vendor names have dashes.
> > I don't know if underscores are allowed.
> > 
> > $ grep -rP --include=*.[ch] -oh "compatible\s*=\s*\"[^,]+,\w" * | \
> >   sed -r -e 's/\s//g' -e 's/,.$//' | sort | uniq -c | grep "[_-]"
> >       1 compatible="active-semi
> >       8 compatible="asahi-kasei
[]
> In ePAPR v1.1, I could not find any strict requirement. It
> is just saying:
> 
> The recommended format is “manufacturer,model”, where manufacturer is a
> string describing the name of the manufacturer (such as a stock ticker
> symbol), and model specifies the model number.

Should there also be a check in .c and .h files for
	.compatible = "somestring"
and
	OF_DEV_AUXDATA("somestring",,,,)

?

--
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 4/6] phy-rcar-usb-gen2: add device tree support
From: Sergei Shtylyov @ 2014-02-28  0:03 UTC (permalink / raw)
  To: Ben Dooks
  Cc: linux-kernel, linux-sh, Magnus Damm, Simon Horman,
	open list:OPEN FIRMWARE AND...
In-Reply-To: <530F61C4.7070706@codethink.co.uk>

Hello.

On 02/27/2014 07:03 PM, Ben Dooks wrote:

>>>>> Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
>>>>> Reviewed-by: Ian Molton <ian.molton@codethink.co.uk>
>>>>> ---
>>>>> Cc: linux-usb@vger.kernel.org (open list:USB PHY LAYER)
>>>>> Cc: linux-sh@vger.kernel.org (open list:ARM/SHMOBILE ARM...)
>>>>> Cc: Magnus Damm <magnus.damm@gmail.com> (supporter:ARM/SHMOBILE ARM...)
>>>>> Cc: Simon Horman <horms@verge.net.au> (supporter:ARM/SHMOBILE ARM...)
>>>>> Cc: devicetree@vger.kernel.org (open list:OPEN FIRMWARE AND...)
>>>>> ---
>>>>>   drivers/usb/phy/phy-rcar-gen2-usb.c | 35
>>>>> ++++++++++++++++++++++++++++++-----
>>>>>   1 file changed, 30 insertions(+), 5 deletions(-)

>>>>> diff --git a/drivers/usb/phy/phy-rcar-gen2-usb.c
>>>>> b/drivers/usb/phy/phy-rcar-gen2-usb.c
>>>>> index db3ab34..906b74b 100644
>>>>> --- a/drivers/usb/phy/phy-rcar-gen2-usb.c
>>>>> +++ b/drivers/usb/phy/phy-rcar-gen2-usb.c
>>>> [...]
>>>>> @@ -203,16 +212,31 @@ static int rcar_gen2_usb_phy_probe(struct
>>>>> platform_device *pdev)
>>>> [...]
>>>>> +    if (of_id) {
>> [...]
>>>>> +        int len = 0;
>>>>> +
>>>>> +        if (of_get_property(dev->of_node, "renesas,usb0-hs", &len))
>>>>> +            priv->ugctrl2 = USBHS_UGCTRL2_USB0_HS;
>>>>> +        else
>>>>> +            priv->ugctrl2 = USBHS_UGCTRL2_USB0_PCI;
>>>>> +
>>>>> +        if (of_get_property(dev->of_node, "renesas,usb2-ss", &len))
>>>>> +            priv->ugctrl2 |= USBHS_UGCTRL2_USB2_SS;

>>>>     Where is the bindings file you document these properties in?

>>> Should have been in another patch in the series.

>>     I didn't see it.

> I thought it went out, I will need to go check.

    It turned out that I'd already replied to that email that I had seen all 6 
patches but not the binding patch, so most probably it didn't went out that 
time. I've seen the latter patch (just not posted to linux-usb), so no problem 
here.

WBR, Sergei


^ permalink raw reply

* [PATCH] dma: of: Move the functions under CONFIG_OF_DMA instead of CONFIG_OF
From: Santosh Shilimkar @ 2014-02-28  0:20 UTC (permalink / raw)
  To: devicetree-u79uwXL29TY76Z2rM5mHXA
  Cc: arnd-r2nGTMty4D4,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	Santosh Shilimkar, Grant Likely, Rob Herring

The of-dma.c is compiled out with !CONFIG_OF_DMA but the functions in
the header are kept under CONFIG_OF. Move them under CONFIG_OF_DMA
to avoid build errors with CONFIG_OFF && !CONFIG_OF_DMA

Cc: Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
Cc: Rob Herring <robh+dt-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar-l0cyMroinI0@public.gmane.org>
---
 include/linux/of_dma.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index 0322363..3d2beab 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -31,7 +31,7 @@ struct of_dma_filter_info {
 	dma_filter_fn	filter_fn;
 };
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_OF_DMA
 extern int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
 		(struct of_phandle_args *, struct of_dma *),
-- 
1.7.9.5

--
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: [PATCHv2 14/16] ARM: OMAP3: hwmod data: cleanup data for IOMMUs
From: Tony Lindgren @ 2014-02-28  0:25 UTC (permalink / raw)
  To: Florian Vaussard
  Cc: devicetree-u79uwXL29TY76Z2rM5mHXA,
	linux-omap-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	Laurent Pinchart,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <530F0255.0-p8DiymsW2f8@public.gmane.org>

* Florian Vaussard <florian.vaussard-p8DiymsW2f8@public.gmane.org> [140227 01:19]:
> Hi,
> 
> On 02/26/2014 06:59 PM, Suman Anna wrote:
> > Tony,
> > 
> > On 02/26/2014 11:18 AM, Tony Lindgren wrote:
> >> * Suman Anna <s-anna-l0cyMroinI0@public.gmane.org> [140213 10:19]:
> >>> From: Florian Vaussard <florian.vaussard-p8DiymsW2f8@public.gmane.org>
> >>>
> >>> The irq numbers, ocp address space and device attribute data
> >>> have all been cleaned up for OMAP3 IOMMUs. All this data is
> >>> populated via the corresponding dt node.
> >>>
> >>> Signed-off-by: Florian Vaussard <florian.vaussard-p8DiymsW2f8@public.gmane.org>
> >>> Signed-off-by: Suman Anna <s-anna-l0cyMroinI0@public.gmane.org>
> >>
> >> This will need to wait until we've made omap3 to be DT only
> >> as this will break idling of things for the legacy booting.
> >>
> > 
> > OK, will drop this and I will adjust Patch 9 to support the legacy boot
> > for OMAP3 ISP.
> > 
> 
> BTW, Tony do you have a new window for omap3 to be DT onyl?

I think a good point would be when we have DSS working with DT,
and have a .dts file for the Pandora board.

Regards,

Tony

^ permalink raw reply

* Re: [PATCH] dma: of: Move the functions under CONFIG_OF_DMA instead of CONFIG_OF
From: Santosh Shilimkar @ 2014-02-28  0:27 UTC (permalink / raw)
  To: devicetree; +Cc: Grant Likely, Rob Herring, linux-arm-kernel, arnd
In-Reply-To: <1393546850-13907-1-git-send-email-santosh.shilimkar@ti.com>

On Thursday 27 February 2014 07:20 PM, Santosh Shilimkar wrote:
> The of-dma.c is compiled out with !CONFIG_OF_DMA but the functions in
> the header are kept under CONFIG_OF. Move them under CONFIG_OF_DMA
> to avoid build errors with CONFIG_OFF && !CONFIG_OF_DMA
> 
> Cc: Grant Likely <grant.likely@linaro.org>
> Cc: Rob Herring <robh+dt@kernel.org>
> Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
> ---
>  include/linux/of_dma.h |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
> index 0322363..3d2beab 100644
> --- a/include/linux/of_dma.h
> +++ b/include/linux/of_dma.h
> @@ -31,7 +31,7 @@ struct of_dma_filter_info {
>  	dma_filter_fn	filter_fn;
>  };
>  
> -#ifdef CONFIG_OF
> +#ifdef CONFIG_OF_DMA
Sorry.. Typo here.. Should have been CONFIG_DMA_OF

>From 31242461b6ba5e8c0c5ee26e394fa4cab61e3aa1 Mon Sep 17 00:00:00 2001
From: Santosh Shilimkar <santosh.shilimkar@ti.com>
Date: Thu, 27 Feb 2014 19:13:36 -0500
Subject: [PATCH] dma: of: Move the functions under CONFIG_DMA_OF instead of
 CONFIG_OF

The of-dma.c is compiled out with !CONFIG_DMA_OF but the functions in
the header are kept under CONFIG_OF. Move them under CONFIG_OF_DMA
to avoid build errors with CONFIG_OFF && !CONFIG_DMA_OF

Cc: Grant Likely <grant.likely@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com>
---
 include/linux/of_dma.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/linux/of_dma.h b/include/linux/of_dma.h
index 0322363..0ea24f4 100644
--- a/include/linux/of_dma.h
+++ b/include/linux/of_dma.h
@@ -31,7 +31,7 @@ struct of_dma_filter_info {
 	dma_filter_fn	filter_fn;
 };
 
-#ifdef CONFIG_OF
+#ifdef CONFIG_DMA_OF
 extern int of_dma_controller_register(struct device_node *np,
 		struct dma_chan *(*of_dma_xlate)
 		(struct of_phandle_args *, struct of_dma *),
-- 
1.7.9.5

^ permalink raw reply related

* Re: [PATCH] checkpatch: fix spurious vendor compatible warnings
From: Rob Herring @ 2014-02-28  1:24 UTC (permalink / raw)
  To: Joe Perches
  Cc: Florian Vaussard, Andy Whitcroft,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1393545229.24588.147.camel@joe-AO722>

On Thu, Feb 27, 2014 at 5:53 PM, Joe Perches <joe-6d6DIl74uiNBDgjK7y7TUQ@public.gmane.org> wrote:
> On Thu, 2014-02-27 at 21:24 +0100, Florian Vaussard wrote:
>> On 02/27/2014 09:10 PM, Joe Perches wrote:
>> > On Thu, 2014-02-27 at 20:56 +0100, Florian Vaussard wrote:
>> >> With a compatible string like
>> >> compatible = "foo";
>> >> checkpatch will currently try to find "foo" in  vendor-prefixes.txt,
>> >> which is wrong since the vendor prefix is empty in this specific case.
> []
>> > Some vendor names have dashes.
>> > I don't know if underscores are allowed.
>> >
>> > $ grep -rP --include=*.[ch] -oh "compatible\s*=\s*\"[^,]+,\w" * | \
>> >   sed -r -e 's/\s//g' -e 's/,.$//' | sort | uniq -c | grep "[_-]"
>> >       1 compatible="active-semi
>> >       8 compatible="asahi-kasei
> []
>> In ePAPR v1.1, I could not find any strict requirement. It
>> is just saying:
>>
>> The recommended format is "manufacturer,model", where manufacturer is a
>> string describing the name of the manufacturer (such as a stock ticker
>> symbol), and model specifies the model number.
>
> Should there also be a check in .c and .h files for
>         .compatible = "somestring"

Ideally, yes. I didn't do that because I figured there would be too
many variations in formatting compared to dts files.

> and
>         OF_DEV_AUXDATA("somestring",,,,)

Probably not. OF_DEV_AUXDATA is hopefully temporary. There are 156
instances now and it looks like they've been going down since 3.8.

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 v3 06/15] dt: binding: add binding for ImgTec IR block
From: Rob Herring @ 2014-02-28  1:28 UTC (permalink / raw)
  To: James Hogan
  Cc: Rob Herring, Mark Rutland, Mauro Carvalho Chehab,
	linux-media@vger.kernel.org, Pawel Moll, Ian Campbell, Kumar Gala,
	devicetree@vger.kernel.org, Rob Landley,
	linux-doc@vger.kernel.org, Tomasz Figa
In-Reply-To: <2514111.qYAaEZbJqk@radagast>

On Thu, Feb 27, 2014 at 4:52 PM, James Hogan <james.hogan@imgtec.com> wrote:
> Hi Rob, Mark + DT maintainers,
>
> On Friday 07 February 2014 15:49:15 James Hogan wrote:
>> Add device tree binding for ImgTec Consumer Infrared block, specifically
>> major revision 1 of the hardware.
>>
>> Signed-off-by: James Hogan <james.hogan@imgtec.com>
>> Cc: Mauro Carvalho Chehab <m.chehab@samsung.com>
>> Cc: linux-media@vger.kernel.org
>> Cc: Rob Herring <robh+dt@kernel.org>
>> Cc: Pawel Moll <pawel.moll@arm.com>
>> Cc: Mark Rutland <mark.rutland@arm.com>
>> Cc: Ian Campbell <ijc+devicetree@hellion.org.uk>
>> Cc: Kumar Gala <galak@codeaurora.org>
>> Cc: devicetree@vger.kernel.org
>> Cc: Rob Landley <rob@landley.net>
>> Cc: linux-doc@vger.kernel.org
>> Cc: Tomasz Figa <tomasz.figa@gmail.com>
>> ---
>> v3:
>> - Rename compatible string to "img,ir-rev1" (Rob Herring).
>> - Specify ordering of clocks explicitly (Rob Herring).
>
> I'd appreciate if somebody could give this another glance after the two
> changes listed above and Ack it (I'll probably be posting a v4 patchset
> tomorrow).

Looks fine.

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

>>
>> v2:
>> - Future proof compatible string from "img,ir" to "img,ir1", where the 1
>>   corresponds to the major revision number of the hardware (Tomasz
>>   Figa).
>> - Added clock-names property and three specific clock names described in
>>   the manual, only one of which is used by the current driver (Tomasz
>>   Figa).
>> ---
>>  .../devicetree/bindings/media/img-ir-rev1.txt      | 34
>> ++++++++++++++++++++++ 1 file changed, 34 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/media/img-ir-rev1.txt
>>
>> diff --git a/Documentation/devicetree/bindings/media/img-ir-rev1.txt
>> b/Documentation/devicetree/bindings/media/img-ir-rev1.txt new file mode
>> 100644
>> index 000000000000..5434ce61b925
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/media/img-ir-rev1.txt
>> @@ -0,0 +1,34 @@
>> +* ImgTec Infrared (IR) decoder version 1
>> +
>> +This binding is for Imagination Technologies' Infrared decoder block,
>> +specifically major revision 1.
>> +
>> +Required properties:
>> +- compatible:                Should be "img,ir-rev1"
>> +- reg:                       Physical base address of the controller and length of
>> +                     memory mapped region.
>> +- interrupts:                The interrupt specifier to the cpu.
>> +
>> +Optional properties:
>> +- clocks:            List of clock specifiers as described in standard
>> +                     clock bindings.
>> +                     Up to 3 clocks may be specified in the following order:
>> +                     1st:    Core clock (defaults to 32.768KHz if omitted).
>> +                     2nd:    System side (fast) clock.
>> +                     3rd:    Power modulation clock.
>> +- clock-names:               List of clock names corresponding to the clocks
>> +                     specified in the clocks property.
>> +                     Accepted clock names are:
>> +                     "core": Core clock.
>> +                     "sys":  System clock.
>> +                     "mod":  Power modulation clock.
>> +
>> +Example:
>> +
>> +     ir@02006200 {
>> +             compatible = "img,ir-rev1";
>> +             reg = <0x02006200 0x100>;
>> +             interrupts = <29 4>;
>> +             clocks = <&clk_32khz>;
>> +             clock-names =  "core";
>> +     };

^ permalink raw reply

* Re: [PATCH 1/1] Memory leak in scripts/dtc/util.c
From: Rob Herring @ 2014-02-28  1:32 UTC (permalink / raw)
  To: xypron.glpk, Jon Loeliger
  Cc: Grant Likely, Rob Herring, devicetree@vger.kernel.org,
	linux-kernel@vger.kernel.org
In-Reply-To: <1393525473-12238-1-git-send-email-xypron.glpk@gmx.de>

On Thu, Feb 27, 2014 at 12:24 PM,  <xypron.glpk@gmx.de> wrote:
> From: Heinrich Schuchardt <xypron.glpk@gmx.de>
>
> buf was leaked if out of memory
>
> Signed-off-by: Heinrich Schuchardt <xypron.glpk@gmx.de>
> ---
>  scripts/dtc/util.c |    2 ++
>  1 file changed, 2 insertions(+)

This needs to be made against upstream dtc repo (on kernel.org now).
Also, there is a newly created list for dtc specific topics:

http://vger.kernel.org/vger-lists.html#devicetree-compiler

Rob

>
> diff --git a/scripts/dtc/util.c b/scripts/dtc/util.c
> index 2422c34..a1e2e59 100644
> --- a/scripts/dtc/util.c
> +++ b/scripts/dtc/util.c
> @@ -210,9 +210,11 @@ int utilfdt_read_err(const char *filename, char **buffp)
>         do {
>                 /* Expand the buffer to hold the next chunk */
>                 if (offset == bufsize) {
> +                       char *buf_old = buf;
>                         bufsize *= 2;
>                         buf = realloc(buf, bufsize);
>                         if (!buf) {
> +                               buf = buf_old;
>                                 ret = ENOMEM;
>                                 break;
>                         }
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe devicetree" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* [PATCH v4 0/9] Use regmap+devm+DT in pm8xxx input drivers
From: Stephen Boyd @ 2014-02-28  1:55 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: devicetree, linux-arm-msm, Josh Cartwright, linux-kernel,
	linux-input, linux-arm-kernel

These patches move the pm8xxx input drivers over to use devm_* APIs
and regmap. This breaks the dependency of these drivers on the pm8xxx
specific read/write calls and also simplifies the probe code a bit.
Finally we add devicetree support to these drivers so they can be probed
on the platforms that are supported upstream.

Changes since v3:
 * Dropped devm conversion patch for pwrkey
 * Fixed compilation of keypad

Changes since v2:
 * Rebased to v3.14-rc3

Changes since v1:
 * Picked up Dmitry's version of devm for pwrkey
 * Added DT bindings and parsing patches
 * Dropped patches picked up by Dmitry

Stephen Boyd (9):
  Input: pmic8xxx-keypad - Fix build by removing gpio configuration
  Input: pmic8xxx-keypad - Migrate to devm_* APIs
  Input: pmic8xxx-keypad - Migrate to regmap APIs
  Input: pmic8xxx-keypad - Migrate to DT
  Input: pmic8xxx-pwrkey - Migrate to DT
  Input: pm8xxx-vibrator - Add DT match table
  devicetree: bindings: Document PM8921/8058 keypads
  devicetree: bindings: Document PM8921/8058 power keys
  devicetree: bindings: Document PM8921/8058 vibrators

 .../bindings/input/qcom,pm8xxx-keypad.txt          |  72 +++++
 .../bindings/input/qcom,pm8xxx-pwrkey.txt          |  39 +++
 .../devicetree/bindings/input/qcom,pm8xxx-vib.txt  |  16 +
 drivers/input/keyboard/pmic8xxx-keypad.c           | 348 ++++++++-------------
 drivers/input/misc/pm8xxx-vibrator.c               |   8 +
 drivers/input/misc/pmic8xxx-pwrkey.c               |  33 +-
 include/linux/input/pmic8xxx-keypad.h              |  52 ---
 include/linux/input/pmic8xxx-pwrkey.h              |  31 --
 8 files changed, 286 insertions(+), 313 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt
 delete mode 100644 include/linux/input/pmic8xxx-keypad.h
 delete mode 100644 include/linux/input/pmic8xxx-pwrkey.h

-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply

* [PATCH v4 7/9] devicetree: bindings: Document PM8921/8058 keypads
From: Stephen Boyd @ 2014-02-28  1:55 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-kernel, linux-arm-msm, linux-arm-kernel, Josh Cartwright,
	linux-input, devicetree
In-Reply-To: <1393552520-9068-1-git-send-email-sboyd@codeaurora.org>

Document the keypad device found on PM8921 and PM8058 PMICs.

Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 .../bindings/input/qcom,pm8xxx-keypad.txt          | 72 ++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt

diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
new file mode 100644
index 000000000000..aa5a9c6cf512
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-keypad.txt
@@ -0,0 +1,72 @@
+Qualcomm PM8xxx PMIC Keypad
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be one of:
+		    "qcom,pm8058-keypad"
+		    "qcom,pm8921-keypad"
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the first interrupt specifies the key sense interrupt
+		    and the second interrupt specifies the key stuck interrupt.
+		    The format of the specifier is defined by the binding
+		    document describing the node's interrupt parent.
+
+- linux,keymap:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the linux keymap. More information can be found in
+		    input/matrix-keymap.txt.
+
+- keypad,num-rows:
+	Usage: required
+	Value type: <u32>
+	Definition: number of rows in the keymap. More information can be found
+		    in input/matrix-keymap.txt.
+
+- keypad,num-columns:
+	Usage: required
+	Value type: <u32>
+	Definition: number of columns in the keymap. More information can be
+		    found in input/matrix-keymap.txt.
+
+- debounce:
+	Usage: optional
+	Value type: <u32>
+	Definition: time in microseconds that key must be pressed or release
+		    for key sense interrupt to trigger.
+
+- scan-delay:
+	Usage: optional
+	Value type: <u32>
+	Definition: time in microseconds to pause between successive scans
+		    of the matrix array.
+
+- row-hold:
+	Usage: optional
+	Value type: <u32>
+	Definition: time in nanoseconds to pause between scans of each row in
+		    the matrix array.
+
+EXAMPLE
+
+	keypad {
+		compatible = "qcom,pm8921-keypad";
+		interrupt-parent = <&pmicintc>;
+		interrupts = <74 1>, <75 1>;
+		linux,keymap = <
+			MATRIX_KEY(0, 0, KEY_VOLUMEUP)
+			MATRIX_KEY(0, 1, KEY_VOLUMEDOWN)
+			MATRIX_KEY(0, 2, KEY_CAMERA_FOCUS)
+			MATRIX_KEY(0, 3, KEY_CAMERA)
+			>;
+		keypad,num-rows = <1>;
+		keypad,num-columns = <5>;
+		debounce = <15>;
+		scan-delay = <32>;
+		row-hold = <91500>;
+	};
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply related

* [PATCH v4 8/9] devicetree: bindings: Document PM8921/8058 power keys
From: Stephen Boyd @ 2014-02-28  1:55 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-kernel, linux-arm-msm, linux-arm-kernel, Josh Cartwright,
	linux-input, devicetree
In-Reply-To: <1393552520-9068-1-git-send-email-sboyd@codeaurora.org>

Document the power key found on PM8921 and PM8058 PMICs.

Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 .../bindings/input/qcom,pm8xxx-pwrkey.txt          | 39 ++++++++++++++++++++++
 1 file changed, 39 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt

diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt
new file mode 100644
index 000000000000..e124d9f33632
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-pwrkey.txt
@@ -0,0 +1,39 @@
+Qualcomm PM8xxx PMIC Power Key
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be one of:
+		    "qcom,pm8058-pwrkey"
+		    "qcom,pm8921-pwrkey"
+- interrupts:
+	Usage: required
+	Value type: <prop-encoded-array>
+	Definition: the first interrupt specifies the key release interrupt
+		    and the second interrupt specifies the key press interrupt.
+		    The format of the specifier is defined by the binding
+		    document describing the node's interrupt parent.
+
+- debounce:
+	Usage: optional
+	Value type: <u32>
+	Definition: time in microseconds that key must be pressed or release
+		    for state change interrupt to trigger.
+
+- pull-up:
+	Usage: optional
+	Value type: <empty>
+	Definition: presence of this property indicates that the KPDPWR_N pin
+		    should be configured for pull up.
+
+EXAMPLE
+
+	pwrkey {
+		compatible = "qcom,pm8921-pwrkey";
+		interrupt-parent = <&pmicintc>;
+		interrupts = <50 1>, <51 1>;
+		debounce = <15625>;
+		pull-up;
+	};
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply related

* [PATCH v4 9/9] devicetree: bindings: Document PM8921/8058 vibrators
From: Stephen Boyd @ 2014-02-28  1:55 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-kernel, linux-arm-msm, linux-arm-kernel, Josh Cartwright,
	linux-input, devicetree
In-Reply-To: <1393552520-9068-1-git-send-email-sboyd@codeaurora.org>

Document the vibration device found on PM8921 and PM8058 PMICs.

Cc: <devicetree@vger.kernel.org>
Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
---
 .../devicetree/bindings/input/qcom,pm8xxx-vib.txt        | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt

diff --git a/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt
new file mode 100644
index 000000000000..dca1b8872cf1
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/qcom,pm8xxx-vib.txt
@@ -0,0 +1,16 @@
+Qualcomm PM8xxx PMIC Vibrator
+
+PROPERTIES
+
+- compatible:
+	Usage: required
+	Value type: <string>
+	Definition: must be one of:
+		    "qcom,pm8058-vib"
+		    "qcom,pm8921-vib"
+
+EXAMPLE
+
+	vibrator {
+		compatible = "qcom,pm8058-vib";
+	};
-- 
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
hosted by The Linux Foundation

^ permalink raw reply related

* Re: [PATCHv1 1/2] rx51_battery: convert to iio consumer
From: Sebastian Reichel @ 2014-02-28  2:05 UTC (permalink / raw)
  To: Belisko Marek
  Cc: Dmitry Eremin-Solenikov, David Woodhouse, Jonathan Cameron,
	Rob Herring, Pawel Moll, Mark Rutland, Ian Campbell, Kumar Gala,
	Grant Likely, LKML, devicetree@vger.kernel.org, linux-iio,
	Pali Rohár
In-Reply-To: <CAAfyv340pA2ihUAoFytBgevLtedvtj5Z0aw_=G9Rbx5occtyqw@mail.gmail.com>

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

On Thu, Feb 27, 2014 at 10:34:35PM +0100, Belisko Marek wrote:
> Well I've tried and it's worse :). I got during booting:
> [    2.218383] ERROR: could not get IIO channel /battery:temp(0)
> [    2.224639] platform battery.4: Driver twl4030_madc_battery
> requests probe deferral
> Not sure if it's just error or warning but temp is always reported as
> 0 (and also other values in sysfs).

This is an error, which basically means, that twl4030-madc has not
yet been loaded. Do you get proper values when you use the old madc
API with the patchset applied?

-- Sebastian

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 819 bytes --]

^ permalink raw reply

* RE: [PATCH v4] can: xilinx CAN controller support.
From: Appana Durga Kedareswara Rao @ 2014-02-28  5:50 UTC (permalink / raw)
  To: Marc Kleine-Budde, wg@grandegger.com, Michal Simek,
	grant.likely@linaro.org, robh+dt@kernel.org,
	linux-can@vger.kernel.org
  Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <530E0B92.5010903@pengutronix.de>

Hi Marc,


> -----Original Message-----
> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> Sent: Wednesday, February 26, 2014 9:13 PM
> To: Appana Durga Kedareswara Rao; wg@grandegger.com; Michal Simek;
> grant.likely@linaro.org; robh+dt@kernel.org; linux-can@vger.kernel.org
> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
> kernel@vger.kernel.org; devicetree@vger.kernel.org
> Subject: Re: [PATCH v4] can: xilinx CAN controller support.
>
> On 02/26/2014 03:46 PM, Appana Durga Kedareswara Rao wrote:
> > Hi Marc,
> >
> >
> >> -----Original Message-----
> >> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
> >> Sent: Wednesday, February 26, 2014 6:52 PM
> >> To: Appana Durga Kedareswara Rao; wg@grandegger.com; Michal Simek;
> >> grant.likely@linaro.org; robh+dt@kernel.org;
> >> linux-can@vger.kernel.org
> >> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
> >> linux- kernel@vger.kernel.org; devicetree@vger.kernel.org
> >> Subject: Re: [PATCH v4] can: xilinx CAN controller support.
> >>
> >> On 02/26/2014 02:07 PM, Appana Durga Kedareswara Rao wrote:
> >>>> This loop looks broken. Can you explain how it works.
> >>>>
> >>>> What it shoud do is:
> >>>> We have put (priv->tx_head - priv->tx_tail) CAN frames into the FIFO.
> >>>> This means at maximum there could be this amount of CAN frames
> >>>> which have been successfully transmitted. For every cycle in this
> >>>> while loop you
> >>>> should:
> >>>> a) check if a CAN frame has successfully been transmitted
> >>>>    (as this CAN core uses a FIFO it should be "oldest")
> >>>>    A read_reg() of some kind is missing in your loop.
> >>>> b) if needed, remove this event from the FIFO or
> >>>>    mark the interrupt as done. Whatever you hardware needs.
> >>>> c) update your statistics
> >>>> d) Use can_get_echo_skb to push this frame into the networking
> >>>> stack
> >>>> e) As a CAN frame has been transmitted successfully, wake the
> tx_queue.
> >>>>
> >>>>> +   while (priv->tx_head - priv->tx_tail > 0) {
> >>>>> +           if (isr & XCAN_IXR_TXFLL_MASK) {
> >>>>> +                   priv->write_reg(priv, XCAN_ICR_OFFSET,
> >>>>> +                                   XCAN_IXR_TXFLL_MASK);
> >>>>> +                   netif_stop_queue(ndev);
> >>>>
> >>>> Why do you stop the queue here? A CAN frame has successfully been
> >>>> transmitted, there should be room in the FIFO.
> >>>>
> >>>>> +                   break;
> >>>>> +           }
> >>>>> +           can_get_echo_skb(ndev, priv->tx_tail %
> >>>>> +                                   priv->xcan_echo_skb_max_tx);
> >>>>> +           priv->tx_tail++;
> >>>>> +   }
> >>>>> +
> >>>
> >>> The below are the bit fields available for the Transmit FIFO.
> >>> 1) In the ISR(interrupt status register)  Tx Ok interrupt and Tx
> >>> fifo full
> >> interrupt.
> >>> 2) in the SR(Status Register) Tx fifo full condition.
> >>>
> >>>
> >>> I am modifying the entire tx interrupt logic to like below.
> >>>
> >>> static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) {
> >>>         struct xcan_priv *priv = netdev_priv(ndev);
> >>>         struct net_device_stats *stats = &ndev->stats;
> >>>
> >>>             while (priv->tx_head - priv->tx_tail > 0) {
> >>>                 if (isr & XCAN_IXR_TXFLL_MASK) {
> >>>                         priv->write_reg(priv, XCAN_ICR_OFFSET,
> >>>                                         XCAN_IXR_TXFLL_MASK);
> >>>                           break;
> >>>                 }
> >>>                 can_get_echo_skb(ndev, priv->tx_tail %
> >>>                                         priv->xcan_echo_skb_max_tx);
> >>>                 priv->tx_tail++;
> >>>          stats->tx_packets++;
> >>>         netif_wake_queue(ndev);
> >>>               can_led_event(ndev, CAN_LED_EVENT_TX);
> >>>
> >>>         }
> >>
> >> You just need to wake the queue once.
> >
> > Ok
> >>
> >>> }
> >>>
> >>>
> >>> Are you Ok with the above logic?
> >>
> >> No, how can you tell how many frames have been transmitted?
> >
> > There is no register to read how many can frames are transmitted.
> > The only way to know Is by reading this parameter
> > (stats->tx_packets++;) through ip command
>
> stats->tx_packets is calculated in the above loop and the loop is
> broken. Let me illustrate the problem:
>
> - xmit is called 10 times in a row
> - this means you have 10 CAN frames in the TX FIFO
> - a single CAN frame gets transmitted
> - you get an interrupt
> - you enter the above routine and loop 10 times and echo the CAN frame
>   back into the stack
>
> Now every application sees 10 transmitted packages, but there is only one
> transmitted. Every time you loop you have to check if the CAN frame has
> already been transmitted or not. Is that possible with the hardware?

        The only way to know whether the TX packet is transmitted successfully or not is by using the Tx Ok interrupt from the ISR.
This interrupt will come for every Tx Packet.
So I am thinking of there is no loop required in the TX interrupt routine. As it is called for each and every packet.

static void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
{
        struct xcan_priv *priv = netdev_priv(ndev);
        struct net_device_stats *stats = &ndev->stats;


        can_get_echo_skb(ndev, priv->tx_tail %
                                priv->xcan_echo_skb_max_tx);
        priv->tx_tail++;
        stats->tx_packets++;
        can_led_event(ndev, CAN_LED_EVENT_TX);
        netif_wake_queue(ndev);
}

If you want me to put some locks for this Will put some spin_locks in the _xmit and in the tx interrupt routine (for the tx_head and tx_tail).


Regards,
Kedar.

>
> > ip -d -s link show can
> > Or using ifconfig command.
> >
> > At the h/w level it can transmit Max upto 64 packets (Max fifo depth)
> > We need to monitor the Tx fifo full bit in the ISR(Interrupt Status Register)
> or Tx fifo full bit in the SR(Status Register) and if it is full we need to stop
> the queue that is
> > I am doing in the _xmit by reading the status register before proceeding
> the   packet transmission.
>
> Marc
>
> --
> Pengutronix e.K.                  | Marc Kleine-Budde           |
> Industrial Linux Solutions        | Phone: +49-231-2826-924     |
> Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
> Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |



This email and any attachments are intended for the sole use of the named recipient(s) and contain(s) confidential information that may be proprietary, privileged or copyrighted under applicable law. If you are not the intended recipient, do not read, copy, or forward this email message or any attachments. Delete this email message and any attachments immediately.




^ permalink raw reply

* Re: [PATCH v3] hwspinlock/msm: Add support for Qualcomm MSM HW Mutex block
From: Bjorn Andersson @ 2014-02-28  5:52 UTC (permalink / raw)
  To: Kumar Gala
  Cc: Ohad Ben-Cohen, Rob Herring, Pawel Moll, Mark Rutland,
	Stephen Warren, Ian Campbell, Grant Likely,
	devicetree@vger.kernel.org, linux-kernel@vger.kernel.org,
	linux-arm-msm, Jeffrey Hugo, Eric Holmberg
In-Reply-To: <1376507361-26907-1-git-send-email-galak@codeaurora.org>

Hi Kumar,

I pulled this in to my 3.14 tree and gave it a spin. But I keep
hitting the case of unlock below telling me that someone else is
holding the lock.

On Wed, Aug 14, 2013 at 12:09 PM, Kumar Gala <galak@codeaurora.org> wrote:
[...]
> +
> +static int msm_hwspinlock_trylock(struct hwspinlock *lock)
> +{
> +       void __iomem *lock_addr = lock->priv;
> +
> +       writel_relaxed(SPINLOCK_ID_APPS_PROC, lock_addr);

You need some sort of barrier here; the caf code have a smp_mb() here,
inserting that solves the problem.

> +
> +       return readl_relaxed(lock_addr) == SPINLOCK_ID_APPS_PROC;
> +}
> +
> +static void msm_hwspinlock_unlock(struct hwspinlock *lock)
> +{
> +       u32 lock_owner;
> +       void __iomem *lock_addr = lock->priv;
> +
> +       lock_owner = readl_relaxed(lock_addr);
> +       if (lock_owner != SPINLOCK_ID_APPS_PROC) {
> +               pr_err("%s: spinlock not owned by us (actual owner is %d)\n",
> +                               __func__, lock_owner);
> +       }
> +
> +       writel_relaxed(0, lock_addr);
> +}
> +

Part of this I think this driver looks good, it would be nice to get
the last details cleaned up so we could get it into the tree.

Regards,
Bjorn

^ permalink raw reply

* Re: [PATCH V2 1/3] dt: palmas: support IRQ inversion at the board level
From: Mark Brown @ 2014-02-28  5:58 UTC (permalink / raw)
  To: Stephen Warren
  Cc: Graeme Gregory, Mark Rutland, devicetree-u79uwXL29TY76Z2rM5mHXA,
	Stephen Warren, Samuel Ortiz, Pawel Moll, Ian Campbell, J Keerthy,
	Ian Lartey, Rob Herring, Kumar Gala,
	linux-tegra-u79uwXL29TY76Z2rM5mHXA, Lee Jones,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
In-Reply-To: <530FAFAE.5050800-3lzwWm7+Weoh9ZMKESR00Q@public.gmane.org>

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

On Thu, Feb 27, 2014 at 02:35:42PM -0700, Stephen Warren wrote:
> On 02/27/2014 02:02 PM, Graeme Gregory wrote:

> >> +- ti,irq-externally-inverted : If missing, the polarity of the Palmas IRQ
> >> +  output should be set to the opposite of the polarity indicated by the IRQ
> >> +  specifier in the interrupts property. If absent, the polarity should be
> >> +  configured to match. This allows the representation of an inverter between
> >> +  the Palmas IRQ output and the interrupt parent's IRQ input.

> > This has got to be the wrong way to do things, all this leads to is every
> > device doing this property in its own way and having totally inconsistent
> > properties all meaning the same thing.

> > If there is some other hardware inverting lines then there should be
> > a generic binding for this in DT. This is not describing the palmas hardware
> > but some external object to the palmas.

> I'd be fine with removing the "ti," vendor prefix from the property
> name, and promoting it to be a cross-device standard.

> I'm not sure that many devices will need this though; most don't have
> configurable output polarity. Still, I guess that shouldn't stop us from
> creating standards for the cases where it is needed.

It's really common for PMICs and CODECs to be able to set any interrupt
polarity at least.

> If the DT reviewers can ack the concept, I'm happy to respin the patch
> with the more generic property name.

I'm not sure that renaming the property really deals with the concerns
though since drivers still all need to manually add support for this,
shouldn't there be an interrupt controller described in the DT which
just chains on to the parent with the polarity inverted to do the
impedence match?

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH] ARM: dts: am335x-evmsk: enable USB1
From: yegorslists @ 2014-02-28  7:19 UTC (permalink / raw)
  To: linux-omap; +Cc: tony, devicetree, linux-arm-kernel, Yegor Yefremov

From: Yegor Yefremov <yegorslists@googlemail.com>

Enable second USB channel and set it into 'host' mode.

Signed-off-by: Yegor Yefremov <yegorslists@googlemail.com>
---
 arch/arm/boot/dts/am335x-evmsk.dts |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/am335x-evmsk.dts b/arch/arm/boot/dts/am335x-evmsk.dts
index 486880b..40a66bd 100644
--- a/arch/arm/boot/dts/am335x-evmsk.dts
+++ b/arch/arm/boot/dts/am335x-evmsk.dts
@@ -342,9 +342,18 @@
 		status = "okay";
 	};
 
+	usb-phy@47401b00 {
+		status = "okay";
+	};
+
 	usb@47401000 {
 		status = "okay";
 	};
+
+	usb@47401800 {
+		status = "okay";
+		dr_mode = "host";
+	};
 };
 
 &epwmss2 {
-- 
1.7.7

^ permalink raw reply related

* Re: [RFC PATCH v4 3/8] staging: imx-drm: Document updated imx-drm device tree bindings
From: Tomi Valkeinen @ 2014-02-28  7:36 UTC (permalink / raw)
  To: Philipp Zabel
  Cc: devel, devicetree, Russell King - ARM Linux, David Airlie,
	Greg Kroah-Hartman, dri-devel, Laurent Pinchart, kernel,
	Grant Likely, Shawn Guo, linux-arm-kernel
In-Reply-To: <1393520088.4507.92.camel@paszta.hi.pengutronix.de>


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

On 27/02/14 18:54, Philipp Zabel wrote:

>> - One IPU enabled, one disabled: nothing special here, just set the
>> other IPU to status="disabled" in the DT data. The driver for the
>> enabled IPU would register the required DRM entities.
> 
> that should work. Let the enabled IPU create the imx-drm platform device
> on probe, parse the device tree and ignore everything only hanging off
> of the disabled IPU.

I think you misunderstood me a bit.

What I meant is that there's no need for imx-drm device at all, neither
in the DT data or in the kernel side.

There'd just be the DT nodes for the IPUs, which would cause the IPU
platform devices to be created, and a driver for the IPU. So just like
for any other normal platform device.

In the simplest cases, where only one IPU is enabled, or the IPUs want
to be considered as totally independent, there'd be nothing special. The
IPU driver would just register the drm entities.

> [Reordering a bit...]
>> - Two IPUs in combined mode:
>>
>> Pick one IPU as the master, and one as slave. Link the IPU nodes in DT
>> data with phandles, say: master=<&ipu1> on the slave IPU and
>> slave=<&ipu0> on the master.
>>
>> The master one will register the DRM entities, and the slave one will
>> just do what the master says.
> 
> That might work, too. Just let the each IPU scan the graph and try to
> find the imx-drm master before creating the imx-drm platform device.
> The first IPU fill find no preexisting master and create the imx-drm
> platform device as above, adding the other IPU as well as the other
> components with component_master_add_child. It just has to make sure
> that the other IPU is added to the list before the encoders are.
> 
> The second IPU will scan the graph, find a preexisting master for the
> other IPU node, register its component and just wait to be bound by the
> master.

Here the slave IPU doesn't need to scan the graph at all. It just needs
to make itself available somehow to the master. Maybe just by exported
functions, or registering itself somewhere.

Only the master IPU will scan the graph, and as all the entities are
connected to the same graph, including the slave IPU, the master can
find all the relevant nodes.

>> - Two IPUs as separate units: almost the same as above, but both would
>> independently register the DRM entities.
> 
> Here the second IPU would not be connected to the first IPU via the
> graph - it would not find a preexisting imx-drm device when scanning its
> graph and create its own imx-drm device just like the first IPU did.
> As a result there are two completely separate DRM devices.

I understood that that would be the idea, two separate, independent DRM
devices. Like two graphics cards on a PC.

> That being said, this change could be made at any time in the future,
> in a backwards compatible fashion, by just declaring the imx-drm node
> optional and ignoring it if it exists.

Yes, I agree.

And I don't even know if the master-slave method I described is valid,
although I don't see why it would not work. The master
"display-subsystem" DT node does make sense to me in cases like this,
where the IPUs need to be driven as a single unit.

> Did anybody propose such a generic term? How about:
> 
> -imx-drm {
> -	compatible = "fsl,imx-drm";
> -	ports = <&ipu1_di0>, <&ipu1_di1>;
> -};
> +display-subsystem {
> +	compatible = "fsl,imx-display-subsystem";
> +	ports = <&ipu1_di0>, <&ipu1_di1>;
> +};

That sounds fine to me.

I wonder how it works if, say, there are 4 IPUs, and you want to run
them in two pairs. In that case you need two of those display-subsystem
nodes. But I guess it's just a matter of assigning a number for them
with 'regs' property, and making sure the driver has nothing that
prevents multiple instances of it.

>>> If this wasn't the case, we wouldn't even attempt to describe what devices
>>> we have on which I2C buses - we'd just list the hardware on the board
>>> without giving any information about how it's wired together.
>>>
>>> This is no different - however, it doesn't have (and shouldn't) be
>>> subsystem specific... but - and this is the challenge we then face - how
>>> do you decide that on one board with a single zImage kernel, with both
>>> DRM and fbdev built-in, whether to use the DRM interfaces or the fbdev
>>> interfaces?  We could have both matching the same compatible string, but
>>> we'd also need some way to tell each other that they're not allowed to
>>> bind.
>>
>> Yes, that's an annoying problem, we have that on OMAP. It's a clear sign
>> that our video support is rather messed up.
>>
>> My opinion is that the fbdev and drm drivers for a single hardware
>> should be exclusive at compile time. We don't allow multiple drivers for
>> single device for other subsystems either, do we? Eventually we should
>> have only one driver for one hardware device.
>>
>> If that's not possible, then the drivers in question could have an
>> option to enable or disable themselves, passed via the kernel command
>> line, so that the user can select which subsystem to use.
> 
> That is the exact same problem as having multiple drivers that can bind
> to the same device.

Hmm, sorry? Weren't we just discussing about that problem =). Or maybe I
missed the original point from Russell, as the problem about DRM and
fbdev conflicting sounded a bit unrelated.

> For i.MX, for now, let's keep the mandatory imx-drm node. Maybe rename
> it so nobody can say we are leaking linux subsystem names into the
> device tree.

Sounds good to me.

 Tomi



[-- Attachment #1.2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 901 bytes --]

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

_______________________________________________
devel mailing list
devel@linuxdriverproject.org
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel

^ permalink raw reply

* [PATCH v5 5/8 fix] mtd: m25p80: use the SPI nor framework
From: Huang Shijie @ 2014-02-28  7:55 UTC (permalink / raw)
  To: dwmw2
  Cc: computersforpeace, angus.clark, lee.jones, pekon, sourav.poddar,
	broonie, linux-mtd, linux-spi, linux-arm-kernel, linux-doc,
	devicetree, shawn.guo, Huang Shijie
In-Reply-To: <1393238262-8622-6-git-send-email-b32955@freescale.com>

Use the new SPI nor framework, and rewrite the m25p80:
 (0) remove all the NOR comands.
 (1) change the m25p->command to an array.
 (2) implement the necessary hooks, such as m25p80_read/m25p80_write.

Tested with the m25p32.
Signed-off-by: Huang Shijie <b32955@freescale.com>
---
add back the dependency information in the Kconfig. 

---
 drivers/mtd/devices/Kconfig  |    2 +-
 drivers/mtd/devices/m25p80.c | 1302 ++++--------------------------------------
 2 files changed, 106 insertions(+), 1198 deletions(-)

diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 0128138..004b17b 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -80,7 +80,7 @@ config MTD_DATAFLASH_OTP
 
 config MTD_M25P80
 	tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
-	depends on SPI_MASTER
+	depends on SPI_MASTER && MTD_SPI_NOR_BASE
 	help
 	  This enables access to most modern SPI flash chips, used for
 	  program and data storage.   Series supported include Atmel AT26DF,
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 882b720..4af6400 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -19,485 +19,98 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/mutex.h>
-#include <linux/math64.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/mod_devicetable.h>
 
-#include <linux/mtd/cfi.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <linux/of_platform.h>
 
 #include <linux/spi/spi.h>
 #include <linux/spi/flash.h>
+#include <linux/mtd/spi-nor.h>
 
-/* Flash opcodes. */
-#define	OPCODE_WREN		0x06	/* Write enable */
-#define	OPCODE_RDSR		0x05	/* Read status register */
-#define	OPCODE_WRSR		0x01	/* Write status register 1 byte */
-#define	OPCODE_NORM_READ	0x03	/* Read data bytes (low frequency) */
-#define	OPCODE_FAST_READ	0x0b	/* Read data bytes (high frequency) */
-#define	OPCODE_DUAL_READ        0x3b    /* Read data bytes (Dual SPI) */
-#define	OPCODE_QUAD_READ        0x6b    /* Read data bytes (Quad SPI) */
-#define	OPCODE_PP		0x02	/* Page program (up to 256 bytes) */
-#define	OPCODE_BE_4K		0x20	/* Erase 4KiB block */
-#define	OPCODE_BE_4K_PMC	0xd7	/* Erase 4KiB block on PMC chips */
-#define	OPCODE_BE_32K		0x52	/* Erase 32KiB block */
-#define	OPCODE_CHIP_ERASE	0xc7	/* Erase whole flash chip */
-#define	OPCODE_SE		0xd8	/* Sector erase (usually 64KiB) */
-#define	OPCODE_RDID		0x9f	/* Read JEDEC ID */
-#define	OPCODE_RDCR             0x35    /* Read configuration register */
-
-/* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
-#define	OPCODE_NORM_READ_4B	0x13	/* Read data bytes (low frequency) */
-#define	OPCODE_FAST_READ_4B	0x0c	/* Read data bytes (high frequency) */
-#define	OPCODE_DUAL_READ_4B	0x3c    /* Read data bytes (Dual SPI) */
-#define	OPCODE_QUAD_READ_4B	0x6c    /* Read data bytes (Quad SPI) */
-#define	OPCODE_PP_4B		0x12	/* Page program (up to 256 bytes) */
-#define	OPCODE_SE_4B		0xdc	/* Sector erase (usually 64KiB) */
-
-/* Used for SST flashes only. */
-#define	OPCODE_BP		0x02	/* Byte program */
-#define	OPCODE_WRDI		0x04	/* Write disable */
-#define	OPCODE_AAI_WP		0xad	/* Auto address increment word program */
-
-/* Used for Macronix and Winbond flashes. */
-#define	OPCODE_EN4B		0xb7	/* Enter 4-byte mode */
-#define	OPCODE_EX4B		0xe9	/* Exit 4-byte mode */
-
-/* Used for Spansion flashes only. */
-#define	OPCODE_BRWR		0x17	/* Bank register write */
-
-/* Status Register bits. */
-#define	SR_WIP			1	/* Write in progress */
-#define	SR_WEL			2	/* Write enable latch */
-/* meaning of other SR_* bits may differ between vendors */
-#define	SR_BP0			4	/* Block protect 0 */
-#define	SR_BP1			8	/* Block protect 1 */
-#define	SR_BP2			0x10	/* Block protect 2 */
-#define	SR_SRWD			0x80	/* SR write protect */
-
-#define SR_QUAD_EN_MX           0x40    /* Macronix Quad I/O */
-
-/* Configuration Register bits. */
-#define CR_QUAD_EN_SPAN		0x2     /* Spansion Quad I/O */
-
-/* Define max times to check status register before we give up. */
-#define	MAX_READY_WAIT_JIFFIES	(40 * HZ)	/* M25P16 specs 40s max chip erase */
 #define	MAX_CMD_SIZE		6
-
-#define JEDEC_MFR(_jedec_id)	((_jedec_id) >> 16)
-
-/****************************************************************************/
-
-enum read_type {
-	M25P80_NORMAL = 0,
-	M25P80_FAST,
-	M25P80_DUAL,
-	M25P80_QUAD,
-};
-
 struct m25p {
 	struct spi_device	*spi;
-	struct mutex		lock;
+	struct spi_nor		spi_nor;
 	struct mtd_info		mtd;
-	u16			page_size;
-	u16			addr_width;
-	u8			erase_opcode;
-	u8			read_opcode;
-	u8			program_opcode;
-	u8			*command;
-	enum read_type		flash_read;
+	u8			command[MAX_CMD_SIZE];
 };
 
-static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
-{
-	return container_of(mtd, struct m25p, mtd);
-}
-
-/****************************************************************************/
-
-/*
- * Internal helper functions
- */
-
-/*
- * Read the status register, returning its value in the location
- * Return the status register value.
- * Returns negative if error occurred.
- */
-static int read_sr(struct m25p *flash)
-{
-	ssize_t retval;
-	u8 code = OPCODE_RDSR;
-	u8 val;
-
-	retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
-
-	if (retval < 0) {
-		dev_err(&flash->spi->dev, "error %d reading SR\n",
-				(int) retval);
-		return retval;
-	}
-
-	return val;
-}
-
-/*
- * Read configuration register, returning its value in the
- * location. Return the configuration register value.
- * Returns negative if error occured.
- */
-static int read_cr(struct m25p *flash)
-{
-	u8 code = OPCODE_RDCR;
-	int ret;
-	u8 val;
-
-	ret = spi_write_then_read(flash->spi, &code, 1, &val, 1);
-	if (ret < 0) {
-		dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
-		return ret;
-	}
-
-	return val;
-}
-
-/*
- * Write status register 1 byte
- * Returns negative if error occurred.
- */
-static int write_sr(struct m25p *flash, u8 val)
-{
-	flash->command[0] = OPCODE_WRSR;
-	flash->command[1] = val;
-
-	return spi_write(flash->spi, flash->command, 2);
-}
-
-/*
- * Set write enable latch with Write Enable command.
- * Returns negative if error occurred.
- */
-static inline int write_enable(struct m25p *flash)
-{
-	u8	code = OPCODE_WREN;
-
-	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
-}
-
-/*
- * Send write disble instruction to the chip.
- */
-static inline int write_disable(struct m25p *flash)
-{
-	u8	code = OPCODE_WRDI;
-
-	return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
-}
-
-/*
- * Enable/disable 4-byte addressing mode.
- */
-static inline int set_4byte(struct m25p *flash, u32 jedec_id, int enable)
-{
-	int status;
-	bool need_wren = false;
-
-	switch (JEDEC_MFR(jedec_id)) {
-	case CFI_MFR_ST: /* Micron, actually */
-		/* Some Micron need WREN command; all will accept it */
-		need_wren = true;
-	case CFI_MFR_MACRONIX:
-	case 0xEF /* winbond */:
-		if (need_wren)
-			write_enable(flash);
-
-		flash->command[0] = enable ? OPCODE_EN4B : OPCODE_EX4B;
-		status = spi_write(flash->spi, flash->command, 1);
-
-		if (need_wren)
-			write_disable(flash);
-
-		return status;
-	default:
-		/* Spansion style */
-		flash->command[0] = OPCODE_BRWR;
-		flash->command[1] = enable << 7;
-		return spi_write(flash->spi, flash->command, 2);
-	}
-}
-
-/*
- * Service routine to read status register until ready, or timeout occurs.
- * Returns non-zero if error.
- */
-static int wait_till_ready(struct m25p *flash)
-{
-	unsigned long deadline;
-	int sr;
-
-	deadline = jiffies + MAX_READY_WAIT_JIFFIES;
-
-	do {
-		if ((sr = read_sr(flash)) < 0)
-			break;
-		else if (!(sr & SR_WIP))
-			return 0;
-
-		cond_resched();
-
-	} while (!time_after_eq(jiffies, deadline));
-
-	return 1;
-}
-
-/*
- * Write status Register and configuration register with 2 bytes
- * The first byte will be written to the status register, while the
- * second byte will be written to the configuration register.
- * Return negative if error occured.
- */
-static int write_sr_cr(struct m25p *flash, u16 val)
-{
-	flash->command[0] = OPCODE_WRSR;
-	flash->command[1] = val & 0xff;
-	flash->command[2] = (val >> 8);
-
-	return spi_write(flash->spi, flash->command, 3);
-}
-
-static int macronix_quad_enable(struct m25p *flash)
-{
-	int ret, val;
-	u8 cmd[2];
-	cmd[0] = OPCODE_WRSR;
-
-	val = read_sr(flash);
-	cmd[1] = val | SR_QUAD_EN_MX;
-	write_enable(flash);
-
-	spi_write(flash->spi, &cmd, 2);
-
-	if (wait_till_ready(flash))
-		return 1;
-
-	ret = read_sr(flash);
-	if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
-		dev_err(&flash->spi->dev, "Macronix Quad bit not set\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int spansion_quad_enable(struct m25p *flash)
+static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
 {
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
 	int ret;
-	int quad_en = CR_QUAD_EN_SPAN << 8;
-
-	write_enable(flash);
 
-	ret = write_sr_cr(flash, quad_en);
-	if (ret < 0) {
-		dev_err(&flash->spi->dev,
-			"error while writing configuration register\n");
-		return -EINVAL;
-	}
-
-	/* read back and check it */
-	ret = read_cr(flash);
-	if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
-		dev_err(&flash->spi->dev, "Spansion Quad bit not set\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int set_quad_mode(struct m25p *flash, u32 jedec_id)
-{
-	int status;
-
-	switch (JEDEC_MFR(jedec_id)) {
-	case CFI_MFR_MACRONIX:
-		status = macronix_quad_enable(flash);
-		if (status) {
-			dev_err(&flash->spi->dev,
-				"Macronix quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	default:
-		status = spansion_quad_enable(flash);
-		if (status) {
-			dev_err(&flash->spi->dev,
-				"Spansion quad-read not enabled\n");
-			return -EINVAL;
-		}
-		return status;
-	}
-}
-
-/*
- * Erase the whole flash memory
- *
- * Returns 0 if successful, non-zero otherwise.
- */
-static int erase_chip(struct m25p *flash)
-{
-	pr_debug("%s: %s %lldKiB\n", dev_name(&flash->spi->dev), __func__,
-			(long long)(flash->mtd.size >> 10));
+	ret = spi_write_then_read(spi, &code, 1, val, len);
+	if (ret < 0)
+		dev_err(&spi->dev, "error %d reading %x\n", ret, code);
 
-	/* Wait until finished previous write command. */
-	if (wait_till_ready(flash))
-		return 1;
-
-	/* Send write enable, then erase commands. */
-	write_enable(flash);
-
-	/* Set up command buffer. */
-	flash->command[0] = OPCODE_CHIP_ERASE;
-
-	spi_write(flash->spi, flash->command, 1);
-
-	return 0;
+	return ret;
 }
 
-static void m25p_addr2cmd(struct m25p *flash, unsigned int addr, u8 *cmd)
+static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
 {
 	/* opcode is in cmd[0] */
-	cmd[1] = addr >> (flash->addr_width * 8 -  8);
-	cmd[2] = addr >> (flash->addr_width * 8 - 16);
-	cmd[3] = addr >> (flash->addr_width * 8 - 24);
-	cmd[4] = addr >> (flash->addr_width * 8 - 32);
+	cmd[1] = addr >> (nor->addr_width * 8 -  8);
+	cmd[2] = addr >> (nor->addr_width * 8 - 16);
+	cmd[3] = addr >> (nor->addr_width * 8 - 24);
+	cmd[4] = addr >> (nor->addr_width * 8 - 32);
 }
 
-static int m25p_cmdsz(struct m25p *flash)
+static int m25p_cmdsz(struct spi_nor *nor)
 {
-	return 1 + flash->addr_width;
+	return 1 + nor->addr_width;
 }
 
-/*
- * Erase one sector of flash memory at offset ``offset'' which is any
- * address within the sector which should be erased.
- *
- * Returns 0 if successful, non-zero otherwise.
- */
-static int erase_sector(struct m25p *flash, u32 offset)
+static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len,
+			int wr_en)
 {
-	pr_debug("%s: %s %dKiB at 0x%08x\n", dev_name(&flash->spi->dev),
-			__func__, flash->mtd.erasesize / 1024, offset);
-
-	/* Wait until finished previous write command. */
-	if (wait_till_ready(flash))
-		return 1;
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
 
-	/* Send write enable, then erase commands. */
-	write_enable(flash);
-
-	/* Set up command buffer. */
-	flash->command[0] = flash->erase_opcode;
-	m25p_addr2cmd(flash, offset, flash->command);
-
-	spi_write(flash->spi, flash->command, m25p_cmdsz(flash));
+	flash->command[0] = opcode;
+	if (buf)
+		memcpy(&flash->command[1], buf, len);
 
-	return 0;
+	return spi_write(spi, flash->command, len + 1);
 }
 
-/****************************************************************************/
-
-/*
- * MTD implementation
- */
-
-/*
- * Erase an address range on the flash chip.  The address range may extend
- * one or more erase sectors.  Return an error is there is a problem erasing.
- */
-static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
+static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
+			size_t *retlen, const u_char *buf)
 {
-	struct m25p *flash = mtd_to_m25p(mtd);
-	u32 addr,len;
-	uint32_t rem;
-
-	pr_debug("%s: %s at 0x%llx, len %lld\n", dev_name(&flash->spi->dev),
-			__func__, (long long)instr->addr,
-			(long long)instr->len);
-
-	div_u64_rem(instr->len, mtd->erasesize, &rem);
-	if (rem)
-		return -EINVAL;
-
-	addr = instr->addr;
-	len = instr->len;
-
-	mutex_lock(&flash->lock);
-
-	/* whole-chip erase? */
-	if (len == flash->mtd.size) {
-		if (erase_chip(flash)) {
-			instr->state = MTD_ERASE_FAILED;
-			mutex_unlock(&flash->lock);
-			return -EIO;
-		}
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
+	struct spi_transfer t[2] = {};
+	struct spi_message m;
+	int cmd_sz = m25p_cmdsz(nor);
 
-	/* REVISIT in some cases we could speed up erasing large regions
-	 * by using OPCODE_SE instead of OPCODE_BE_4K.  We may have set up
-	 * to use "small sector erase", but that's not always optimal.
-	 */
+	spi_message_init(&m);
 
-	/* "sector"-at-a-time erase */
-	} else {
-		while (len) {
-			if (erase_sector(flash, addr)) {
-				instr->state = MTD_ERASE_FAILED;
-				mutex_unlock(&flash->lock);
-				return -EIO;
-			}
+	if (nor->program_opcode == OPCODE_AAI_WP && nor->sst_write_second)
+		cmd_sz = 1;
 
-			addr += mtd->erasesize;
-			len -= mtd->erasesize;
-		}
-	}
+	flash->command[0] = nor->program_opcode;
+	m25p_addr2cmd(nor, to, flash->command);
 
-	mutex_unlock(&flash->lock);
+	t[0].tx_buf = flash->command;
+	t[0].len = cmd_sz;
+	spi_message_add_tail(&t[0], &m);
 
-	instr->state = MTD_ERASE_DONE;
-	mtd_erase_callback(instr);
+	t[1].tx_buf = buf;
+	t[1].len = len;
+	spi_message_add_tail(&t[1], &m);
 
-	return 0;
-}
+	spi_sync(spi, &m);
 
-/*
- * Dummy Cycle calculation for different type of read.
- * It can be used to support more commands with
- * different dummy cycle requirements.
- */
-static inline int m25p80_dummy_cycles_read(struct m25p *flash)
-{
-	switch (flash->flash_read) {
-	case M25P80_FAST:
-	case M25P80_DUAL:
-	case M25P80_QUAD:
-		return 1;
-	case M25P80_NORMAL:
-		return 0;
-	default:
-		dev_err(&flash->spi->dev, "No valid read type supported\n");
-		return -1;
-	}
+	*retlen += m.actual_length - cmd_sz;
 }
 
-static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
+static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
 {
-	switch (flash->flash_read) {
-	case M25P80_DUAL:
+	switch (nor->flash_read) {
+	case SPI_NOR_DUAL:
 		return 2;
-	case M25P80_QUAD:
+	case SPI_NOR_QUAD:
 		return 4;
 	default:
 		return 0;
@@ -505,589 +118,72 @@ static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
 }
 
 /*
- * Read an address range from the flash chip.  The address range
+ * Read an address range from the nor chip.  The address range
  * may be any size provided it is within the physical boundaries.
  */
-static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
-	size_t *retlen, u_char *buf)
+static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
+			size_t *retlen, u_char *buf)
 {
-	struct m25p *flash = mtd_to_m25p(mtd);
+	struct m25p *flash = nor->priv;
+	struct spi_device *spi = flash->spi;
 	struct spi_transfer t[2];
 	struct spi_message m;
-	uint8_t opcode;
-	int dummy;
+	int dummy = nor->read_dummy;
+	int ret;
 
-	pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-			__func__, (u32)from, len);
+	/* Wait till previous write/erase is done. */
+	ret = nor->wait_till_ready(nor);
+	if (ret)
+		return ret;
 
 	spi_message_init(&m);
 	memset(t, 0, (sizeof t));
 
-	dummy =  m25p80_dummy_cycles_read(flash);
-	if (dummy < 0) {
-		dev_err(&flash->spi->dev, "No valid read command supported\n");
-		return -EINVAL;
-	}
+	flash->command[0] = nor->read_opcode;
+	m25p_addr2cmd(nor, from, flash->command);
 
 	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(flash) + dummy;
+	t[0].len = m25p_cmdsz(nor) + dummy;
 	spi_message_add_tail(&t[0], &m);
 
 	t[1].rx_buf = buf;
-	t[1].rx_nbits = m25p80_rx_nbits(flash);
+	t[1].rx_nbits = m25p80_rx_nbits(nor);
 	t[1].len = len;
 	spi_message_add_tail(&t[1], &m);
 
-	mutex_lock(&flash->lock);
-
-	/* Wait till previous write/erase is done. */
-	if (wait_till_ready(flash)) {
-		/* REVISIT status return?? */
-		mutex_unlock(&flash->lock);
-		return 1;
-	}
-
-	/* Set up the write data buffer. */
-	opcode = flash->read_opcode;
-	flash->command[0] = opcode;
-	m25p_addr2cmd(flash, from, flash->command);
-
-	spi_sync(flash->spi, &m);
-
-	*retlen = m.actual_length - m25p_cmdsz(flash) - dummy;
-
-	mutex_unlock(&flash->lock);
+	spi_sync(spi, &m);
 
+	*retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
 	return 0;
 }
 
-/*
- * Write an address range to the flash chip.  Data must be written in
- * FLASH_PAGESIZE chunks.  The address range may be any size provided
- * it is within the physical boundaries.
- */
-static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
-	size_t *retlen, const u_char *buf)
+static int m25p80_erase(struct spi_nor *nor, loff_t offset)
 {
-	struct m25p *flash = mtd_to_m25p(mtd);
-	u32 page_offset, page_size;
-	struct spi_transfer t[2];
-	struct spi_message m;
-
-	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-			__func__, (u32)to, len);
-
-	spi_message_init(&m);
-	memset(t, 0, (sizeof t));
-
-	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(flash);
-	spi_message_add_tail(&t[0], &m);
-
-	t[1].tx_buf = buf;
-	spi_message_add_tail(&t[1], &m);
-
-	mutex_lock(&flash->lock);
-
-	/* Wait until finished previous write command. */
-	if (wait_till_ready(flash)) {
-		mutex_unlock(&flash->lock);
-		return 1;
-	}
-
-	write_enable(flash);
-
-	/* Set up the opcode in the write buffer. */
-	flash->command[0] = flash->program_opcode;
-	m25p_addr2cmd(flash, to, flash->command);
-
-	page_offset = to & (flash->page_size - 1);
-
-	/* do all the bytes fit onto one page? */
-	if (page_offset + len <= flash->page_size) {
-		t[1].len = len;
-
-		spi_sync(flash->spi, &m);
-
-		*retlen = m.actual_length - m25p_cmdsz(flash);
-	} else {
-		u32 i;
-
-		/* the size of data remaining on the first page */
-		page_size = flash->page_size - page_offset;
-
-		t[1].len = page_size;
-		spi_sync(flash->spi, &m);
-
-		*retlen = m.actual_length - m25p_cmdsz(flash);
-
-		/* write everything in flash->page_size chunks */
-		for (i = page_size; i < len; i += page_size) {
-			page_size = len - i;
-			if (page_size > flash->page_size)
-				page_size = flash->page_size;
-
-			/* write the next page to flash */
-			m25p_addr2cmd(flash, to + i, flash->command);
-
-			t[1].tx_buf = buf + i;
-			t[1].len = page_size;
-
-			wait_till_ready(flash);
-
-			write_enable(flash);
-
-			spi_sync(flash->spi, &m);
-
-			*retlen += m.actual_length - m25p_cmdsz(flash);
-		}
-	}
-
-	mutex_unlock(&flash->lock);
-
-	return 0;
-}
-
-static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
-		size_t *retlen, const u_char *buf)
-{
-	struct m25p *flash = mtd_to_m25p(mtd);
-	struct spi_transfer t[2];
-	struct spi_message m;
-	size_t actual;
-	int cmd_sz, ret;
-
-	pr_debug("%s: %s to 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
-			__func__, (u32)to, len);
-
-	spi_message_init(&m);
-	memset(t, 0, (sizeof t));
-
-	t[0].tx_buf = flash->command;
-	t[0].len = m25p_cmdsz(flash);
-	spi_message_add_tail(&t[0], &m);
-
-	t[1].tx_buf = buf;
-	spi_message_add_tail(&t[1], &m);
+	struct m25p *flash = nor->priv;
+	int ret;
 
-	mutex_lock(&flash->lock);
+	dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
+		flash->mtd.erasesize / 1024, (u32)offset);
 
 	/* Wait until finished previous write command. */
-	ret = wait_till_ready(flash);
+	ret = nor->wait_till_ready(nor);
 	if (ret)
-		goto time_out;
-
-	write_enable(flash);
-
-	actual = to % 2;
-	/* Start write from odd address. */
-	if (actual) {
-		flash->command[0] = OPCODE_BP;
-		m25p_addr2cmd(flash, to, flash->command);
-
-		/* write one byte. */
-		t[1].len = 1;
-		spi_sync(flash->spi, &m);
-		ret = wait_till_ready(flash);
-		if (ret)
-			goto time_out;
-		*retlen += m.actual_length - m25p_cmdsz(flash);
-	}
-	to += actual;
-
-	flash->command[0] = OPCODE_AAI_WP;
-	m25p_addr2cmd(flash, to, flash->command);
-
-	/* Write out most of the data here. */
-	cmd_sz = m25p_cmdsz(flash);
-	for (; actual < len - 1; actual += 2) {
-		t[0].len = cmd_sz;
-		/* write two bytes. */
-		t[1].len = 2;
-		t[1].tx_buf = buf + actual;
+		return ret;
 
-		spi_sync(flash->spi, &m);
-		ret = wait_till_ready(flash);
-		if (ret)
-			goto time_out;
-		*retlen += m.actual_length - cmd_sz;
-		cmd_sz = 1;
-		to += 2;
-	}
-	write_disable(flash);
-	ret = wait_till_ready(flash);
+	/* Send write enable, then erase commands. */
+	ret = nor->write_reg(nor, OPCODE_WREN, NULL, 0, 0);
 	if (ret)
-		goto time_out;
-
-	/* Write out trailing byte if it exists. */
-	if (actual != len) {
-		write_enable(flash);
-		flash->command[0] = OPCODE_BP;
-		m25p_addr2cmd(flash, to, flash->command);
-		t[0].len = m25p_cmdsz(flash);
-		t[1].len = 1;
-		t[1].tx_buf = buf + actual;
-
-		spi_sync(flash->spi, &m);
-		ret = wait_till_ready(flash);
-		if (ret)
-			goto time_out;
-		*retlen += m.actual_length - m25p_cmdsz(flash);
-		write_disable(flash);
-	}
-
-time_out:
-	mutex_unlock(&flash->lock);
-	return ret;
-}
-
-static int m25p80_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-	struct m25p *flash = mtd_to_m25p(mtd);
-	uint32_t offset = ofs;
-	uint8_t status_old, status_new;
-	int res = 0;
-
-	mutex_lock(&flash->lock);
-	/* Wait until finished previous command */
-	if (wait_till_ready(flash)) {
-		res = 1;
-		goto err;
-	}
-
-	status_old = read_sr(flash);
-
-	if (offset < flash->mtd.size-(flash->mtd.size/2))
-		status_new = status_old | SR_BP2 | SR_BP1 | SR_BP0;
-	else if (offset < flash->mtd.size-(flash->mtd.size/4))
-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
-	else if (offset < flash->mtd.size-(flash->mtd.size/8))
-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-	else if (offset < flash->mtd.size-(flash->mtd.size/16))
-		status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
-	else if (offset < flash->mtd.size-(flash->mtd.size/32))
-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-	else if (offset < flash->mtd.size-(flash->mtd.size/64))
-		status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
-	else
-		status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
-
-	/* Only modify protection if it will not unlock other areas */
-	if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) >
-					(status_old&(SR_BP2|SR_BP1|SR_BP0))) {
-		write_enable(flash);
-		if (write_sr(flash, status_new) < 0) {
-			res = 1;
-			goto err;
-		}
-	}
-
-err:	mutex_unlock(&flash->lock);
-	return res;
-}
-
-static int m25p80_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
-{
-	struct m25p *flash = mtd_to_m25p(mtd);
-	uint32_t offset = ofs;
-	uint8_t status_old, status_new;
-	int res = 0;
-
-	mutex_lock(&flash->lock);
-	/* Wait until finished previous command */
-	if (wait_till_ready(flash)) {
-		res = 1;
-		goto err;
-	}
-
-	status_old = read_sr(flash);
-
-	if (offset+len > flash->mtd.size-(flash->mtd.size/64))
-		status_new = status_old & ~(SR_BP2|SR_BP1|SR_BP0);
-	else if (offset+len > flash->mtd.size-(flash->mtd.size/32))
-		status_new = (status_old & ~(SR_BP2|SR_BP1)) | SR_BP0;
-	else if (offset+len > flash->mtd.size-(flash->mtd.size/16))
-		status_new = (status_old & ~(SR_BP2|SR_BP0)) | SR_BP1;
-	else if (offset+len > flash->mtd.size-(flash->mtd.size/8))
-		status_new = (status_old & ~SR_BP2) | SR_BP1 | SR_BP0;
-	else if (offset+len > flash->mtd.size-(flash->mtd.size/4))
-		status_new = (status_old & ~(SR_BP0|SR_BP1)) | SR_BP2;
-	else if (offset+len > flash->mtd.size-(flash->mtd.size/2))
-		status_new = (status_old & ~SR_BP1) | SR_BP2 | SR_BP0;
-	else
-		status_new = (status_old & ~SR_BP0) | SR_BP2 | SR_BP1;
-
-	/* Only modify protection if it will not lock other areas */
-	if ((status_new&(SR_BP2|SR_BP1|SR_BP0)) <
-					(status_old&(SR_BP2|SR_BP1|SR_BP0))) {
-		write_enable(flash);
-		if (write_sr(flash, status_new) < 0) {
-			res = 1;
-			goto err;
-		}
-	}
-
-err:	mutex_unlock(&flash->lock);
-	return res;
-}
-
-/****************************************************************************/
-
-/*
- * SPI device driver setup and teardown
- */
-
-struct flash_info {
-	/* JEDEC id zero means "no ID" (most older chips); otherwise it has
-	 * a high byte of zero plus three data bytes: the manufacturer id,
-	 * then a two byte device id.
-	 */
-	u32		jedec_id;
-	u16             ext_id;
-
-	/* The size listed here is what works with OPCODE_SE, which isn't
-	 * necessarily called a "sector" by the vendor.
-	 */
-	unsigned	sector_size;
-	u16		n_sectors;
-
-	u16		page_size;
-	u16		addr_width;
-
-	u16		flags;
-#define	SECT_4K		0x01		/* OPCODE_BE_4K works uniformly */
-#define	M25P_NO_ERASE	0x02		/* No erase command needed */
-#define	SST_WRITE	0x04		/* use SST byte programming */
-#define	M25P_NO_FR	0x08		/* Can't do fastread */
-#define	SECT_4K_PMC	0x10		/* OPCODE_BE_4K_PMC works uniformly */
-#define	M25P80_DUAL_READ	0x20    /* Flash supports Dual Read */
-#define	M25P80_QUAD_READ	0x40    /* Flash supports Quad Read */
-};
-
-#define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)	\
-	((kernel_ulong_t)&(struct flash_info) {				\
-		.jedec_id = (_jedec_id),				\
-		.ext_id = (_ext_id),					\
-		.sector_size = (_sector_size),				\
-		.n_sectors = (_n_sectors),				\
-		.page_size = 256,					\
-		.flags = (_flags),					\
-	})
-
-#define CAT25_INFO(_sector_size, _n_sectors, _page_size, _addr_width, _flags)	\
-	((kernel_ulong_t)&(struct flash_info) {				\
-		.sector_size = (_sector_size),				\
-		.n_sectors = (_n_sectors),				\
-		.page_size = (_page_size),				\
-		.addr_width = (_addr_width),				\
-		.flags = (_flags),					\
-	})
-
-/* NOTE: double check command sets and memory organization when you add
- * more flash chips.  This current list focusses on newer chips, which
- * have been converging on command sets which including JEDEC ID.
- */
-static const struct spi_device_id m25p_ids[] = {
-	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
-	{ "at25fs010",  INFO(0x1f6601, 0, 32 * 1024,   4, SECT_4K) },
-	{ "at25fs040",  INFO(0x1f6604, 0, 64 * 1024,   8, SECT_4K) },
-
-	{ "at25df041a", INFO(0x1f4401, 0, 64 * 1024,   8, SECT_4K) },
-	{ "at25df321a", INFO(0x1f4701, 0, 64 * 1024,  64, SECT_4K) },
-	{ "at25df641",  INFO(0x1f4800, 0, 64 * 1024, 128, SECT_4K) },
-
-	{ "at26f004",   INFO(0x1f0400, 0, 64 * 1024,  8, SECT_4K) },
-	{ "at26df081a", INFO(0x1f4501, 0, 64 * 1024, 16, SECT_4K) },
-	{ "at26df161a", INFO(0x1f4601, 0, 64 * 1024, 32, SECT_4K) },
-	{ "at26df321",  INFO(0x1f4700, 0, 64 * 1024, 64, SECT_4K) },
-
-	{ "at45db081d", INFO(0x1f2500, 0, 64 * 1024, 16, SECT_4K) },
-
-	/* EON -- en25xxx */
-	{ "en25f32",    INFO(0x1c3116, 0, 64 * 1024,   64, SECT_4K) },
-	{ "en25p32",    INFO(0x1c2016, 0, 64 * 1024,   64, 0) },
-	{ "en25q32b",   INFO(0x1c3016, 0, 64 * 1024,   64, 0) },
-	{ "en25p64",    INFO(0x1c2017, 0, 64 * 1024,  128, 0) },
-	{ "en25q64",    INFO(0x1c3017, 0, 64 * 1024,  128, SECT_4K) },
-	{ "en25qh256",  INFO(0x1c7019, 0, 64 * 1024,  512, 0) },
-
-	/* ESMT */
-	{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
-
-	/* Everspin */
-	{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, M25P_NO_ERASE | M25P_NO_FR) },
-	{ "mr25h10",  CAT25_INFO(128 * 1024, 1, 256, 3, M25P_NO_ERASE | M25P_NO_FR) },
-
-	/* GigaDevice */
-	{ "gd25q32", INFO(0xc84016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
-
-	/* Intel/Numonyx -- xxxs33b */
-	{ "160s33b",  INFO(0x898911, 0, 64 * 1024,  32, 0) },
-	{ "320s33b",  INFO(0x898912, 0, 64 * 1024,  64, 0) },
-	{ "640s33b",  INFO(0x898913, 0, 64 * 1024, 128, 0) },
-
-	/* Macronix */
-	{ "mx25l2005a",  INFO(0xc22012, 0, 64 * 1024,   4, SECT_4K) },
-	{ "mx25l4005a",  INFO(0xc22013, 0, 64 * 1024,   8, SECT_4K) },
-	{ "mx25l8005",   INFO(0xc22014, 0, 64 * 1024,  16, 0) },
-	{ "mx25l1606e",  INFO(0xc22015, 0, 64 * 1024,  32, SECT_4K) },
-	{ "mx25l3205d",  INFO(0xc22016, 0, 64 * 1024,  64, 0) },
-	{ "mx25l3255e",  INFO(0xc29e16, 0, 64 * 1024,  64, SECT_4K) },
-	{ "mx25l6405d",  INFO(0xc22017, 0, 64 * 1024, 128, 0) },
-	{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
-	{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
-	{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
-	{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
-	{ "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) },
-
-	/* Micron */
-	{ "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
-	{ "n25q128a11",  INFO(0x20bb18, 0, 64 * 1024,  256, 0) },
-	{ "n25q128a13",  INFO(0x20ba18, 0, 64 * 1024,  256, 0) },
-	{ "n25q256a",    INFO(0x20ba19, 0, 64 * 1024,  512, SECT_4K) },
-	{ "n25q512a",    INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
-
-	/* PMC */
-	{ "pm25lv512",   INFO(0,        0, 32 * 1024,    2, SECT_4K_PMC) },
-	{ "pm25lv010",   INFO(0,        0, 32 * 1024,    4, SECT_4K_PMC) },
-	{ "pm25lq032",   INFO(0x7f9d46, 0, 64 * 1024,   64, SECT_4K) },
-
-	/* Spansion -- single (large) sector size only, at least
-	 * for the chips listed here (without boot sectors).
-	 */
-	{ "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 0) },
-	{ "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
-	{ "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
-	{ "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, M25P80_DUAL_READ | M25P80_QUAD_READ) },
-	{ "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_DUAL_READ | M25P80_QUAD_READ) },
-	{ "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
-	{ "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
-	{ "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
-	{ "s25fl129p0", INFO(0x012018, 0x4d00, 256 * 1024,  64, 0) },
-	{ "s25fl129p1", INFO(0x012018, 0x4d01,  64 * 1024, 256, 0) },
-	{ "s25sl004a",  INFO(0x010212,      0,  64 * 1024,   8, 0) },
-	{ "s25sl008a",  INFO(0x010213,      0,  64 * 1024,  16, 0) },
-	{ "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
-	{ "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
-	{ "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
-	{ "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
-	{ "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
-	{ "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
-
-	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
-	{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-	{ "sst25vf080b", INFO(0xbf258e, 0, 64 * 1024, 16, SECT_4K | SST_WRITE) },
-	{ "sst25vf016b", INFO(0xbf2541, 0, 64 * 1024, 32, SECT_4K | SST_WRITE) },
-	{ "sst25vf032b", INFO(0xbf254a, 0, 64 * 1024, 64, SECT_4K | SST_WRITE) },
-	{ "sst25vf064c", INFO(0xbf254b, 0, 64 * 1024, 128, SECT_4K) },
-	{ "sst25wf512",  INFO(0xbf2501, 0, 64 * 1024,  1, SECT_4K | SST_WRITE) },
-	{ "sst25wf010",  INFO(0xbf2502, 0, 64 * 1024,  2, SECT_4K | SST_WRITE) },
-	{ "sst25wf020",  INFO(0xbf2503, 0, 64 * 1024,  4, SECT_4K | SST_WRITE) },
-	{ "sst25wf040",  INFO(0xbf2504, 0, 64 * 1024,  8, SECT_4K | SST_WRITE) },
-
-	/* ST Microelectronics -- newer production may have feature updates */
-	{ "m25p05",  INFO(0x202010,  0,  32 * 1024,   2, 0) },
-	{ "m25p10",  INFO(0x202011,  0,  32 * 1024,   4, 0) },
-	{ "m25p20",  INFO(0x202012,  0,  64 * 1024,   4, 0) },
-	{ "m25p40",  INFO(0x202013,  0,  64 * 1024,   8, 0) },
-	{ "m25p80",  INFO(0x202014,  0,  64 * 1024,  16, 0) },
-	{ "m25p16",  INFO(0x202015,  0,  64 * 1024,  32, 0) },
-	{ "m25p32",  INFO(0x202016,  0,  64 * 1024,  64, 0) },
-	{ "m25p64",  INFO(0x202017,  0,  64 * 1024, 128, 0) },
-	{ "m25p128", INFO(0x202018,  0, 256 * 1024,  64, 0) },
-	{ "n25q032", INFO(0x20ba16,  0,  64 * 1024,  64, 0) },
-
-	{ "m25p05-nonjedec",  INFO(0, 0,  32 * 1024,   2, 0) },
-	{ "m25p10-nonjedec",  INFO(0, 0,  32 * 1024,   4, 0) },
-	{ "m25p20-nonjedec",  INFO(0, 0,  64 * 1024,   4, 0) },
-	{ "m25p40-nonjedec",  INFO(0, 0,  64 * 1024,   8, 0) },
-	{ "m25p80-nonjedec",  INFO(0, 0,  64 * 1024,  16, 0) },
-	{ "m25p16-nonjedec",  INFO(0, 0,  64 * 1024,  32, 0) },
-	{ "m25p32-nonjedec",  INFO(0, 0,  64 * 1024,  64, 0) },
-	{ "m25p64-nonjedec",  INFO(0, 0,  64 * 1024, 128, 0) },
-	{ "m25p128-nonjedec", INFO(0, 0, 256 * 1024,  64, 0) },
-
-	{ "m45pe10", INFO(0x204011,  0, 64 * 1024,    2, 0) },
-	{ "m45pe80", INFO(0x204014,  0, 64 * 1024,   16, 0) },
-	{ "m45pe16", INFO(0x204015,  0, 64 * 1024,   32, 0) },
-
-	{ "m25pe20", INFO(0x208012,  0, 64 * 1024,  4,       0) },
-	{ "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
-	{ "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
-
-	{ "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, SECT_4K) },
-	{ "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
-	{ "m25px64",    INFO(0x207117,  0, 64 * 1024, 128, 0) },
-
-	/* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
-	{ "w25x10", INFO(0xef3011, 0, 64 * 1024,  2,  SECT_4K) },
-	{ "w25x20", INFO(0xef3012, 0, 64 * 1024,  4,  SECT_4K) },
-	{ "w25x40", INFO(0xef3013, 0, 64 * 1024,  8,  SECT_4K) },
-	{ "w25x80", INFO(0xef3014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25x16", INFO(0xef3015, 0, 64 * 1024,  32, SECT_4K) },
-	{ "w25x32", INFO(0xef3016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25q32", INFO(0xef4016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25q32dw", INFO(0xef6016, 0, 64 * 1024,  64, SECT_4K) },
-	{ "w25x64", INFO(0xef3017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q64", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
-	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
-	{ "w25q80", INFO(0xef5014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25q80bl", INFO(0xef4014, 0, 64 * 1024,  16, SECT_4K) },
-	{ "w25q128", INFO(0xef4018, 0, 64 * 1024, 256, SECT_4K) },
-	{ "w25q256", INFO(0xef4019, 0, 64 * 1024, 512, SECT_4K) },
-
-	/* Catalyst / On Semiconductor -- non-JEDEC */
-	{ "cat25c11", CAT25_INFO(  16, 8, 16, 1, M25P_NO_ERASE | M25P_NO_FR) },
-	{ "cat25c03", CAT25_INFO(  32, 8, 16, 2, M25P_NO_ERASE | M25P_NO_FR) },
-	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
-	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2, M25P_NO_ERASE | M25P_NO_FR) },
-	{ "cat25128", CAT25_INFO(2048, 8, 64, 2, M25P_NO_ERASE | M25P_NO_FR) },
-	{ },
-};
-MODULE_DEVICE_TABLE(spi, m25p_ids);
-
-static const struct spi_device_id *jedec_probe(struct spi_device *spi)
-{
-	int			tmp;
-	u8			code = OPCODE_RDID;
-	u8			id[5];
-	u32			jedec;
-	u16                     ext_jedec;
-	struct flash_info	*info;
+		return ret;
 
-	/* JEDEC also defines an optional "extended device information"
-	 * string for after vendor-specific data, after the three bytes
-	 * we use here.  Supporting some chips might require using it.
-	 */
-	tmp = spi_write_then_read(spi, &code, 1, id, 5);
-	if (tmp < 0) {
-		pr_debug("%s: error %d reading JEDEC ID\n",
-				dev_name(&spi->dev), tmp);
-		return ERR_PTR(tmp);
-	}
-	jedec = id[0];
-	jedec = jedec << 8;
-	jedec |= id[1];
-	jedec = jedec << 8;
-	jedec |= id[2];
+	/* Set up command buffer. */
+	flash->command[0] = nor->erase_opcode;
+	m25p_addr2cmd(nor, offset, flash->command);
 
-	ext_jedec = id[3] << 8 | id[4];
+	spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
 
-	for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) {
-		info = (void *)m25p_ids[tmp].driver_data;
-		if (info->jedec_id == jedec) {
-			if (info->ext_id == 0 || info->ext_id == ext_jedec)
-				return &m25p_ids[tmp];
-		}
-	}
-	dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
-	return ERR_PTR(-ENODEV);
+	return 0;
 }
 
-
 /*
  * board specific setup should have ensured the SPI clock used here
  * matches what the READ command supports, at least until this driver
@@ -1095,231 +191,43 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
  */
 static int m25p_probe(struct spi_device *spi)
 {
-	const struct spi_device_id	*id = spi_get_device_id(spi);
-	struct flash_platform_data	*data;
-	struct m25p			*flash;
-	struct flash_info		*info;
-	unsigned			i;
 	struct mtd_part_parser_data	ppdata;
-	struct device_node *np = spi->dev.of_node;
+	struct flash_platform_data	*data;
+	struct m25p *flash;
+	struct spi_nor *nor;
+	enum read_mode mode = SPI_NOR_NORMAL;
 	int ret;
 
-	/* Platform data helps sort out which chip type we have, as
-	 * well as how this board partitions it.  If we don't have
-	 * a chip ID, try the JEDEC id commands; they'll work for most
-	 * newer chips, even if we don't recognize the particular chip.
-	 */
-	data = dev_get_platdata(&spi->dev);
-	if (data && data->type) {
-		const struct spi_device_id *plat_id;
-
-		for (i = 0; i < ARRAY_SIZE(m25p_ids) - 1; i++) {
-			plat_id = &m25p_ids[i];
-			if (strcmp(data->type, plat_id->name))
-				continue;
-			break;
-		}
-
-		if (i < ARRAY_SIZE(m25p_ids) - 1)
-			id = plat_id;
-		else
-			dev_warn(&spi->dev, "unrecognized id %s\n", data->type);
-	}
-
-	info = (void *)id->driver_data;
-
-	if (info->jedec_id) {
-		const struct spi_device_id *jid;
-
-		jid = jedec_probe(spi);
-		if (IS_ERR(jid)) {
-			return PTR_ERR(jid);
-		} else if (jid != id) {
-			/*
-			 * JEDEC knows better, so overwrite platform ID. We
-			 * can't trust partitions any longer, but we'll let
-			 * mtd apply them anyway, since some partitions may be
-			 * marked read-only, and we don't want to lose that
-			 * information, even if it's not 100% accurate.
-			 */
-			dev_warn(&spi->dev, "found %s, expected %s\n",
-				 jid->name, id->name);
-			id = jid;
-			info = (void *)jid->driver_data;
-		}
-	}
-
 	flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
 	if (!flash)
 		return -ENOMEM;
 
-	flash->command = devm_kzalloc(&spi->dev, MAX_CMD_SIZE, GFP_KERNEL);
-	if (!flash->command)
-		return -ENOMEM;
-
-	flash->spi = spi;
-	mutex_init(&flash->lock);
-	spi_set_drvdata(spi, flash);
-
-	/*
-	 * Atmel, SST and Intel/Numonyx serial flash tend to power
-	 * up with the software protection bits set
-	 */
+	nor = &flash->spi_nor;
 
-	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ATMEL ||
-	    JEDEC_MFR(info->jedec_id) == CFI_MFR_INTEL ||
-	    JEDEC_MFR(info->jedec_id) == CFI_MFR_SST) {
-		write_enable(flash);
-		write_sr(flash, 0);
-	}
-
-	if (data && data->name)
-		flash->mtd.name = data->name;
-	else
-		flash->mtd.name = dev_name(&spi->dev);
-
-	flash->mtd.type = MTD_NORFLASH;
-	flash->mtd.writesize = 1;
-	flash->mtd.flags = MTD_CAP_NORFLASH;
-	flash->mtd.size = info->sector_size * info->n_sectors;
-	flash->mtd._erase = m25p80_erase;
-	flash->mtd._read = m25p80_read;
-
-	/* flash protection support for STmicro chips */
-	if (JEDEC_MFR(info->jedec_id) == CFI_MFR_ST) {
-		flash->mtd._lock = m25p80_lock;
-		flash->mtd._unlock = m25p80_unlock;
-	}
+	/* install the hooks */
+	nor->read = m25p80_read;
+	nor->write = m25p80_write;
+	nor->erase = m25p80_erase;
+	nor->write_reg = m25p80_write_reg;
+	nor->read_reg = m25p80_read_reg;
 
-	/* sst flash chips use AAI word program */
-	if (info->flags & SST_WRITE)
-		flash->mtd._write = sst_write;
-	else
-		flash->mtd._write = m25p80_write;
+	nor->dev = &spi->dev;
+	nor->mtd = &flash->mtd;
+	nor->priv = flash;
 
-	/* prefer "small sector" erase if possible */
-	if (info->flags & SECT_4K) {
-		flash->erase_opcode = OPCODE_BE_4K;
-		flash->mtd.erasesize = 4096;
-	} else if (info->flags & SECT_4K_PMC) {
-		flash->erase_opcode = OPCODE_BE_4K_PMC;
-		flash->mtd.erasesize = 4096;
-	} else {
-		flash->erase_opcode = OPCODE_SE;
-		flash->mtd.erasesize = info->sector_size;
-	}
+	spi_set_drvdata(spi, flash);
+	flash->mtd.priv = nor;
+	flash->spi = spi;
 
-	if (info->flags & M25P_NO_ERASE)
-		flash->mtd.flags |= MTD_NO_ERASE;
+	if (spi->mode & SPI_RX_QUAD)
+		mode = SPI_NOR_QUAD;
+	ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
+	if (ret)
+		return ret;
 
+	data = dev_get_platdata(&spi->dev);
 	ppdata.of_node = spi->dev.of_node;
-	flash->mtd.dev.parent = &spi->dev;
-	flash->page_size = info->page_size;
-	flash->mtd.writebufsize = flash->page_size;
-
-	if (np) {
-		/* If we were instantiated by DT, use it */
-		if (of_property_read_bool(np, "m25p,fast-read"))
-			flash->flash_read = M25P80_FAST;
-		else
-			flash->flash_read = M25P80_NORMAL;
-	} else {
-		/* If we weren't instantiated by DT, default to fast-read */
-		flash->flash_read = M25P80_FAST;
-	}
-
-	/* Some devices cannot do fast-read, no matter what DT tells us */
-	if (info->flags & M25P_NO_FR)
-		flash->flash_read = M25P80_NORMAL;
-
-	/* Quad/Dual-read mode takes precedence over fast/normal */
-	if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) {
-		ret = set_quad_mode(flash, info->jedec_id);
-		if (ret) {
-			dev_err(&flash->spi->dev, "quad mode not supported\n");
-			return ret;
-		}
-		flash->flash_read = M25P80_QUAD;
-	} else if (spi->mode & SPI_RX_DUAL && info->flags & M25P80_DUAL_READ) {
-		flash->flash_read = M25P80_DUAL;
-	}
 
-	/* Default commands */
-	switch (flash->flash_read) {
-	case M25P80_QUAD:
-		flash->read_opcode = OPCODE_QUAD_READ;
-		break;
-	case M25P80_DUAL:
-		flash->read_opcode = OPCODE_DUAL_READ;
-		break;
-	case M25P80_FAST:
-		flash->read_opcode = OPCODE_FAST_READ;
-		break;
-	case M25P80_NORMAL:
-		flash->read_opcode = OPCODE_NORM_READ;
-		break;
-	default:
-		dev_err(&flash->spi->dev, "No Read opcode defined\n");
-		return -EINVAL;
-	}
-
-	flash->program_opcode = OPCODE_PP;
-
-	if (info->addr_width)
-		flash->addr_width = info->addr_width;
-	else if (flash->mtd.size > 0x1000000) {
-		/* enable 4-byte addressing if the device exceeds 16MiB */
-		flash->addr_width = 4;
-		if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
-			/* Dedicated 4-byte command set */
-			switch (flash->flash_read) {
-			case M25P80_QUAD:
-				flash->read_opcode = OPCODE_QUAD_READ_4B;
-				break;
-			case M25P80_DUAL:
-				flash->read_opcode = OPCODE_DUAL_READ_4B;
-				break;
-			case M25P80_FAST:
-				flash->read_opcode = OPCODE_FAST_READ_4B;
-				break;
-			case M25P80_NORMAL:
-				flash->read_opcode = OPCODE_NORM_READ_4B;
-				break;
-			}
-			flash->program_opcode = OPCODE_PP_4B;
-			/* No small sector erase for 4-byte command set */
-			flash->erase_opcode = OPCODE_SE_4B;
-			flash->mtd.erasesize = info->sector_size;
-		} else
-			set_4byte(flash, info->jedec_id, 1);
-	} else {
-		flash->addr_width = 3;
-	}
-
-	dev_info(&spi->dev, "%s (%lld Kbytes)\n", id->name,
-			(long long)flash->mtd.size >> 10);
-
-	pr_debug("mtd .name = %s, .size = 0x%llx (%lldMiB) "
-			".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
-		flash->mtd.name,
-		(long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
-		flash->mtd.erasesize, flash->mtd.erasesize / 1024,
-		flash->mtd.numeraseregions);
-
-	if (flash->mtd.numeraseregions)
-		for (i = 0; i < flash->mtd.numeraseregions; i++)
-			pr_debug("mtd.eraseregions[%d] = { .offset = 0x%llx, "
-				".erasesize = 0x%.8x (%uKiB), "
-				".numblocks = %d }\n",
-				i, (long long)flash->mtd.eraseregions[i].offset,
-				flash->mtd.eraseregions[i].erasesize,
-				flash->mtd.eraseregions[i].erasesize / 1024,
-				flash->mtd.eraseregions[i].numblocks);
-
-
-	/* partitions should match sector boundaries; and it may be good to
-	 * use readonly partitions for writeprotected sectors (BP2..BP0).
-	 */
 	return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
 			data ? data->parts : NULL,
 			data ? data->nr_parts : 0);
@@ -1340,7 +248,7 @@ static struct spi_driver m25p80_driver = {
 		.name	= "m25p80",
 		.owner	= THIS_MODULE,
 	},
-	.id_table	= m25p_ids,
+	.id_table	= spi_nor_ids,
 	.probe	= m25p_probe,
 	.remove	= m25p_remove,
 
-- 
1.7.2.rc3



^ permalink raw reply related

* [PATCH v5 4/8 fix] Documentation: add the document for the SPI NOR framework
From: Huang Shijie @ 2014-02-28  7:58 UTC (permalink / raw)
  To: dwmw2
  Cc: computersforpeace, angus.clark, lee.jones, pekon, sourav.poddar,
	broonie, linux-mtd, linux-spi, linux-arm-kernel, linux-doc,
	devicetree, shawn.guo, Huang Shijie
In-Reply-To: <1393238262-8622-5-git-send-email-b32955@freescale.com>

This patch adds the document for the SPI NOR framework.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
fix a typo
---
 Documentation/mtd/spi-nor.txt |   59 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 59 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/mtd/spi-nor.txt

diff --git a/Documentation/mtd/spi-nor.txt b/Documentation/mtd/spi-nor.txt
new file mode 100644
index 0000000..294d5b0
--- /dev/null
+++ b/Documentation/mtd/spi-nor.txt
@@ -0,0 +1,59 @@
+                          SPI NOR framework
+               ============================================
+
+Part I - why we need this framework?
+-------------------------------------
+
+The SPI bus controller only deals with the byte stream.
+Some controller does not works like a SPI bus controller, it works
+like a SPI NOR controller instead, such as the Freescale's QuadSPI controller.
+
+The Freescale's QuadSPI controller should know the NOR commands to
+find the right LUT sequence. Unfortunately, the old code can not meet
+this requirement.
+
+Part II - How does the framework work?
+-------------------------------------
+
+This framework just adds a new layer between the MTD and the SPI bus driver.
+With this new layer, the SPI NOR controller driver does not depend on the
+m25p80 code anymore.
+
+   Before this framework, the layer is like:
+
+                   MTD
+         ------------------------
+                  m25p80
+         ------------------------
+	       SPI bus driver
+         ------------------------
+	        SPI NOR chip
+
+   After this framework, the layer is like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                  m25p80
+         ------------------------
+	       SPI bus driver
+         ------------------------
+	       SPI NOR chip
+
+  With the SPI NOR controller driver(Freescale QuadSPI), it looks like:
+                   MTD
+         ------------------------
+              SPI NOR framework
+         ------------------------
+                fsl-quadSPI
+         ------------------------
+	       SPI NOR chip
+
+Part III - How can the drivers use the framework
+-------------------------------------
+
+The main API is the spi_nor_scan(). Before you call the hook, you should
+initialize the necessary fields for spi_nor{}.
+Please see the drivers/mtd/spi-nor/spi-nor.c for detail.
+Please also reference to the fsl-quadspi.c when you want to write a new driver
+for a SPI NOR controller.
-- 
1.7.2.rc3



^ permalink raw reply related

* Re: devicetree repository separation/migration
From: Sascha Hauer @ 2014-02-28  8:00 UTC (permalink / raw)
  To: Olof Johansson
  Cc: Frank Rowand, Jason Cooper, Grant Likely, Rob Herring,
	Ian Campbell, Pawel Moll, Mark Rutland, Kumar Gala, Rob Landley,
	devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-spec-u79uwXL29TY76Z2rM5mHXA,
	devicetree-compiler-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <CAOesGMjY2aDLPYLncxHs9gqmWCFy+e4sZK_ET-17qzEU-JwvdQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

On Fri, Feb 21, 2014 at 10:47:09AM -0800, Olof Johansson wrote:
> On Fri, Feb 21, 2014 at 6:11 AM, Sascha Hauer <s.hauer-bIcnvbaLZ9MEGnE8C9+IrQ@public.gmane.org> wrote:
> > On Thu, Feb 20, 2014 at 05:07:12PM -0800, Frank Rowand wrote:
> 
> >> Why are the changes not submitted upstream?  (Or if they were submitted, why
> >> were they not accepted?)
> >
> > The descriptions where to find the environment are obviously barebox
> > specific and not acceptable upstream.
> 
> Why not? Wouldn't it be useful if you could find where the environment
> is from the running Linux image so that you can change variables
> without rebooting into Barebox first?

Indeed that would be very useful. Generally that would require some
generic binding for referring to partitions on mtd devices, partitions
on block devices and EEPROMs. If you think such a binding would have a
chance upstream I could try and come up with a binding.

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
--
To unsubscribe from this list: send the line "unsubscribe devicetree-spec" 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 3/6] spi: sh-msiof: Add support for R-Car H2 and M2
From: Geert Uytterhoeven @ 2014-02-28  8:01 UTC (permalink / raw)
  To: Laurent Pinchart
  Cc: Bastian Hecht, Mark Brown, Takashi Yoshii, Magnus Damm, linux-spi,
	Linux-sh list, linux-kernel@vger.kernel.org, Geert Uytterhoeven,
	devicetree@vger.kernel.org
In-Reply-To: <10401513.fZZM0mLxSj@avalon>

Hi Laurent,

On Fri, Feb 28, 2014 at 12:02 AM, Laurent Pinchart
<laurent.pinchart@ideasonboard.com> wrote:
>> And if we remove "renesas,sh-msiof", we should probably remove
>> "renesas,sh-mobile-msiof", too, as there are no current users, and it also
>> assumes the same MSIOF implementation?
>
> I'm not too familiar with the MSIOF hardware, can "renesas,sh-mobile-msiof" be
> used as a fallback for the currently support ARM SoCs ?

r8a73a4/APE6: No
r8a7740/A1: Maybe (not 100% clear to me from the datasheet)
r8a7790/R-Car H2: No
r8a7791/R-Car M2: No
sh7372/AP4: No information
sh73a0/AG5: No information

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* Re: [PATCH v4] can: xilinx CAN controller support.
From: Marc Kleine-Budde @ 2014-02-28  8:32 UTC (permalink / raw)
  To: Appana Durga Kedareswara Rao, wg@grandegger.com, Michal Simek,
	grant.likely@linaro.org, robh+dt@kernel.org,
	linux-can@vger.kernel.org
  Cc: netdev@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, devicetree@vger.kernel.org
In-Reply-To: <2e3bfd38-37d5-4102-af79-821196c6c732@CH1EHSMHS006.ehs.local>

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

On 02/28/2014 06:50 AM, Appana Durga Kedareswara Rao wrote:
> Hi Marc,
> 
> 
>> -----Original Message-----
>> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
>> Sent: Wednesday, February 26, 2014 9:13 PM
>> To: Appana Durga Kedareswara Rao; wg@grandegger.com; Michal Simek;
>> grant.likely@linaro.org; robh+dt@kernel.org; linux-can@vger.kernel.org
>> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org; linux-
>> kernel@vger.kernel.org; devicetree@vger.kernel.org
>> Subject: Re: [PATCH v4] can: xilinx CAN controller support.
>>
>> On 02/26/2014 03:46 PM, Appana Durga Kedareswara Rao wrote:
>>> Hi Marc,
>>>
>>>
>>>> -----Original Message-----
>>>> From: Marc Kleine-Budde [mailto:mkl@pengutronix.de]
>>>> Sent: Wednesday, February 26, 2014 6:52 PM
>>>> To: Appana Durga Kedareswara Rao; wg@grandegger.com; Michal Simek;
>>>> grant.likely@linaro.org; robh+dt@kernel.org;
>>>> linux-can@vger.kernel.org
>>>> Cc: netdev@vger.kernel.org; linux-arm-kernel@lists.infradead.org;
>>>> linux- kernel@vger.kernel.org; devicetree@vger.kernel.org
>>>> Subject: Re: [PATCH v4] can: xilinx CAN controller support.
>>>>
>>>> On 02/26/2014 02:07 PM, Appana Durga Kedareswara Rao wrote:
>>>>>> This loop looks broken. Can you explain how it works.
>>>>>>
>>>>>> What it shoud do is:
>>>>>> We have put (priv->tx_head - priv->tx_tail) CAN frames into the FIFO.
>>>>>> This means at maximum there could be this amount of CAN frames
>>>>>> which have been successfully transmitted. For every cycle in this
>>>>>> while loop you
>>>>>> should:
>>>>>> a) check if a CAN frame has successfully been transmitted
>>>>>>    (as this CAN core uses a FIFO it should be "oldest")
>>>>>>    A read_reg() of some kind is missing in your loop.
>>>>>> b) if needed, remove this event from the FIFO or
>>>>>>    mark the interrupt as done. Whatever you hardware needs.
>>>>>> c) update your statistics
>>>>>> d) Use can_get_echo_skb to push this frame into the networking
>>>>>> stack
>>>>>> e) As a CAN frame has been transmitted successfully, wake the
>> tx_queue.
>>>>>>
>>>>>>> +   while (priv->tx_head - priv->tx_tail > 0) {
>>>>>>> +           if (isr & XCAN_IXR_TXFLL_MASK) {
>>>>>>> +                   priv->write_reg(priv, XCAN_ICR_OFFSET,
>>>>>>> +                                   XCAN_IXR_TXFLL_MASK);
>>>>>>> +                   netif_stop_queue(ndev);
>>>>>>
>>>>>> Why do you stop the queue here? A CAN frame has successfully been
>>>>>> transmitted, there should be room in the FIFO.
>>>>>>
>>>>>>> +                   break;
>>>>>>> +           }
>>>>>>> +           can_get_echo_skb(ndev, priv->tx_tail %
>>>>>>> +                                   priv->xcan_echo_skb_max_tx);
>>>>>>> +           priv->tx_tail++;
>>>>>>> +   }
>>>>>>> +
>>>>>
>>>>> The below are the bit fields available for the Transmit FIFO.
>>>>> 1) In the ISR(interrupt status register)  Tx Ok interrupt and Tx
>>>>> fifo full
>>>> interrupt.
>>>>> 2) in the SR(Status Register) Tx fifo full condition.
>>>>>
>>>>>
>>>>> I am modifying the entire tx interrupt logic to like below.
>>>>>
>>>>> static void xcan_tx_interrupt(struct net_device *ndev, u32 isr) {
>>>>>         struct xcan_priv *priv = netdev_priv(ndev);
>>>>>         struct net_device_stats *stats = &ndev->stats;
>>>>>
>>>>>             while (priv->tx_head - priv->tx_tail > 0) {
>>>>>                 if (isr & XCAN_IXR_TXFLL_MASK) {
>>>>>                         priv->write_reg(priv, XCAN_ICR_OFFSET,
>>>>>                                         XCAN_IXR_TXFLL_MASK);
>>>>>                           break;
>>>>>                 }
>>>>>                 can_get_echo_skb(ndev, priv->tx_tail %
>>>>>                                         priv->xcan_echo_skb_max_tx);
>>>>>                 priv->tx_tail++;
>>>>>          stats->tx_packets++;
>>>>>         netif_wake_queue(ndev);
>>>>>               can_led_event(ndev, CAN_LED_EVENT_TX);
>>>>>
>>>>>         }
>>>>
>>>> You just need to wake the queue once.
>>>
>>> Ok
>>>>
>>>>> }
>>>>>
>>>>>
>>>>> Are you Ok with the above logic?
>>>>
>>>> No, how can you tell how many frames have been transmitted?
>>>
>>> There is no register to read how many can frames are transmitted.
>>> The only way to know Is by reading this parameter
>>> (stats->tx_packets++;) through ip command
>>
>> stats->tx_packets is calculated in the above loop and the loop is
>> broken. Let me illustrate the problem:
>>
>> - xmit is called 10 times in a row
>> - this means you have 10 CAN frames in the TX FIFO
>> - a single CAN frame gets transmitted
>> - you get an interrupt
>> - you enter the above routine and loop 10 times and echo the CAN frame
>>   back into the stack
>>
>> Now every application sees 10 transmitted packages, but there is only one
>> transmitted. Every time you loop you have to check if the CAN frame has
>> already been transmitted or not. Is that possible with the hardware?
> 
>         The only way to know whether the TX packet is transmitted successfully or not is by using the Tx Ok interrupt from the ISR.
> This interrupt will come for every Tx Packet.
> So I am thinking of there is no loop required in the TX interrupt routine. As it is called for each and every packet.

What happens if the interrupt handler is delayed? For example in a RT
enabled system the interrupt handler runs as a thread. There might be
other threads with higher priority. The hardware will probably send all
CAN frames in the FIFO, so you want to reduce the overhead and loop in
the tx complete handler.

> 
> static void xcan_tx_interrupt(struct net_device *ndev, u32 isr)
> {
>         struct xcan_priv *priv = netdev_priv(ndev);
>         struct net_device_stats *stats = &ndev->stats;
> 
> 
>         can_get_echo_skb(ndev, priv->tx_tail %
>                                 priv->xcan_echo_skb_max_tx);
>         priv->tx_tail++;
>         stats->tx_packets++;
>         can_led_event(ndev, CAN_LED_EVENT_TX);
>         netif_wake_queue(ndev);
> }
> 
> If you want me to put some locks for this Will put some spin_locks in the _xmit and in the tx interrupt routine (for the tx_head and tx_tail).

There is no need for locking regarding tx_{head,tail}. As the tx
complete handler only increments tx_tail and the xmit routine increments
tx_head.

Marc

-- 
Pengutronix e.K.                  | Marc Kleine-Budde           |
Industrial Linux Solutions        | Phone: +49-231-2826-924     |
Vertretung West/Dortmund          | Fax:   +49-5121-206917-5555 |
Amtsgericht Hildesheim, HRA 2686  | http://www.pengutronix.de   |


[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 242 bytes --]

^ permalink raw reply

* Re: [PATCH v2 4/4] pci: Add support for creating a generic host_bridge from device tree
From: Arnd Bergmann @ 2014-02-28  8:46 UTC (permalink / raw)
  To: linux-arm-kernel
  Cc: Benjamin Herrenschmidt, devicetree@vger.kernel.org, linaro-kernel,
	linux-pci, Liviu Dudau, LKML, Will Deacon, Catalin Marinas,
	Bjorn Helgaas
In-Reply-To: <1393543924.14012.56.camel@pasglop>

On Friday 28 February 2014 10:32:04 Benjamin Herrenschmidt wrote:
> On Thu, 2014-02-27 at 14:38 +0100, Arnd Bergmann wrote:
> > On Thursday 27 February 2014 13:06:42 Liviu Dudau wrote:
> > > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > 
> > Please add Benjamin Herrenschmidt to Cc here, I think it would be helpful
> > to get his input so we can make this work on powerpc as well.
> 
> Tricky... We would need hooks which would turn the whole thing into a
> pile of spaghetti. I think we should stick to using the range helpers
> (Andrew latest patch), which makes the powerpc code a lot smaller,
> and leave it at that.

We can certainly do both: small helpers that let you shrink the powerpc
code, and a generic implementation that can be shared by some of the
other architectures that you don't use. The PCI core already uses
a number of 'weak' functions here, and we can expand on that.

 > > +		res = kzalloc(sizeof(struct resource), GFP_KERNEL);
> > > +		if (!res) {
> > > +			err = -ENOMEM;
> > > +			goto bridge_ranges_nomem;
> > > +		}
> > > +
> > > +		of_pci_range_to_resource(&range, dev, res);
> > > +
> > > +		if (resource_type(res) == IORESOURCE_IO)
> > > +			*io_base = range.cpu_addr;
> 
> You don't care about the size of the IO space ?

We probably should. The ARM code currently assumes that each I/O
space is 64KB, but for a generic implementation we probably want
to handle both smaller and larger windows. I suggested not supporting
more than 1MB though, which is the maximum that I can see a reason
for, i.e. the pci-mvebu fake host bridge that has to combine
multiple per-port HW I/O spaces into one logical space.

> > > +		pci_add_resource_offset(resources, res,
> > > +				res->start - range.pci_addr);
> > > +	}
> > 
> > This is not the correct resource for I/O space at all. Please talk
> > to Will, I've been over this with him in detail and he probably
> > understands it now. I assume you are both working in the same
> > building.
> 
> Yes, the IO offsets work differently on powerpc as well

As I noticed later, the first patch in the series actually changes
the range_to_resource parser to return the logical start here, which
would make the offset correct even on powerpc, but unfortunately
I think that cannot work.

> > > +struct pci_host_bridge *
> > > +of_create_pci_host_bridge(struct device *parent, struct pci_ops *ops, void *host_data)
> > > +{
> > > +	int err, domain, busno;
> > > +	struct resource bus_range;
> > > +	struct pci_bus *root_bus;
> > > +	struct pci_host_bridge *bridge;
> > > +	resource_size_t io_base;
> > > +	LIST_HEAD(res);
> > > +
> > > +	domain = of_alias_get_id(parent->of_node, "pci-domain");
> > > +	if (domain == -ENODEV)
> > > +		domain = domain_nr++;
> > >
> We probably want some uniqueness testing here.

I thought this at first too, but as Liviu mentioned, this does
get caught later when trying to create the root bus with
a conflicting number.

What the above code cannot do is to put multiple host bridges
into the same domain, using distinct bus ranges. This is an
intentional simplification over what some architectures currently
do, and we could not see a reason why you would still need
to put multiple host bridges into one domain in 2014.

x86 with ACPI does it, but they won't call of_create_pci_host_bridge.

	Arnd

^ permalink raw reply


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