linux-mtd.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
@ 2014-11-06 15:51 Ionela Voinescu
  2014-11-06 16:05 ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Ionela Voinescu @ 2014-11-06 15:51 UTC (permalink / raw)
  To: computersforpeace, gregkh, linux-mtd
  Cc: Ionela Voinescu, abrestic, dehrenberg, ezequiel.garcia,
	sourav.poddar, james.hartley

Hi, 

These patches add support for GigaDevice 4Gb SPI NAND flash.
This is an initial version, adding it to staging, as there is no existing 
framework for SPI NAND as there is for SPI NOR in MTD.

Therefore, I want to start an early discussion about this in order to find 
the best way to integrate it. I am at the beginning regarding both upstreaming 
and understanding all of the MTD layer, so your comments and ideas are 
welcomed.

I've structured this driver similar to the existing Micron SPI NAND 
(mt29f_spinand), in order to make it easier to understand the common code.
I know there is an atempt to add support for a generic SPI NAND based 
framework from Sourav Poddar but that never got merged, and it would be 
a valid option to consider.

http://lists.infradead.org/pipermail/linux-mtd/2013-July/047373.html

This initial version does not implement all the functionality and I will 
add to it once we decide on a structure. This is based on linux-next. 

Thank you and I welcome all comments,
Ionela. 

Ionela Voinescu (2):
  staging: mtd: GigaDevice 4Gb SPI NAND driver
  Documentation: staging: mtd: Binding document for GigaDevice SPI NAND

 .../bindings/staging/mtd/gd5f_spinand.txt          |   13 +
 drivers/staging/Kconfig                            |    2 +
 drivers/staging/Makefile                           |    1 +
 drivers/staging/gd5f_spinand/Kconfig               |   15 +
 drivers/staging/gd5f_spinand/Makefile              |    1 +
 drivers/staging/gd5f_spinand/gd5f_spinand.c        | 1056 ++++++++++++++++++++
 drivers/staging/gd5f_spinand/gd5f_spinand.h        |  182 ++++
 7 files changed, 1270 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/staging/mtd/gd5f_spinand.txt
 create mode 100644 drivers/staging/gd5f_spinand/Kconfig
 create mode 100644 drivers/staging/gd5f_spinand/Makefile
 create mode 100644 drivers/staging/gd5f_spinand/gd5f_spinand.c
 create mode 100644 drivers/staging/gd5f_spinand/gd5f_spinand.h

-- 
1.7.9.5

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 15:51 Ionela Voinescu
@ 2014-11-06 16:05 ` Greg KH
  2014-11-06 17:32   ` Ionela Voinescu
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2014-11-06 16:05 UTC (permalink / raw)
  To: Ionela Voinescu
  Cc: abrestic, dehrenberg, linux-mtd, ezequiel.garcia, sourav.poddar,
	computersforpeace, james.hartley

On Thu, Nov 06, 2014 at 03:51:17PM +0000, Ionela Voinescu wrote:
> Hi, 
> 
> These patches add support for GigaDevice 4Gb SPI NAND flash.
> This is an initial version, adding it to staging, as there is no existing 
> framework for SPI NAND as there is for SPI NOR in MTD.
> 
> Therefore, I want to start an early discussion about this in order to find 
> the best way to integrate it. I am at the beginning regarding both upstreaming 
> and understanding all of the MTD layer, so your comments and ideas are 
> welcomed.
> 
> I've structured this driver similar to the existing Micron SPI NAND 
> (mt29f_spinand), in order to make it easier to understand the common code.
> I know there is an atempt to add support for a generic SPI NAND based 
> framework from Sourav Poddar but that never got merged, and it would be 
> a valid option to consider.
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047373.html
> 
> This initial version does not implement all the functionality and I will 
> add to it once we decide on a structure. This is based on linux-next. 
> 
> Thank you and I welcome all comments,

If you want to add code to the staging tree, you need a TODO file that
lists what is needed to be done to the driver in order to get it out of
the staging tree.  Otherwise I don't know why the code is in staging at
all, and not in the "real" part of the kernel.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 16:05 ` Greg KH
@ 2014-11-06 17:32   ` Ionela Voinescu
  2014-11-06 17:44     ` Greg KH
  0 siblings, 1 reply; 16+ messages in thread
From: Ionela Voinescu @ 2014-11-06 17:32 UTC (permalink / raw)
  To: Greg KH
  Cc: abrestic, dehrenberg, linux-mtd, ezequiel.garcia, sourav.poddar,
	computersforpeace, james.hartley

On 11/06/14 16:05, Greg KH wrote:
> On Thu, Nov 06, 2014 at 03:51:17PM +0000, Ionela Voinescu wrote:
>> Hi,
>>
>> These patches add support for GigaDevice 4Gb SPI NAND flash.
>> This is an initial version, adding it to staging, as there is no existing
>> framework for SPI NAND as there is for SPI NOR in MTD.
>>
>> Therefore, I want to start an early discussion about this in order to find
>> the best way to integrate it. I am at the beginning regarding both upstreaming
>> and understanding all of the MTD layer, so your comments and ideas are
>> welcomed.
>>
>> I've structured this driver similar to the existing Micron SPI NAND
>> (mt29f_spinand), in order to make it easier to understand the common code.
>> I know there is an atempt to add support for a generic SPI NAND based
>> framework from Sourav Poddar but that never got merged, and it would be
>> a valid option to consider.
>>
>> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047373.html
>>
>> This initial version does not implement all the functionality and I will
>> add to it once we decide on a structure. This is based on linux-next.
>>
>> Thank you and I welcome all comments,
> If you want to add code to the staging tree, you need a TODO file that
> lists what is needed to be done to the driver in order to get it out of
> the staging tree.  Otherwise I don't know why the code is in staging at
> all, and not in the "real" part of the kernel.
>
> thanks,
>
> greg k-h
Hi Greg,

For now I am submitting this for staging, but I am interested in having
a discussion about the best way to integrate it and hopefully merge
this in drivers/mtd/spinand/.
Therefore, I will add the TODO file to explain why it is put in staging
at this point.

Thank you,
Ionela.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 17:32   ` Ionela Voinescu
@ 2014-11-06 17:44     ` Greg KH
  2014-11-06 18:03       ` Ionela Voinescu
  0 siblings, 1 reply; 16+ messages in thread
From: Greg KH @ 2014-11-06 17:44 UTC (permalink / raw)
  To: Ionela Voinescu
  Cc: abrestic, dehrenberg, linux-mtd, ezequiel.garcia, sourav.poddar,
	computersforpeace, james.hartley

On Thu, Nov 06, 2014 at 05:32:43PM +0000, Ionela Voinescu wrote:
> On 11/06/14 16:05, Greg KH wrote:
> >On Thu, Nov 06, 2014 at 03:51:17PM +0000, Ionela Voinescu wrote:
> >>Hi,
> >>
> >>These patches add support for GigaDevice 4Gb SPI NAND flash.
> >>This is an initial version, adding it to staging, as there is no existing
> >>framework for SPI NAND as there is for SPI NOR in MTD.
> >>
> >>Therefore, I want to start an early discussion about this in order to find
> >>the best way to integrate it. I am at the beginning regarding both upstreaming
> >>and understanding all of the MTD layer, so your comments and ideas are
> >>welcomed.
> >>
> >>I've structured this driver similar to the existing Micron SPI NAND
> >>(mt29f_spinand), in order to make it easier to understand the common code.
> >>I know there is an atempt to add support for a generic SPI NAND based
> >>framework from Sourav Poddar but that never got merged, and it would be
> >>a valid option to consider.
> >>
> >>http://lists.infradead.org/pipermail/linux-mtd/2013-July/047373.html
> >>
> >>This initial version does not implement all the functionality and I will
> >>add to it once we decide on a structure. This is based on linux-next.
> >>
> >>Thank you and I welcome all comments,
> >If you want to add code to the staging tree, you need a TODO file that
> >lists what is needed to be done to the driver in order to get it out of
> >the staging tree.  Otherwise I don't know why the code is in staging at
> >all, and not in the "real" part of the kernel.
> >
> >thanks,
> >
> >greg k-h
> Hi Greg,
> 
> For now I am submitting this for staging, but I am interested in having
> a discussion about the best way to integrate it and hopefully merge
> this in drivers/mtd/spinand/.

Then why not just go directly for drivers/mtd/?  Why even stop at
drivers/staging/ at all?  I need an ACK from the MTD maintainer to get
this into staging as well.

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 17:44     ` Greg KH
@ 2014-11-06 18:03       ` Ionela Voinescu
  2014-11-06 18:17         ` Ezequiel Garcia
  0 siblings, 1 reply; 16+ messages in thread
From: Ionela Voinescu @ 2014-11-06 18:03 UTC (permalink / raw)
  To: Greg KH
  Cc: abrestic, dehrenberg, linux-mtd, ezequiel.garcia,
	computersforpeace, james.hartley

On 11/06/14 17:44, Greg KH wrote:
> On Thu, Nov 06, 2014 at 05:32:43PM +0000, Ionela Voinescu wrote:
>> On 11/06/14 16:05, Greg KH wrote:
>>> On Thu, Nov 06, 2014 at 03:51:17PM +0000, Ionela Voinescu wrote:
>>>> Hi,
>>>>
>>>> These patches add support for GigaDevice 4Gb SPI NAND flash.
>>>> This is an initial version, adding it to staging, as there is no existing
>>>> framework for SPI NAND as there is for SPI NOR in MTD.
>>>>
>>>> Therefore, I want to start an early discussion about this in order to find
>>>> the best way to integrate it. I am at the beginning regarding both upstreaming
>>>> and understanding all of the MTD layer, so your comments and ideas are
>>>> welcomed.
>>>>
>>>> I've structured this driver similar to the existing Micron SPI NAND
>>>> (mt29f_spinand), in order to make it easier to understand the common code.
>>>> I know there is an atempt to add support for a generic SPI NAND based
>>>> framework from Sourav Poddar but that never got merged, and it would be
>>>> a valid option to consider.
>>>>
>>>> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047373.html
>>>>
>>>> This initial version does not implement all the functionality and I will
>>>> add to it once we decide on a structure. This is based on linux-next.
>>>>
>>>> Thank you and I welcome all comments,
>>> If you want to add code to the staging tree, you need a TODO file that
>>> lists what is needed to be done to the driver in order to get it out of
>>> the staging tree.  Otherwise I don't know why the code is in staging at
>>> all, and not in the "real" part of the kernel.
>>>
>>> thanks,
>>>
>>> greg k-h
>> Hi Greg,
>>
>> For now I am submitting this for staging, but I am interested in having
>> a discussion about the best way to integrate it and hopefully merge
>> this in drivers/mtd/spinand/.
> Then why not just go directly for drivers/mtd/?  Why even stop at
> drivers/staging/ at all?  I need an ACK from the MTD maintainer to get
> this into staging as well.
>
> thanks,
>
> greg k-h
Because the right way to do it in drivers/mtd would be to add a generic
SPI NAND framework and above that have the device specific part.
That would accommodate both my driver and the existing Micron
mt29f_spinand, also in staging, and prepare the ground for other drivers.
But that requires a discussion with the community regarding the structure
of that generic framework and this is what I want to start here.

Therefore, I've added in staging this initial version, because as I see thing,
we can either find the good way to do it, detailed above, or have it
as it is, in staging.

Thank you,
Ionela.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 18:03       ` Ionela Voinescu
@ 2014-11-06 18:17         ` Ezequiel Garcia
  2014-11-06 19:20           ` Brian Norris
  0 siblings, 1 reply; 16+ messages in thread
From: Ezequiel Garcia @ 2014-11-06 18:17 UTC (permalink / raw)
  To: computersforpeace, Ionela Voinescu, Greg KH
  Cc: abrestic, linux-mtd, james.hartley, dehrenberg


Brian, Ionela:

On 11/06/2014 03:03 PM, Ionela Voinescu wrote:
> On 11/06/14 17:44, Greg KH wrote:
>> On Thu, Nov 06, 2014 at 05:32:43PM +0000, Ionela Voinescu wrote:
>>> On 11/06/14 16:05, Greg KH wrote:
>>>> On Thu, Nov 06, 2014 at 03:51:17PM +0000, Ionela Voinescu wrote:
[snip]
>>>
>>> For now I am submitting this for staging, but I am interested in having
>>> a discussion about the best way to integrate it and hopefully merge
>>> this in drivers/mtd/spinand/.

[..]
>> Then why not just go directly for drivers/mtd/?  Why even stop at
>> drivers/staging/ at all?  I need an ACK from the MTD maintainer to get
>> this into staging as well.
>>
> of that generic framework and this is what I want to start here.
> Therefore, I've added in staging this initial version, because as I see
> thing, we can either find the good way to do it, detailed above, or have it
> as it is, in staging.
> 

How about picking Sourav's v2 as a starting point:

http://lists.infradead.org/pipermail/linux-mtd/2013-July/047434.html

And then try to use that to support Micron's MT29F and Gigadevice's GD5F ?

Brian: Any ideas or suggestion on how to proceed?
-- 
Ezequiel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 18:17         ` Ezequiel Garcia
@ 2014-11-06 19:20           ` Brian Norris
  2014-11-07 13:00             ` Ionela Voinescu
  2014-11-10  9:00             ` arnaud.mouiche
  0 siblings, 2 replies; 16+ messages in thread
From: Brian Norris @ 2014-11-06 19:20 UTC (permalink / raw)
  To: Ezequiel Garcia
  Cc: Marek Vasut, Ionela Voinescu, Kamlakant Patel, abrestic, Greg KH,
	Rafał Miłecki, dehrenberg, linux-mtd, james.hartley

On Thu, Nov 06, 2014 at 03:17:10PM -0300, Ezequiel Garcia wrote:
> How about picking Sourav's v2 as a starting point:
> 
> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047434.html

Completely irrelevant, but I found this amusing in that patch, a few
lines into spinand.h:

+/bin/bash: 4: command not found

:)

> And then try to use that to support Micron's MT29F and Gigadevice's GD5F ?
> 
> Brian: Any ideas or suggestion on how to proceed?

I'm not opposed to trying to build a proper SPI-NAND framework. But the
linked v2 patch doesn't provide much to start from. It barely handles
anything that is specific to SPI-NAND (pushing the details out to a
flash-specific driver), and it doesn't address what I think the biggest
question is: how similar will the various SPI-NAND implementations be?
I've talked with a few flash vendors and seen that there were some
growing pains with developing a first generation de-facto standard, so
there is bound to be a bit of incompatibility if we try to support the
earliest examples, but it seemed like there was some effort to keep
things consistent across different manufacturers. I don't know the
progress of any standardization effort there.

Anyway, I think we really should look at whether any of the
identification and command sequencing details can be abstracted into a
drivers/mtd/spinand/spinand.c, with client drivers mostly handling the
transport protocol differences (e.g., interfacing with the SPI layer,
similar to what m25p80.c does for SPI NOR).

I don't have any time to create such a framwork on my own, but I may be
able to spare some limited resources for reviewing others' work. I'd
really like to see some efforts from a few interested reviewers, as I
haven't figured out how to squeeze more hours into my day yet.

BTW, has there been any progress on whatever TODO items landed
mt29f_spinand in staging in the first place?

Brian

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 19:20           ` Brian Norris
@ 2014-11-07 13:00             ` Ionela Voinescu
  2014-11-10  9:00             ` arnaud.mouiche
  1 sibling, 0 replies; 16+ messages in thread
From: Ionela Voinescu @ 2014-11-07 13:00 UTC (permalink / raw)
  To: Brian Norris
  Cc: Marek Vasut, Kamlakant Patel, abrestic, Greg KH,
	Rafał Miłecki, dehrenberg, linux-mtd, Ezequiel Garcia,
	james.hartley

Hi Brian,

Thank you for your feedback.

On 11/06/14 19:20, Brian Norris wrote:
> On Thu, Nov 06, 2014 at 03:17:10PM -0300, Ezequiel Garcia wrote:
>> How about picking Sourav's v2 as a starting point:
>>
>> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047434.html
> Completely irrelevant, but I found this amusing in that patch, a few
> lines into spinand.h:
>
> +/bin/bash: 4: command not found
>
> :)
>
>> And then try to use that to support Micron's MT29F and Gigadevice's GD5F ?
>>
>> Brian: Any ideas or suggestion on how to proceed?
> I'm not opposed to trying to build a proper SPI-NAND framework. But the
> linked v2 patch doesn't provide much to start from. It barely handles
> anything that is specific to SPI-NAND (pushing the details out to a
> flash-specific driver), and it doesn't address what I think the biggest
> question is: how similar will the various SPI-NAND implementations be?
> I've talked with a few flash vendors and seen that there were some
> growing pains with developing a first generation de-facto standard, so
> there is bound to be a bit of incompatibility if we try to support the
> earliest examples, but it seemed like there was some effort to keep
> things consistent across different manufacturers. I don't know the
> progress of any standardization effort there.
>
> Anyway, I think we really should look at whether any of the
> identification and command sequencing details can be abstracted into a
> drivers/mtd/spinand/spinand.c, with client drivers mostly handling the
> transport protocol differences (e.g., interfacing with the SPI layer,
> similar to what m25p80.c does for SPI NOR).

I know that the linked v2 does not provide much but it provides a starting
point. If you agree I'm going to start from that and try to add as much
of the command sequencing that is common between the micron chip
and the gigadevice chip that I have access to, through the exiting drivers and
the datasheets, following the example set by m25p80.c.

As far as I've seen from the datasheets I have available (SPI NAND
GigaDevice 1Gb/2Gb/4Gb, Micron 1Gb/2Gb/4Gb), the command sequencing
is the same for read/write/erase operations (read: enable ECC, read to cache,
wait, read from cache, check for errors, disable ECC; write: enable ECC,
write enable, program load, program execute, wait, verify, disable ECC;
erase: write enable, erase block, verify).

Regarding the stream of bytes for each command, the problematic
commands are the read from cache ones (read, fast read, read x2,
read x4, read dual read quad) that have different command format
(additional dummy bytes, a plane select bit to be set).
Other differences are in the structure of the protection and status registers
(some of them use more ECC and protection bits according to the size
of the chip). Also, each has a different ECC layout.
>
> I don't have any time to create such a framwork on my own, but I may be
> able to spare some limited resources for reviewing others' work. I'd
> really like to see some efforts from a few interested reviewers, as I
> haven't figured out how to squeeze more hours into my day yet.

As I said, I have some time to continue Sourav's work and I would
greatly appreciate the review effort.

>
> BTW, has there been any progress on whatever TODO items landed
> mt29f_spinand in staging in the first place?
>
> Brian
Thank you very much,
Ionela.

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-06 19:20           ` Brian Norris
  2014-11-07 13:00             ` Ionela Voinescu
@ 2014-11-10  9:00             ` arnaud.mouiche
  1 sibling, 0 replies; 16+ messages in thread
From: arnaud.mouiche @ 2014-11-10  9:00 UTC (permalink / raw)
  To: Brian Norris, Ezequiel Garcia, Marek Vasut, dehrenberg, linux-mtd,
	james.hartley
  Cc: abrestic, Greg KH, Rafał Miłecki, Ionela Voinescu,
	Kamlakant Patel

Hi All,

Le 06/11/2014 20:20, Brian Norris a écrit :
> On Thu, Nov 06, 2014 at 03:17:10PM -0300, Ezequiel Garcia wrote:
>> How about picking Sourav's v2 as a starting point:
>>
>> http://lists.infradead.org/pipermail/linux-mtd/2013-July/047434.html
> Completely irrelevant, but I found this amusing in that patch, a few
> lines into spinand.h:
>
> +/bin/bash: 4: command not found
>
> :)
>
>> And then try to use that to support Micron's MT29F and Gigadevice's GD5F ?
>>
>> Brian: Any ideas or suggestion on how to proceed?
> I'm not opposed to trying to build a proper SPI-NAND framework. But the
> linked v2 patch doesn't provide much to start from. It barely handles
> anything that is specific to SPI-NAND (pushing the details out to a
> flash-specific driver), and it doesn't address what I think the biggest
> question is: how similar will the various SPI-NAND implementations be?
> I've talked with a few flash vendors and seen that there were some
> growing pains with developing a first generation de-facto standard, so
> there is bound to be a bit of incompatibility if we try to support the
> earliest examples, but it seemed like there was some effort to keep
> things consistent across different manufacturers. I don't know the
> progress of any standardization effort there.
I was playing with spi nand devices (MT29F1G01AAADD and GD5F1GQ4x) 
starting from the linked v2 patch, and I have a some hardware with such 
devices.
As far as I could say, it was not a good idea to start from that patch. 
I had to rewrite a lot of things to make the devices working 
correctly... and the result is not very beautiful, despite spi nand is 
not really complicated.

Basically, spinand is really more similar to spi nor, than to standard 
raw nand device.
I even wonder if it is a good idea or not, to extend the spi nor 
framework for a spi nand support ... (add bad block scanning, write size 
different from 1, check the the status for ECC errors or bad blocks ...)
But I suspect that "spi nor" maintainers will  not be happy to allow 
such risky modifications.

If we are going to a specific spinand framework, my advise would be to 
read again the spi nor framework carefully first, and do something 
similar (especially for latests work on quad spi)

Arnaud
>
> Anyway, I think we really should look at whether any of the
> identification and command sequencing details can be abstracted into a
> drivers/mtd/spinand/spinand.c, with client drivers mostly handling the
> transport protocol differences (e.g., interfacing with the SPI layer,
> similar to what m25p80.c does for SPI NOR).
>
> I don't have any time to create such a framwork on my own, but I may be
> able to spare some limited resources for reviewing others' work. I'd
> really like to see some efforts from a few interested reviewers, as I
> haven't figured out how to squeeze more hours into my day yet.
>
> BTW, has there been any progress on whatever TODO items landed
> mt29f_spinand in staging in the first place?
>
> Brian
>
> ______________________________________________________
> Linux MTD discussion mailing list
> http://lists.infradead.org/mailman/listinfo/linux-mtd/

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
@ 2014-11-20  8:39 bpqw
  2014-11-20 13:18 ` Ezequiel Garcia
  0 siblings, 1 reply; 16+ messages in thread
From: bpqw @ 2014-11-20  8:39 UTC (permalink / raw)
  To: Brian Norris, arnaud.mouiche@invoxia.com,
	linux-mtd@lists.infradead.org
  Cc: ezequiel.garcia@imgtec.com, ionela.voinescu@imgtec.com

Hi Brian, Arnaud:
> If we are going to a specific spinand framework, my advice would be to 
> read again the spi nor framework carefully first, and do something 
> similar (especially for latests work on quad spi)

I think above idea is good. 
SPI NAND interface and command protocol are similar with SPI NOR, we can 
create a SPI NAND folder with similar framework with SPI NOR. But need to duplicate 
nand_bbt and nand_bch code into this folder due to SPI NAND still need BBM and ECC.
How do you think?

I ever compared the SPI NAND command protocol with different vendor, result is same
with Ionela's answer.  

" As far as I've seen from the datasheets I have available (SPI NAND
GigaDevice 1Gb/2Gb/4Gb, Micron 1Gb/2Gb/4Gb), the command sequencing
is the same for read/write/erase operations (read: enable ECC, read to cache,
wait, read from cache, check for errors, disable ECC; write: enable ECC,
write enable, program load, program execute, wait, verify, disable ECC;
erase: write enable, erase block, verify).

Regarding the stream of bytes for each command, the problematic
commands are the read from cache ones (read, fast read, read x2,
read x4, read dual read quad) that have different command format
(additional dummy bytes, a plane select bit to be set).
Other differences are in the structure of the protection and status registers
(some of them use more ECC and protection bits according to the size
of the chip). Also, each has a different ECC layout "

If you need my detail comparison table, please let me know.

I already set up platform to support SPI NAND now, if you think the framework I mentioned 
above is reasonable, I can start to work on this.

Thanks

Qi Wang

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-20  8:39 bpqw
@ 2014-11-20 13:18 ` Ezequiel Garcia
  2014-11-25  7:02   ` bpqw
  0 siblings, 1 reply; 16+ messages in thread
From: Ezequiel Garcia @ 2014-11-20 13:18 UTC (permalink / raw)
  To: bpqw, Brian Norris, arnaud.mouiche@invoxia.com,
	linux-mtd@lists.infradead.org
  Cc: ionela.voinescu@imgtec.com



On 11/20/2014 05:39 AM, bpqw wrote:
> Hi Brian, Arnaud:
>> If we are going to a specific spinand framework, my advice would be to 
>> read again the spi nor framework carefully first, and do something 
>> similar (especially for latests work on quad spi)
> 
> I think above idea is good. 
> SPI NAND interface and command protocol are similar with SPI NOR, we can 
> create a SPI NAND folder with similar framework with SPI NOR. But need to duplicate 
> nand_bbt and nand_bch code into this folder due to SPI NAND still need BBM and ECC.
> How do you think?
> 

Hm, perhaps it's better to rely in the NAND core code and avoid that BBT
and ECC code handling duplication?

Ionela and I are preparing an SPI NAND framework, but it's far from
ready yet, so if you have something to submit, please do so :)

Thanks,
-- 
Ezequiel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
       [not found] <mailman.22397.1416508326.22890.linux-mtd@lists.infradead.org>
@ 2014-11-21  1:16 ` Qi Wang 王起 (qiwang)
  2014-11-21  9:24   ` arnaud.mouiche
  2014-11-21 11:51   ` Ezequiel Garcia
  0 siblings, 2 replies; 16+ messages in thread
From: Qi Wang 王起 (qiwang) @ 2014-11-21  1:16 UTC (permalink / raw)
  To: linux-mtd@lists.infradead.org, ezequiel.garcia@imgtec.com,
	arnaud.mouiche@invoxia.com, Brian Norris
  Cc: ionela.voinescu@imgtec.com

> On 11/20/2014 10:18 AM, Ezequiel Garcia wrote:
> Hm, perhaps it's better to rely in the NAND core code and avoid that BBT
> and ECC code handling duplication?
> 
> Ionela and I are preparing an SPI NAND framework, but it's far from
> ready yet, so if you have something to submit, please do so :)

Yes, duplicate BBT and ECC code from nand code do is not a good idea.
But SPI NAND framework should be a standalone module in MTD, might cause
chaos if it still rely on NAND core code, that is my only concern.
How do you think?

Thanks

Qi Wang

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-21  1:16 ` [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash Qi Wang 王起 (qiwang)
@ 2014-11-21  9:24   ` arnaud.mouiche
  2014-11-21 11:51   ` Ezequiel Garcia
  1 sibling, 0 replies; 16+ messages in thread
From: arnaud.mouiche @ 2014-11-21  9:24 UTC (permalink / raw)
  To: linux-mtd


Le 21/11/2014 02:16, Qi Wang 王起 (qiwang) a écrit :
>> On 11/20/2014 10:18 AM, Ezequiel Garcia wrote:
>> Hm, perhaps it's better to rely in the NAND core code and avoid that BBT
>> and ECC code handling duplication?
If it means using the framework from drivers/mtd/nand directory, no, 
definitely not.
This framework rely on common things that every raw nand devices are 
sharing, and on nand controllers from the SOC side.
That was my first attempt when looking for a spinand driver, but I 
quickly switch to
>>
>> Ionela and I are preparing an SPI NAND framework, but it's far from
>> ready yet, so if you have something to submit, please do so :)
> Yes, duplicate BBT and ECC code from nand code do is not a good idea.
> But SPI NAND framework should be a standalone module in MTD, might cause
> chaos if it still rely on NAND core code, that is my only concern.
> How do you think?
The ideal way to do should be to factorize the BBT for nand / onenand / 
spinand, or to provide helpers than are common.

Concerning ECC, we can even decide to drop software ECC for spinand. 
Current spinand device embed the required ecc hardware, correctly 
designed for the target nand (required ecc strength).
(may be I'm wrong on this point)

Arnaud

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

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-21  1:16 ` [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash Qi Wang 王起 (qiwang)
  2014-11-21  9:24   ` arnaud.mouiche
@ 2014-11-21 11:51   ` Ezequiel Garcia
  1 sibling, 0 replies; 16+ messages in thread
From: Ezequiel Garcia @ 2014-11-21 11:51 UTC (permalink / raw)
  To: "Qi Wang 王起 (qiwang)",
	linux-mtd@lists.infradead.org, arnaud.mouiche@invoxia.com,
	Brian Norris
  Cc: ionela.voinescu@imgtec.com, James Hartley



On 11/20/2014 10:16 PM, Qi Wang 王起 (qiwang) wrote:
>> On 11/20/2014 10:18 AM, Ezequiel Garcia wrote:
>> Hm, perhaps it's better to rely in the NAND core code and avoid that BBT
>> and ECC code handling duplication?
>>
>> Ionela and I are preparing an SPI NAND framework, but it's far from
>> ready yet, so if you have something to submit, please do so :)
> 
> Yes, duplicate BBT and ECC code from nand code do is not a good idea.
> But SPI NAND framework should be a standalone module in MTD, might cause
> chaos if it still rely on NAND core code, that is my only concern.

Any reasons why you think it should be a standalone MTD driver?

Why do you say it'd case chaos?

> How do you think?
> 

Yeah, I've been thinking about this for some time. Right now, I think that
SPI NAND is just that: a NAND over SPI, so I'm doing some experiments
around this design:

    Userspace
  ------------------
    MTD
  ------------------
    NAND core
  ------------------
    SPI NAND core
  ------------------
    SPI NAND device
  ------------------
    SPI core
  ------------------
    SPI master
  ------------------
    Hardware

-- 
Ezequiel

^ permalink raw reply	[flat|nested] 16+ messages in thread

* RE: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-20 13:18 ` Ezequiel Garcia
@ 2014-11-25  7:02   ` bpqw
  2014-11-25 16:59     ` Ezequiel Garcia
  0 siblings, 1 reply; 16+ messages in thread
From: bpqw @ 2014-11-25  7:02 UTC (permalink / raw)
  To: Ezequiel Garcia, bpqw, Brian Norris, arnaud.mouiche@invoxia.com,
	linux-mtd@lists.infradead.org
  Cc: ionela.voinescu@imgtec.com

>Yeah, I've been thinking about this for some time. Right now, I think that
>SPI NAND is just that: a NAND over SPI, so I'm doing some experiments
>around this design:
>
>    Userspace
>  ------------------
>    MTD
>  ------------------
>    NAND core
>  ------------------
>    SPI NAND core
>  ------------------
>    SPI NAND device
>  ------------------
>    SPI core
>  ------------------
>    SPI master
>  ------------------
>    Hardware

I have finished a initial version of SPI-NAND framework based on drivers/staging/
mt29f_spinand/mt29f_spinand.c . The structure is the same as yours, just treate SPI
NAND as a NAND over SPI, put SPI NAND core under NAND core. Do you think it is a
good structure to start with? Because it is a quick product, I even do not finish
the unregisger function. So just care about the structure. Any suggestion about the
patch is welcomed.

---
 drivers/mtd/Kconfig                           |   2 +
 drivers/mtd/Makefile                          |   1 +
 drivers/mtd/nand/nand_ids.c                   |   1 +
 drivers/mtd/spi-nand/Kconfig                  |  16 +
 drivers/mtd/spi-nand/Makefile                 |   1 +
 drivers/mtd/spi-nand/spi-nand.c               | 911 ++++++++++++++++++++++++++
 drivers/staging/mt29f_spinand/Kconfig         |   9 +-
 drivers/staging/mt29f_spinand/mt29f_spinand.c | 850 +-----------------------
 include/linux/mtd/spi-nand.h                  | 116 ++++
 9 files changed, 1068 insertions(+), 839 deletions(-)
 create mode 100644 drivers/mtd/spi-nand/Kconfig
 create mode 100644 drivers/mtd/spi-nand/Makefile
 create mode 100644 drivers/mtd/spi-nand/spi-nand.c
 create mode 100644 include/linux/mtd/spi-nand.h

diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index 94b8210..7bab890 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -323,6 +323,8 @@ source "drivers/mtd/lpddr/Kconfig"
 
 source "drivers/mtd/spi-nor/Kconfig"
 
+source "drivers/mtd/spi-nand/Kconfig"
+
 source "drivers/mtd/ubi/Kconfig"
 
 endif # MTD
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 99bb9a1..581688f 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -33,4 +33,5 @@ inftl-objs		:= inftlcore.o inftlmount.o
 obj-y		+= chips/ lpddr/ maps/ devices/ nand/ onenand/ tests/
 
 obj-$(CONFIG_MTD_SPI_NOR)	+= spi-nor/
+obj-$(CONFIG_MTD_SPI_NAND)	+= spi-nand/
 obj-$(CONFIG_MTD_UBI)		+= ubi/
diff --git a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c
index fbde8910..743a688 100644
--- a/drivers/mtd/nand/nand_ids.c
+++ b/drivers/mtd/nand/nand_ids.c
@@ -109,6 +109,7 @@ struct nand_flash_dev nand_flash_ids[] = {
 	/* 2 Gigabit */
 	EXTENDED_ID_NAND("NAND 256MiB 1,8V 8-bit",  0xAA, 256, LP_OPTIONS),
 	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0xDA, 256, LP_OPTIONS),
+	EXTENDED_ID_NAND("NAND 256MiB 3,3V 8-bit",  0x22, 256, LP_OPTIONS),
 	EXTENDED_ID_NAND("NAND 256MiB 1,8V 16-bit", 0xBA, 256, LP_OPTIONS16),
 	EXTENDED_ID_NAND("NAND 256MiB 3,3V 16-bit", 0xCA, 256, LP_OPTIONS16),
 
diff --git a/drivers/mtd/spi-nand/Kconfig b/drivers/mtd/spi-nand/Kconfig
new file mode 100644
index 0000000..ef0927b
--- /dev/null
+++ b/drivers/mtd/spi-nand/Kconfig
@@ -0,0 +1,16 @@
+menuconfig MTD_SPI_NAND
+	tristate "SPI-NAND device Support"
+	depends on MTD_NAND && SPI
+	help
+	  This is the framework for the SPI NAND which can be used by the SPI
+	  device drivers and the SPI-NAND device drivers.
+
+if MTD_SPI_NAND
+
+config MTD_SPI_NAND_ONDIEECC
+	bool "Use SPINAND internal ECC"
+	help
+	  Internal ECC.
+	  Enables Hardware ECC support for SPI NAND.
+
+endif # MTD_SPI_NAND
diff --git a/drivers/mtd/spi-nand/Makefile b/drivers/mtd/spi-nand/Makefile
new file mode 100644
index 0000000..0c018fc
--- /dev/null
+++ b/drivers/mtd/spi-nand/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_MTD_SPI_NAND) += spi-nand.o
diff --git a/drivers/mtd/spi-nand/spi-nand.c b/drivers/mtd/spi-nand/spi-nand.c
new file mode 100644
index 0000000..fccaabb
--- /dev/null
+++ b/drivers/mtd/spi-nand/spi-nand.c
@@ -0,0 +1,910 @@
+/*
+ * Copyright (c) 2009-2014 Micron Technology, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/nand.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/spi-nand.h>
+
+static inline struct spi_nand_chip *mtd_to_spinand(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
+	struct spi_nand_chip *spi_chip =
+			container_of(chip, struct spi_nand_chip, chip);
+
+	return spi_chip;
+}
+
+
+/*
+ * spinand_cmd - to process a command to send to the SPI Nand
+ * Description:
+ *    Set up the command buffer to send to the SPI controller.
+ *    The command buffer has to initialized to 0.
+ */
+
+static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
+{
+	struct spi_message message;
+	struct spi_transfer x[4];
+	u8 dummy = 0xff;
+
+	spi_message_init(&message);
+	memset(x, 0, sizeof(x));
+
+	x[0].len = 1;
+	x[0].tx_buf = &cmd->cmd;
+	spi_message_add_tail(&x[0], &message);
+
+	if (cmd->n_addr) {
+		x[1].len = cmd->n_addr;
+		x[1].tx_buf = cmd->addr;
+		spi_message_add_tail(&x[1], &message);
+	}
+
+	if (cmd->n_dummy) {
+		x[2].len = cmd->n_dummy;
+		x[2].tx_buf = &dummy;
+		spi_message_add_tail(&x[2], &message);
+	}
+
+	if (cmd->n_tx) {
+		x[3].len = cmd->n_tx;
+		x[3].tx_buf = cmd->tx_buf;
+		spi_message_add_tail(&x[3], &message);
+	}
+
+	if (cmd->n_rx) {
+		x[3].len = cmd->n_rx;
+		x[3].rx_buf = cmd->rx_buf;
+		spi_message_add_tail(&x[3], &message);
+	}
+
+	return spi_sync(spi, &message);
+}
+
+/*
+ * spinand_read_id- Read SPI Nand ID
+ * Description:
+ *    Read ID: read two ID bytes from the SPI Nand device
+ */
+static int spinand_read_id(struct spi_device *spi, u8 *id)
+{
+	int retval;
+	u8 nand_id[3];
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_READ_ID;
+	cmd.n_rx = 3;
+	cmd.rx_buf = &nand_id[0];
+
+	retval = spinand_cmd(spi, &cmd);
+	if (retval < 0) {
+		dev_err(&spi->dev, "error %d reading id\n", retval);
+		return retval;
+	}
+
+	/*Micron SPI NAND device*/
+	if (nand_id[1] == 0x2C) {
+		id[0] = nand_id[1];
+		id[1] = nand_id[2];
+	}
+	/*Giga device SPI NAND device*/
+	else if (nand_id[0] == 0xC8) {
+		id[0] = nand_id[0];
+		id[1] = nand_id[1];
+		id[2] = nand_id[2];
+	}
+
+	return retval;
+}
+
+/*
+ * spinand_read_status- send command 0xf to the SPI Nand status register
+ * Description:
+ *    After read, write, or erase, the Nand device is expected to set the
+ *    busy status.
+ *    This function is to allow reading the status of the command: read,
+ *    write, and erase.
+ *    Once the status turns to be ready, the other status bits also are
+ *    valid status bits.
+ */
+static int spinand_read_status(struct spi_device *spi, uint8_t *status)
+{
+	struct spinand_cmd cmd = {0};
+	int ret;
+
+	cmd.cmd = SPINAND_CMD_READ_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_STATUS;
+	cmd.n_rx = 1;
+	cmd.rx_buf = status;
+
+	ret = spinand_cmd(spi, &cmd);
+	if (ret < 0)
+		dev_err(&spi->dev, "err: %d read status register\n", ret);
+
+	return ret;
+}
+
+#define MAX_WAIT_JIFFIES  (40 * HZ)
+static int wait_till_ready(struct spi_device *spi)
+{
+	unsigned long deadline;
+	int retval;
+	u8 stat = 0;
+
+	deadline = jiffies + MAX_WAIT_JIFFIES;
+	do {
+		retval = spinand_read_status(spi, &stat);
+		if (retval < 0)
+			return -1;
+		else if (!(stat & 0x1))
+			break;
+
+		cond_resched();
+	} while (!time_after_eq(jiffies, deadline));
+
+	if ((stat & 0x1) == 0)
+		return 0;
+
+	return -1;
+}
+/**
+ * spinand_get_otp- send command 0xf to read the SPI Nand OTP register
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+ */
+static int spinand_get_otp(struct spi_device *spi, u8 *otp)
+{
+	struct spinand_cmd cmd = {0};
+	int retval;
+
+	cmd.cmd = SPINAND_CMD_READ_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_OTP;
+	cmd.n_rx = 1;
+	cmd.rx_buf = otp;
+
+	retval = spinand_cmd(spi, &cmd);
+	if (retval < 0)
+		dev_err(&spi->dev, "error %d get otp\n", retval);
+	return retval;
+}
+
+/**
+ * spinand_set_otp- send command 0x1f to write the SPI Nand OTP register
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+ */
+static int spinand_set_otp(struct spi_device *spi, u8 *otp)
+{
+	int retval;
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_WRITE_REG,
+	cmd.n_addr = 1,
+	cmd.addr[0] = REG_OTP,
+	cmd.n_tx = 1,
+	cmd.tx_buf = otp,
+
+	retval = spinand_cmd(spi, &cmd);
+	if (retval < 0)
+		dev_err(&spi->dev, "error %d set otp\n", retval);
+
+	return retval;
+}
+
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+/**
+ * spinand_enable_ecc- send command 0x1f to write the SPI Nand OTP register
+ * Description:
+ *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
+ *   Enable chip internal ECC, set the bit to 1
+ *   Disable chip internal ECC, clear the bit to 0
+ */
+static int spinand_enable_ecc(struct spi_device *spi)
+{
+	int retval;
+	u8 otp = 0;
+
+	retval = spinand_get_otp(spi, &otp);
+	if (retval < 0)
+		return retval;
+
+	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
+		return 0;
+
+	otp |= OTP_ECC_MASK;
+	retval = spinand_set_otp(spi, &otp);
+	if (retval < 0)
+		return retval;
+	return spinand_get_otp(spi, &otp);
+}
+#endif
+
+static int spinand_disable_ecc(struct spi_device *spi)
+{
+	int retval;
+	u8 otp = 0;
+
+	retval = spinand_get_otp(spi, &otp);
+	if (retval < 0)
+		return retval;
+
+	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
+		otp &= ~OTP_ECC_MASK;
+		retval = spinand_set_otp(spi, &otp);
+		if (retval < 0)
+			return retval;
+		return spinand_get_otp(spi, &otp);
+	} else
+		return 0;
+}
+
+/**
+ * spinand_write_enable- send command 0x06 to enable write or erase the
+ * Nand cells
+ * Description:
+ *   Before write and erase the Nand cells, the write enable has to be set.
+ *   After the write or erase, the write enable bit is automatically
+ *   cleared (status register bit 2)
+ *   Set the bit 2 of the status register has the same effect
+ */
+static int spinand_write_enable(struct spi_device *spi)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_WR_ENABLE;
+	return spinand_cmd(spi, &cmd);
+}
+
+static int spinand_read_page_to_cache(struct spi_device *spi, u32 page_id)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_READ;
+	cmd.n_addr = 3;
+	cmd.addr[0] = (u8)((page_id & 0x00FF0000) >> 16);
+	cmd.addr[1] = (u8)((page_id & 0x0000FF00) >> 8);
+	cmd.addr[2] = (u8)(page_id & 0x000000FF);
+
+	return spinand_cmd(spi, &cmd);
+}
+
+/*
+ * spinand_read_from_cache- send command 0x03 to read out the data from the
+ * cache register(2112 bytes max)
+ * Description:
+ *   The read can specify 1 to 2112 bytes of data read at the corresponding
+ *   locations.
+ *   No tRd delay.
+ */
+static int spinand_read_from_cache(struct spi_nand_chip *spi_chip, u32 page_id,
+		u16 byte_id, u16 len, u8 *rbuf)
+{
+	struct spinand_cmd cmd = {0};
+	u16 column;
+	struct spi_device *spi = spi_chip->spi;
+
+	column = byte_id;
+	cmd.cmd = SPINAND_CMD_READ_RDM;
+	cmd.n_addr = 3;
+	cmd.addr[0] = (u8)((column & 0xff00) >> 8);
+	if (spi_chip->plane_sel)
+		cmd.addr[0] |= (u8)(((page_id >> spi_chip->plane_bit) & 0x1)
+				 << 4);
+	cmd.addr[1] = (u8)(column & 0x00ff);
+	cmd.addr[2] = (u8)(0xff);
+	cmd.n_dummy = 0;
+	cmd.n_rx = len;
+	cmd.rx_buf = rbuf;
+
+	return spinand_cmd(spi, &cmd);
+}
+
+/*
+ * spinand_read_page-to read a page with:
+ * @page_id: the physical page number
+ * @offset:  the location from 0 to 2111
+ * @len:     number of bytes to read
+ * @rbuf:    read buffer to hold @len bytes
+ *
+ * Description:
+ *   The read includes two commands to the Nand: 0x13 and 0x03 commands
+ *   Poll to read status to wait for tRD time.
+ */
+static int spinand_read_page(struct spi_nand_chip *spi_chip, u32 page_id,
+		u16 offset, u16 len, u8 *rbuf)
+{
+	int ret;
+	u8 status = 0;
+	struct spi_device *spi = spi_chip->spi;
+
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	if (spi_chip->enable_read_hw_ecc) {
+		if (spinand_enable_ecc(spi) < 0)
+			dev_err(&spi->dev, "enable HW ECC failed!");
+	}
+#endif
+	ret = spinand_read_page_to_cache(spi, page_id);
+	if (ret < 0)
+		return ret;
+
+	if (wait_till_ready(spi))
+		dev_err(&spi->dev, "WAIT timedout!!!\n");
+
+	while (1) {
+		ret = spinand_read_status(spi, &status);
+		if (ret < 0) {
+			dev_err(&spi->dev,
+					"err %d read status register\n", ret);
+			return ret;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
+				dev_err(&spi->dev, "ecc error, page=%d\n",
+						page_id);
+				return 0;
+			}
+			break;
+		}
+	}
+
+	ret = spinand_read_from_cache(spi_chip, page_id, offset, len, rbuf);
+	if (ret < 0) {
+		dev_err(&spi->dev, "read from cache failed!!\n");
+		return ret;
+	}
+
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	if (spi_chip->enable_read_hw_ecc) {
+		ret = spinand_disable_ecc(spi);
+		if (ret < 0) {
+			dev_err(&spi->dev, "disable ecc failed!!\n");
+			return ret;
+		}
+		spi_chip->enable_read_hw_ecc = 0;
+	}
+#endif
+	return ret;
+}
+
+/*
+ * spinand_program_data_to_cache--to write a page to cache with:
+ * @byte_id: the location to write to the cache
+ * @len:     number of bytes to write
+ * @rbuf:    read buffer to hold @len bytes
+ *
+ * Description:
+ *   The write command used here is 0x84--indicating that the cache is
+ *   not cleared first.
+ *   Since it is writing the data to cache, there is no tPROG time.
+ */
+static int spinand_program_data_to_cache(struct spi_device *spi,
+		u32 page_id, u16 byte_id, u16 len, u8 *wbuf)
+{
+	struct spinand_cmd cmd = {0};
+	u16 column;
+
+	column = byte_id;
+	cmd.cmd = SPINAND_CMD_PROG_PAGE_CLRCACHE;
+	cmd.n_addr = 2;
+	cmd.addr[0] = (u8)((column & 0xff00) >> 8);
+	cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
+	cmd.addr[1] = (u8)(column & 0x00ff);
+	cmd.n_tx = len;
+	cmd.tx_buf = wbuf;
+
+	return spinand_cmd(spi, &cmd);
+}
+
+/**
+ * spinand_program_execute--to write a page from cache to the Nand array with
+ * @page_id: the physical page location to write the page.
+ *
+ * Description:
+ *   The write command used here is 0x10--indicating the cache is writing to
+ *   the Nand array.
+ *   Need to wait for tPROG time to finish the transaction.
+ */
+static int spinand_program_execute(struct spi_device *spi, u32 page_id)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_PROG_PAGE_EXC;
+	cmd.n_addr = 3;
+	cmd.addr[0] = (u8)((page_id & 0x00FF0000) >> 16);
+	cmd.addr[1] = (u8)((page_id & 0x0000FF00) >> 8);
+	cmd.addr[2] = (u8)(page_id & 0x000000FF);
+
+
+	return spinand_cmd(spi, &cmd);
+}
+
+/**
+ * spinand_program_page--to write a page with:
+ * @page_id: the physical page location to write the page.
+ * @offset:  the location from the cache starting from 0 to 2111
+ * @len:     the number of bytes to write
+ * @wbuf:    the buffer to hold the number of bytes
+ *
+ * Description:
+ *   The commands used here are 0x06, 0x84, and 0x10--indicating that
+ *   the write enable is first sent, the write cache command, and the
+ *   write execute command.
+ *   Poll to wait for the tPROG time to finish the transaction.
+ */
+static int spinand_program_page(struct spi_nand_chip *spi_chip,
+		u32 page_id, u16 offset, u16 len, u8 *buf)
+{
+	struct spi_device *spi = spi_chip->spi;
+	int retval;
+	u8 status = 0;
+	uint8_t *wbuf;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	unsigned int i, j;
+
+	spi_chip->enable_read_hw_ecc = 0;
+	wbuf = spi_chip->ecc_buf;
+	spinand_read_page(spi_chip, page_id, 0, spi_chip->cache_size, wbuf);
+
+	for (i = offset, j = 0; i < len; i++, j++)
+		wbuf[i] &= buf[j];
+
+	if (spi_chip->enable_hw_ecc) {
+		retval = spinand_enable_ecc(spi);
+		if (retval < 0) {
+			dev_err(&spi->dev, "enable ecc failed!!\n");
+			return retval;
+		}
+	}
+#else
+	wbuf = buf;
+#endif
+	retval = spinand_write_enable(spi);
+	if (retval < 0) {
+		dev_err(&spi->dev, "write enable failed!!\n");
+		return retval;
+	}
+	if (wait_till_ready(spi))
+		dev_err(&spi->dev, "wait timedout!!!\n");
+
+	retval = spinand_program_data_to_cache(spi, page_id,
+			offset, len, wbuf);
+	if (retval < 0)
+		return retval;
+	retval = spinand_program_execute(spi, page_id);
+	if (retval < 0)
+		return retval;
+	while (1) {
+		retval = spinand_read_status(spi, &status);
+		if (retval < 0) {
+			dev_err(&spi->dev,
+					"error %d reading status register\n",
+					retval);
+			return retval;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL)
+				dev_err(&spi->dev,
+					"program error, page %d\n", page_id);
+				return -1;
+			break;
+		}
+	}
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	if (spi_chip->enable_hw_ecc) {
+		retval = spinand_disable_ecc(spi);
+		if (retval < 0) {
+			dev_err(&spi->dev, "disable ecc failed!!\n");
+			return retval;
+		}
+		spi_chip->enable_hw_ecc = 0;
+	}
+#endif
+
+	return 0;
+}
+
+/**
+ * spinand_erase_block_erase--to erase a page with:
+ * @block_id: the physical block location to erase.
+ *
+ * Description:
+ *   The command used here is 0xd8--indicating an erase command to erase
+ *   one block--64 pages
+ *   Need to wait for tERS.
+ */
+static int spinand_erase_block_erase(struct spi_device *spi, u16 block_id)
+{
+	struct spinand_cmd cmd = {0};
+	u16 row;
+
+	row = block_id;
+	cmd.cmd = SPINAND_CMD_ERASE_BLK;
+	cmd.n_addr = 3;
+	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
+	cmd.addr[2] = (u8)(row & 0x00ff);
+
+	return spinand_cmd(spi, &cmd);
+}
+
+/**
+ * spinand_erase_block--to erase a page with:
+ * @block_id: the physical block location to erase.
+ *
+ * Description:
+ *   The commands used here are 0x06 and 0xd8--indicating an erase
+ *   command to erase one block--64 pages
+ *   It will first to enable the write enable bit (0x06 command),
+ *   and then send the 0xd8 erase command
+ *   Poll to wait for the tERS time to complete the tranaction.
+ */
+static int spinand_erase_block(struct spi_device *spi, u16 block_id)
+{
+	int retval;
+	u8 status = 0;
+
+	retval = spinand_write_enable(spi);
+	if (wait_till_ready(spi))
+		dev_err(&spi->dev, "wait timedout!!!\n");
+
+	retval = spinand_erase_block_erase(spi, block_id);
+	while (1) {
+		retval = spinand_read_status(spi, &status);
+		if (retval < 0) {
+			dev_err(&spi->dev,
+					"error %d reading status register\n",
+					(int) retval);
+			return retval;
+		}
+
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL)
+				dev_err(&spi->dev,
+					"erase error, block %d\n", block_id);
+				return -1;
+			break;
+		}
+	}
+	return 0;
+}
+
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+static int spinand_write_page_hwecc(struct mtd_info *mtd,
+		struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	const uint8_t *p = buf;
+	int eccsize = chip->ecc.size;
+	int eccsteps = chip->ecc.steps;
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+
+	spi_chip->enable_hw_ecc = 1;
+	chip->write_buf(mtd, p, eccsize * eccsteps);
+	return 0;
+}
+
+static int spinand_read_page_hwecc(struct mtd_info *mtd,
+	struct nand_chip *chip,	uint8_t *buf, int oob_required, int page)
+{
+	u8 retval, status;
+	uint8_t *p = buf;
+	int eccsize = chip->ecc.size;
+	int eccsteps = chip->ecc.steps;
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+
+	spi_chip->enable_read_hw_ecc = 1;
+	chip->read_buf(mtd, p, eccsize * eccsteps);
+	if (oob_required)
+		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+	while (1) {
+		retval = spinand_read_status(spi_chip->spi, &status);
+		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
+			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
+				pr_info("spinand: ECC error\n");
+				mtd->ecc_stats.failed++;
+			} else if ((status & STATUS_ECC_MASK) ==
+					STATUS_ECC_1BIT_CORRECTED)
+				mtd->ecc_stats.corrected++;
+			break;
+		}
+	}
+	return 0;
+
+}
+#endif
+
+static void spinand_select_chip(struct mtd_info *mtd, int dev)
+{
+}
+
+static uint8_t spinand_read_byte(struct mtd_info *mtd)
+{
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+	u8 data;
+
+	data = spi_chip->buf[spi_chip->buf_ptr];
+	spi_chip->buf_ptr++;
+	return data;
+}
+
+
+static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
+{
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+
+	unsigned long timeo = jiffies;
+	int retval, state = chip->state;
+	u8 status;
+
+	if (state == FL_ERASING)
+		timeo += (HZ * 400) / 1000;
+	else
+		timeo += (HZ * 20) / 1000;
+
+	while (time_before(jiffies, timeo)) {
+		retval = spinand_read_status(spi_chip->spi, &status);
+		if ((status & STATUS_OIP_MASK) == STATUS_READY)
+			return 0;
+
+		cond_resched();
+	}
+	return 0;
+}
+
+static void spinand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
+				int len)
+{
+
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+
+	memcpy(spi_chip->buf + spi_chip->buf_ptr, buf, len);
+	spi_chip->buf_ptr += len;
+}
+
+static void spinand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+
+	memcpy(buf, spi_chip->buf + spi_chip->buf_ptr, len);
+	spi_chip->buf_ptr += len;
+}
+
+/*
+ * spinand_reset- send RESET command "0xff" to the Nand device.
+ */
+static void spinand_reset(struct spi_device *spi)
+{
+	struct spinand_cmd cmd = {0};
+
+	cmd.cmd = SPINAND_CMD_RESET;
+
+	if (spinand_cmd(spi, &cmd) < 0)
+		pr_info("spinand reset failed!\n");
+
+	/* elapse 1ms before issuing any other command */
+	udelay(1000);
+
+	if (wait_till_ready(spi))
+		dev_err(&spi->dev, "wait timedout!\n");
+}
+
+static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
+		int column, int page)
+{
+	struct spi_nand_chip *spi_chip = mtd_to_spinand(mtd);
+	struct spi_device *spi = spi_chip->spi;
+
+	switch (command) {
+	/*
+	 * READ0 - read in first  0x800 bytes
+	 */
+	case NAND_CMD_READ1:
+	case NAND_CMD_READ0:
+		spi_chip->buf_ptr = 0;
+		spinand_read_page(spi_chip, page, 0,
+		mtd->writesize + mtd->oobsize, spi_chip->buf);
+		break;
+	/* READOOB reads only the OOB because no ECC is performed. */
+	case NAND_CMD_READOOB:
+		spi_chip->buf_ptr = 0;
+		spinand_read_page(spi_chip, page, mtd->writesize,
+		 mtd->oobsize, spi_chip->buf);
+		break;
+	case NAND_CMD_RNDOUT:
+		spi_chip->buf_ptr = column;
+		break;
+	case NAND_CMD_READID:
+		spi_chip->buf_ptr = 0;
+		spinand_read_id(spi, (u8 *)spi_chip->buf);
+		break;
+	case NAND_CMD_PARAM:
+		spi_chip->buf_ptr = 0;
+		break;
+	/* ERASE1 stores the block and page address */
+	case NAND_CMD_ERASE1:
+		spinand_erase_block(spi, page);
+		break;
+	/* ERASE2 uses the block and page address from ERASE1 */
+	case NAND_CMD_ERASE2:
+		break;
+	/* SEQIN sets up the addr buffer and all registers except the length */
+	case NAND_CMD_SEQIN:
+		spi_chip->col = column;
+		spi_chip->row = page;
+		spi_chip->buf_ptr = 0;
+		break;
+	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
+	case NAND_CMD_PAGEPROG:
+		spinand_program_page(spi_chip, spi_chip->row, spi_chip->col,
+				spi_chip->buf_ptr, spi_chip->buf);
+		break;
+	case NAND_CMD_STATUS:
+		spinand_get_otp(spi, spi_chip->buf);
+		if (!(spi_chip->buf[0] & 0x80))
+			spi_chip->buf[0] = 0x80;
+		spi_chip->buf_ptr = 0;
+		break;
+	/* RESET command */
+	case NAND_CMD_RESET:
+		if (wait_till_ready(spi))
+			dev_err(&spi->dev, "WAIT timedout!!!\n");
+		/* a minimum of 250us must elapse before issuing RESET cmd*/
+		udelay(250);
+		spinand_reset(spi);
+		break;
+	default:
+		dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command);
+	}
+}
+
+/**
+ * spinand_lock_block- send write register 0x1f command to the Nand device
+ *
+ * Description:
+ *    After power up, all the Nand blocks are locked.  This function allows
+ *    one to unlock the blocks, and so it can be written or erased.
+ */
+static int spinand_lock_block(struct spi_device *spi, u8 lock)
+{
+	struct spinand_cmd cmd = {0};
+	int ret;
+	u8 otp = 0;
+
+	ret = spinand_get_otp(spi, &otp);
+
+	cmd.cmd = SPINAND_CMD_WRITE_REG;
+	cmd.n_addr = 1;
+	cmd.addr[0] = REG_BLOCK_LOCK;
+	cmd.n_tx = 1;
+	cmd.tx_buf = &lock;
+
+	ret = spinand_cmd(spi, &cmd);
+	if (ret < 0)
+		dev_err(&spi->dev, "error %d lock block\n", ret);
+
+	return ret;
+}
+
+int spinand_set_plane_info(struct spi_nand_chip *spi_chip, u16 plane_sel,
+				u16 plane_bit)
+{
+	spi_chip->plane_sel = plane_sel;
+	spi_chip->plane_bit = plane_bit;
+
+	return 0;
+}
+int spinand_set_buffer_size(struct spi_nand_chip *spi_chip, u32 buf_size,
+				u32 cache_size)
+{
+	spi_chip->buf_size = buf_size;
+	spi_chip->cache_size = cache_size;
+
+	return 0;
+}
+
+static int spinand_alloc_buffer(struct spi_nand_chip *spi_chip)
+{
+	struct spi_device *spi = spi_chip->spi;
+
+	spi_chip->buf_ptr	= 0;
+	spi_chip->buf = devm_kzalloc(&spi->dev, spi_chip->buf_size,
+				GFP_KERNEL);
+	if (!spi_chip->buf)
+		return -ENOMEM;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	spi_chip->ecc_buf = devm_kzalloc(&spi->dev, spi_chip->cache_size,
+				GFP_KERNEL);
+	if (!spi_chip->ecc_buf)
+		return -ENOMEM;
+#endif
+
+	return 0;
+}
+
+struct spi_nand_chip *spinand_alloc_chip(struct spi_device *spi)
+{
+	struct spi_nand_chip *spi_chip;
+	struct nand_chip *chip;
+
+	spi_chip = devm_kzalloc(&spi->dev, sizeof(struct spi_nand_chip),
+			GFP_KERNEL);
+	if (!spi_chip)
+		return ERR_PTR(-ENOMEM);
+
+	spi_chip->spi = spi;
+	chip = &spi_chip->chip;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	chip->ecc.mode	= NAND_ECC_HW;
+	chip->ecc.read_page = spinand_read_page_hwecc;
+	chip->ecc.write_page = spinand_write_page_hwecc;
+#else
+	chip->ecc.mode	= NAND_ECC_SOFT;
+	if (spinand_disable_ecc(spi) < 0)
+		pr_info("%s: disable ecc failed!\n", __func__);
+#endif
+
+	chip->read_buf	= spinand_read_buf;
+	chip->write_buf	= spinand_write_buf;
+	chip->read_byte	= spinand_read_byte;
+	chip->cmdfunc	= spinand_cmdfunc;
+	chip->waitfunc	= spinand_wait;
+	chip->options	|= NAND_CACHEPRG;
+	chip->select_chip = spinand_select_chip;
+
+	return spi_chip;
+}
+EXPORT_SYMBOL(spinand_alloc_chip);
+
+
+int spinand_register_chip(struct spi_nand_chip *spi_chip)
+{
+	struct mtd_info *mtd;
+	struct mtd_part_parser_data ppdata;
+	struct spi_device *spi = spi_chip->spi;
+
+	mtd = devm_kzalloc(&spi->dev, sizeof(struct mtd_info), GFP_KERNEL);
+	if (!mtd)
+		return -ENOMEM;
+
+	dev_set_drvdata(&spi->dev, mtd);
+
+	mtd->priv = &spi_chip->chip;
+	mtd->name = dev_name(&spi->dev);
+	mtd->owner = THIS_MODULE;
+	spinand_alloc_buffer(spi_chip);
+
+	spinand_lock_block(spi, BL_ALL_UNLOCKED);
+	if (nand_scan(mtd, 1))
+		return -ENXIO;
+
+	ppdata.of_node = spi->dev.of_node;
+	return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+}
+EXPORT_SYMBOL(spinand_register_chip);
+
+
+MODULE_DESCRIPTION("SPI NAND framewowk");
+MODULE_AUTHOR("Peter Pan<bpqw@micron.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig
index 4031748..7219c5a 100644
--- a/drivers/staging/mt29f_spinand/Kconfig
+++ b/drivers/staging/mt29f_spinand/Kconfig
@@ -1,16 +1,9 @@
 config MTD_SPINAND_MT29F
 	tristate "SPINAND Device Support for Micron"
-	depends on MTD_NAND && SPI
+	depends on MTD_SPI_NAND
 	help
 	  This enables support for accessing Micron SPI NAND flash
 	  devices.
 	  If you have Micron SPI NAND chip say yes.
 
 	  If unsure, say no here.
-
-config MTD_SPINAND_ONDIEECC
-	bool "Use SPINAND internal ECC"
-	depends on MTD_SPINAND_MT29F
-	help
-	  Internel ECC.
-	  Enables Hardware ECC support for Micron SPI NAND.
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 3628bcb..97cee77 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -20,23 +20,8 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/nand.h>
 #include <linux/spi/spi.h>
+#include <linux/mtd/spi-nand.h>
 
-#include "mt29f_spinand.h"
-
-#define BUFSIZE (10 * 64 * 2048)
-#define CACHE_BUF 2112
-/*
- * OOB area specification layout:  Total 32 available free bytes.
- */
-
-static inline struct spinand_state *mtd_to_state(struct mtd_info *mtd)
-{
-	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-	struct spinand_info *info = (struct spinand_info *)chip->priv;
-	struct spinand_state *state = (struct spinand_state *)info->priv;
-
-	return state;
-}
 
 #ifdef CONFIG_MTD_SPINAND_ONDIEECC
 static int enable_hw_ecc;
@@ -63,809 +48,39 @@ static struct nand_ecclayout spinand_oob_64 = {
 };
 #endif
 
-/*
- * spinand_cmd - to process a command to send to the SPI Nand
- * Description:
- *    Set up the command buffer to send to the SPI controller.
- *    The command buffer has to initialized to 0.
- */
-
-static int spinand_cmd(struct spi_device *spi, struct spinand_cmd *cmd)
-{
-	struct spi_message message;
-	struct spi_transfer x[4];
-	u8 dummy = 0xff;
-
-	spi_message_init(&message);
-	memset(x, 0, sizeof(x));
-
-	x[0].len = 1;
-	x[0].tx_buf = &cmd->cmd;
-	spi_message_add_tail(&x[0], &message);
-
-	if (cmd->n_addr) {
-		x[1].len = cmd->n_addr;
-		x[1].tx_buf = cmd->addr;
-		spi_message_add_tail(&x[1], &message);
-	}
-
-	if (cmd->n_dummy) {
-		x[2].len = cmd->n_dummy;
-		x[2].tx_buf = &dummy;
-		spi_message_add_tail(&x[2], &message);
-	}
-
-	if (cmd->n_tx) {
-		x[3].len = cmd->n_tx;
-		x[3].tx_buf = cmd->tx_buf;
-		spi_message_add_tail(&x[3], &message);
-	}
-
-	if (cmd->n_rx) {
-		x[3].len = cmd->n_rx;
-		x[3].rx_buf = cmd->rx_buf;
-		spi_message_add_tail(&x[3], &message);
-	}
-
-	return spi_sync(spi, &message);
-}
-
-/*
- * spinand_read_id- Read SPI Nand ID
- * Description:
- *    Read ID: read two ID bytes from the SPI Nand device
- */
-static int spinand_read_id(struct spi_device *spi_nand, u8 *id)
-{
-	int retval;
-	u8 nand_id[3];
-	struct spinand_cmd cmd = {0};
-
-	cmd.cmd = CMD_READ_ID;
-	cmd.n_rx = 3;
-	cmd.rx_buf = &nand_id[0];
-
-	retval = spinand_cmd(spi_nand, &cmd);
-	if (retval < 0) {
-		dev_err(&spi_nand->dev, "error %d reading id\n", retval);
-		return retval;
-	}
-	id[0] = nand_id[1];
-	id[1] = nand_id[2];
-	return retval;
-}
-
-/*
- * spinand_read_status- send command 0xf to the SPI Nand status register
- * Description:
- *    After read, write, or erase, the Nand device is expected to set the
- *    busy status.
- *    This function is to allow reading the status of the command: read,
- *    write, and erase.
- *    Once the status turns to be ready, the other status bits also are
- *    valid status bits.
- */
-static int spinand_read_status(struct spi_device *spi_nand, uint8_t *status)
-{
-	struct spinand_cmd cmd = {0};
-	int ret;
-
-	cmd.cmd = CMD_READ_REG;
-	cmd.n_addr = 1;
-	cmd.addr[0] = REG_STATUS;
-	cmd.n_rx = 1;
-	cmd.rx_buf = status;
-
-	ret = spinand_cmd(spi_nand, &cmd);
-	if (ret < 0)
-		dev_err(&spi_nand->dev, "err: %d read status register\n", ret);
-
-	return ret;
-}
-
-#define MAX_WAIT_JIFFIES  (40 * HZ)
-static int wait_till_ready(struct spi_device *spi_nand)
-{
-	unsigned long deadline;
-	int retval;
-	u8 stat = 0;
-
-	deadline = jiffies + MAX_WAIT_JIFFIES;
-	do {
-		retval = spinand_read_status(spi_nand, &stat);
-		if (retval < 0)
-			return -1;
-		else if (!(stat & 0x1))
-			break;
-
-		cond_resched();
-	} while (!time_after_eq(jiffies, deadline));
-
-	if ((stat & 0x1) == 0)
-		return 0;
-
-	return -1;
-}
-/**
- * spinand_get_otp- send command 0xf to read the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_get_otp(struct spi_device *spi_nand, u8 *otp)
-{
-	struct spinand_cmd cmd = {0};
-	int retval;
-
-	cmd.cmd = CMD_READ_REG;
-	cmd.n_addr = 1;
-	cmd.addr[0] = REG_OTP;
-	cmd.n_rx = 1;
-	cmd.rx_buf = otp;
-
-	retval = spinand_cmd(spi_nand, &cmd);
-	if (retval < 0)
-		dev_err(&spi_nand->dev, "error %d get otp\n", retval);
-	return retval;
-}
-
-/**
- * spinand_set_otp- send command 0x1f to write the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_set_otp(struct spi_device *spi_nand, u8 *otp)
-{
-	int retval;
-	struct spinand_cmd cmd = {0};
-
-	cmd.cmd = CMD_WRITE_REG,
-	cmd.n_addr = 1,
-	cmd.addr[0] = REG_OTP,
-	cmd.n_tx = 1,
-	cmd.tx_buf = otp,
-
-	retval = spinand_cmd(spi_nand, &cmd);
-	if (retval < 0)
-		dev_err(&spi_nand->dev, "error %d set otp\n", retval);
-
-	return retval;
-}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-/**
- * spinand_enable_ecc- send command 0x1f to write the SPI Nand OTP register
- * Description:
- *   There is one bit( bit 0x10 ) to set or to clear the internal ECC.
- *   Enable chip internal ECC, set the bit to 1
- *   Disable chip internal ECC, clear the bit to 0
- */
-static int spinand_enable_ecc(struct spi_device *spi_nand)
-{
-	int retval;
-	u8 otp = 0;
-
-	retval = spinand_get_otp(spi_nand, &otp);
-	if (retval < 0)
-		return retval;
-
-	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK)
-		return 0;
-	otp |= OTP_ECC_MASK;
-	retval = spinand_set_otp(spi_nand, &otp);
-	if (retval < 0)
-		return retval;
-	return spinand_get_otp(spi_nand, &otp);
-}
-#endif
-
-static int spinand_disable_ecc(struct spi_device *spi_nand)
-{
-	int retval;
-	u8 otp = 0;
-
-	retval = spinand_get_otp(spi_nand, &otp);
-	if (retval < 0)
-		return retval;
-
-	if ((otp & OTP_ECC_MASK) == OTP_ECC_MASK) {
-		otp &= ~OTP_ECC_MASK;
-		retval = spinand_set_otp(spi_nand, &otp);
-		if (retval < 0)
-			return retval;
-		return spinand_get_otp(spi_nand, &otp);
-	}
-	return 0;
-}
-
-/**
- * spinand_write_enable- send command 0x06 to enable write or erase the
- * Nand cells
- * Description:
- *   Before write and erase the Nand cells, the write enable has to be set.
- *   After the write or erase, the write enable bit is automatically
- *   cleared (status register bit 2)
- *   Set the bit 2 of the status register has the same effect
- */
-static int spinand_write_enable(struct spi_device *spi_nand)
-{
-	struct spinand_cmd cmd = {0};
-
-	cmd.cmd = CMD_WR_ENABLE;
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-static int spinand_read_page_to_cache(struct spi_device *spi_nand, u16 page_id)
-{
-	struct spinand_cmd cmd = {0};
-	u16 row;
-
-	row = page_id;
-	cmd.cmd = CMD_READ;
-	cmd.n_addr = 3;
-	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-	cmd.addr[2] = (u8)(row & 0x00ff);
-
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-/*
- * spinand_read_from_cache- send command 0x03 to read out the data from the
- * cache register(2112 bytes max)
- * Description:
- *   The read can specify 1 to 2112 bytes of data read at the corresponding
- *   locations.
- *   No tRd delay.
- */
-static int spinand_read_from_cache(struct spi_device *spi_nand, u16 page_id,
-		u16 byte_id, u16 len, u8 *rbuf)
-{
-	struct spinand_cmd cmd = {0};
-	u16 column;
-
-	column = byte_id;
-	cmd.cmd = CMD_READ_RDM;
-	cmd.n_addr = 3;
-	cmd.addr[0] = (u8)((column & 0xff00) >> 8);
-	cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
-	cmd.addr[1] = (u8)(column & 0x00ff);
-	cmd.addr[2] = (u8)(0xff);
-	cmd.n_dummy = 0;
-	cmd.n_rx = len;
-	cmd.rx_buf = rbuf;
-
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-/*
- * spinand_read_page-to read a page with:
- * @page_id: the physical page number
- * @offset:  the location from 0 to 2111
- * @len:     number of bytes to read
- * @rbuf:    read buffer to hold @len bytes
- *
- * Description:
- *   The read includes two commands to the Nand: 0x13 and 0x03 commands
- *   Poll to read status to wait for tRD time.
- */
-static int spinand_read_page(struct spi_device *spi_nand, u16 page_id,
-		u16 offset, u16 len, u8 *rbuf)
-{
-	int ret;
-	u8 status = 0;
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-	if (enable_read_hw_ecc) {
-		if (spinand_enable_ecc(spi_nand) < 0)
-			dev_err(&spi_nand->dev, "enable HW ECC failed!");
-	}
-#endif
-	ret = spinand_read_page_to_cache(spi_nand, page_id);
-	if (ret < 0)
-		return ret;
-
-	if (wait_till_ready(spi_nand))
-		dev_err(&spi_nand->dev, "WAIT timedout!!!\n");
-
-	while (1) {
-		ret = spinand_read_status(spi_nand, &status);
-		if (ret < 0) {
-			dev_err(&spi_nand->dev,
-					"err %d read status register\n", ret);
-			return ret;
-		}
-
-		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
-				dev_err(&spi_nand->dev, "ecc error, page=%d\n",
-						page_id);
-				return 0;
-			}
-			break;
-		}
-	}
-
-	ret = spinand_read_from_cache(spi_nand, page_id, offset, len, rbuf);
-	if (ret < 0) {
-		dev_err(&spi_nand->dev, "read from cache failed!!\n");
-		return ret;
-	}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-	if (enable_read_hw_ecc) {
-		ret = spinand_disable_ecc(spi_nand);
-		if (ret < 0) {
-			dev_err(&spi_nand->dev, "disable ecc failed!!\n");
-			return ret;
-		}
-		enable_read_hw_ecc = 0;
-	}
-#endif
-	return ret;
-}
-
-/*
- * spinand_program_data_to_cache--to write a page to cache with:
- * @byte_id: the location to write to the cache
- * @len:     number of bytes to write
- * @rbuf:    read buffer to hold @len bytes
- *
- * Description:
- *   The write command used here is 0x84--indicating that the cache is
- *   not cleared first.
- *   Since it is writing the data to cache, there is no tPROG time.
- */
-static int spinand_program_data_to_cache(struct spi_device *spi_nand,
-		u16 page_id, u16 byte_id, u16 len, u8 *wbuf)
-{
-	struct spinand_cmd cmd = {0};
-	u16 column;
-
-	column = byte_id;
-	cmd.cmd = CMD_PROG_PAGE_CLRCACHE;
-	cmd.n_addr = 2;
-	cmd.addr[0] = (u8)((column & 0xff00) >> 8);
-	cmd.addr[0] |= (u8)(((page_id >> 6) & 0x1) << 4);
-	cmd.addr[1] = (u8)(column & 0x00ff);
-	cmd.n_tx = len;
-	cmd.tx_buf = wbuf;
-
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_program_execute--to write a page from cache to the Nand array with
- * @page_id: the physical page location to write the page.
- *
- * Description:
- *   The write command used here is 0x10--indicating the cache is writing to
- *   the Nand array.
- *   Need to wait for tPROG time to finish the transaction.
- */
-static int spinand_program_execute(struct spi_device *spi_nand, u16 page_id)
-{
-	struct spinand_cmd cmd = {0};
-	u16 row;
-
-	row = page_id;
-	cmd.cmd = CMD_PROG_PAGE_EXC;
-	cmd.n_addr = 3;
-	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-	cmd.addr[2] = (u8)(row & 0x00ff);
-
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_program_page--to write a page with:
- * @page_id: the physical page location to write the page.
- * @offset:  the location from the cache starting from 0 to 2111
- * @len:     the number of bytes to write
- * @wbuf:    the buffer to hold the number of bytes
- *
- * Description:
- *   The commands used here are 0x06, 0x84, and 0x10--indicating that
- *   the write enable is first sent, the write cache command, and the
- *   write execute command.
- *   Poll to wait for the tPROG time to finish the transaction.
- */
-static int spinand_program_page(struct spi_device *spi_nand,
-		u16 page_id, u16 offset, u16 len, u8 *buf)
-{
-	int retval;
-	u8 status = 0;
-	uint8_t *wbuf;
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-	unsigned int i, j;
-
-	enable_read_hw_ecc = 0;
-	wbuf = devm_kzalloc(&spi_nand->dev, CACHE_BUF, GFP_KERNEL);
-	spinand_read_page(spi_nand, page_id, 0, CACHE_BUF, wbuf);
-
-	for (i = offset, j = 0; i < len; i++, j++)
-		wbuf[i] &= buf[j];
-
-	if (enable_hw_ecc) {
-		retval = spinand_enable_ecc(spi_nand);
-		if (retval < 0) {
-			dev_err(&spi_nand->dev, "enable ecc failed!!\n");
-			return retval;
-		}
-	}
-#else
-	wbuf = buf;
-#endif
-	retval = spinand_write_enable(spi_nand);
-	if (retval < 0) {
-		dev_err(&spi_nand->dev, "write enable failed!!\n");
-		return retval;
-	}
-	if (wait_till_ready(spi_nand))
-		dev_err(&spi_nand->dev, "wait timedout!!!\n");
-
-	retval = spinand_program_data_to_cache(spi_nand, page_id,
-			offset, len, wbuf);
-	if (retval < 0)
-		return retval;
-	retval = spinand_program_execute(spi_nand, page_id);
-	if (retval < 0)
-		return retval;
-	while (1) {
-		retval = spinand_read_status(spi_nand, &status);
-		if (retval < 0) {
-			dev_err(&spi_nand->dev,
-					"error %d reading status register\n",
-					retval);
-			return retval;
-		}
-
-		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-			if ((status & STATUS_P_FAIL_MASK) == STATUS_P_FAIL) {
-				dev_err(&spi_nand->dev,
-					"program error, page %d\n", page_id);
-				return -1;
-			}
-			break;
-		}
-	}
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-	if (enable_hw_ecc) {
-		retval = spinand_disable_ecc(spi_nand);
-		if (retval < 0) {
-			dev_err(&spi_nand->dev, "disable ecc failed!!\n");
-			return retval;
-		}
-		enable_hw_ecc = 0;
-	}
-#endif
-
-	return 0;
-}
-
-/**
- * spinand_erase_block_erase--to erase a page with:
- * @block_id: the physical block location to erase.
- *
- * Description:
- *   The command used here is 0xd8--indicating an erase command to erase
- *   one block--64 pages
- *   Need to wait for tERS.
- */
-static int spinand_erase_block_erase(struct spi_device *spi_nand, u16 block_id)
-{
-	struct spinand_cmd cmd = {0};
-	u16 row;
-
-	row = block_id;
-	cmd.cmd = CMD_ERASE_BLK;
-	cmd.n_addr = 3;
-	cmd.addr[1] = (u8)((row & 0xff00) >> 8);
-	cmd.addr[2] = (u8)(row & 0x00ff);
-
-	return spinand_cmd(spi_nand, &cmd);
-}
-
-/**
- * spinand_erase_block--to erase a page with:
- * @block_id: the physical block location to erase.
- *
- * Description:
- *   The commands used here are 0x06 and 0xd8--indicating an erase
- *   command to erase one block--64 pages
- *   It will first to enable the write enable bit (0x06 command),
- *   and then send the 0xd8 erase command
- *   Poll to wait for the tERS time to complete the tranaction.
- */
-static int spinand_erase_block(struct spi_device *spi_nand, u16 block_id)
-{
-	int retval;
-	u8 status = 0;
-
-	retval = spinand_write_enable(spi_nand);
-	if (wait_till_ready(spi_nand))
-		dev_err(&spi_nand->dev, "wait timedout!!!\n");
-
-	retval = spinand_erase_block_erase(spi_nand, block_id);
-	while (1) {
-		retval = spinand_read_status(spi_nand, &status);
-		if (retval < 0) {
-			dev_err(&spi_nand->dev,
-					"error %d reading status register\n",
-					(int) retval);
-			return retval;
-		}
-
-		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-			if ((status & STATUS_E_FAIL_MASK) == STATUS_E_FAIL) {
-				dev_err(&spi_nand->dev,
-					"erase error, block %d\n", block_id);
-				return -1;
-			}
-			break;
-		}
-	}
-	return 0;
-}
-
-#ifdef CONFIG_MTD_SPINAND_ONDIEECC
-static int spinand_write_page_hwecc(struct mtd_info *mtd,
-		struct nand_chip *chip, const uint8_t *buf, int oob_required)
-{
-	const uint8_t *p = buf;
-	int eccsize = chip->ecc.size;
-	int eccsteps = chip->ecc.steps;
-
-	enable_hw_ecc = 1;
-	chip->write_buf(mtd, p, eccsize * eccsteps);
-	return 0;
-}
-
-static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
-		uint8_t *buf, int oob_required, int page)
+static int spinand_init_size(struct mtd_info *mtd, struct nand_chip *chip,
+				u8 *id)
 {
-	u8 retval, status;
-	uint8_t *p = buf;
-	int eccsize = chip->ecc.size;
-	int eccsteps = chip->ecc.steps;
-	struct spinand_info *info = (struct spinand_info *)chip->priv;
+	if (id[0] == 0x2C && id[1] == 0x22) {
+		mtd->erasesize = (2048*64);
+		mtd->writesize = 2048;
+		mtd->oobsize = 64;
 
-	enable_read_hw_ecc = 1;
-
-	chip->read_buf(mtd, p, eccsize * eccsteps);
-	if (oob_required)
-		chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
-
-	while (1) {
-		retval = spinand_read_status(info->spi, &status);
-		if ((status & STATUS_OIP_MASK) == STATUS_READY) {
-			if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
-				pr_info("spinand: ECC error\n");
-				mtd->ecc_stats.failed++;
-			} else if ((status & STATUS_ECC_MASK) ==
-					STATUS_ECC_1BIT_CORRECTED)
-				mtd->ecc_stats.corrected++;
-			break;
-		}
+		chip->bits_per_cell = 1;
 	}
-	return 0;
-
-}
-#endif
-
-static void spinand_select_chip(struct mtd_info *mtd, int dev)
-{
-}
-
-static uint8_t spinand_read_byte(struct mtd_info *mtd)
-{
-	struct spinand_state *state = mtd_to_state(mtd);
-	u8 data;
-
-	data = state->buf[state->buf_ptr];
-	state->buf_ptr++;
-	return data;
-}
-
-
-static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
-{
-	struct spinand_info *info = (struct spinand_info *)chip->priv;
 
-	unsigned long timeo = jiffies;
-	int retval, state = chip->state;
-	u8 status;
-
-	if (state == FL_ERASING)
-		timeo += (HZ * 400) / 1000;
-	else
-		timeo += (HZ * 20) / 1000;
-
-	while (time_before(jiffies, timeo)) {
-		retval = spinand_read_status(info->spi, &status);
-		if ((status & STATUS_OIP_MASK) == STATUS_READY)
-			return 0;
-
-		cond_resched();
-	}
 	return 0;
 }
 
-static void spinand_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
-{
-
-	struct spinand_state *state = mtd_to_state(mtd);
-
-	memcpy(state->buf + state->buf_ptr, buf, len);
-	state->buf_ptr += len;
-}
-
-static void spinand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-{
-	struct spinand_state *state = mtd_to_state(mtd);
-
-	memcpy(buf, state->buf + state->buf_ptr, len);
-	state->buf_ptr += len;
-}
 
 /*
- * spinand_reset- send RESET command "0xff" to the Nand device.
- */
-static void spinand_reset(struct spi_device *spi_nand)
-{
-	struct spinand_cmd cmd = {0};
-
-	cmd.cmd = CMD_RESET;
-
-	if (spinand_cmd(spi_nand, &cmd) < 0)
-		pr_info("spinand reset failed!\n");
-
-	/* elapse 1ms before issuing any other command */
-	udelay(1000);
-
-	if (wait_till_ready(spi_nand))
-		dev_err(&spi_nand->dev, "wait timedout!\n");
-}
-
-static void spinand_cmdfunc(struct mtd_info *mtd, unsigned int command,
-		int column, int page)
-{
-	struct nand_chip *chip = (struct nand_chip *)mtd->priv;
-	struct spinand_info *info = (struct spinand_info *)chip->priv;
-	struct spinand_state *state = (struct spinand_state *)info->priv;
-
-	switch (command) {
-	/*
-	 * READ0 - read in first  0x800 bytes
-	 */
-	case NAND_CMD_READ1:
-	case NAND_CMD_READ0:
-		state->buf_ptr = 0;
-		spinand_read_page(info->spi, page, 0x0, 0x840, state->buf);
-		break;
-	/* READOOB reads only the OOB because no ECC is performed. */
-	case NAND_CMD_READOOB:
-		state->buf_ptr = 0;
-		spinand_read_page(info->spi, page, 0x800, 0x40, state->buf);
-		break;
-	case NAND_CMD_RNDOUT:
-		state->buf_ptr = column;
-		break;
-	case NAND_CMD_READID:
-		state->buf_ptr = 0;
-		spinand_read_id(info->spi, (u8 *)state->buf);
-		break;
-	case NAND_CMD_PARAM:
-		state->buf_ptr = 0;
-		break;
-	/* ERASE1 stores the block and page address */
-	case NAND_CMD_ERASE1:
-		spinand_erase_block(info->spi, page);
-		break;
-	/* ERASE2 uses the block and page address from ERASE1 */
-	case NAND_CMD_ERASE2:
-		break;
-	/* SEQIN sets up the addr buffer and all registers except the length */
-	case NAND_CMD_SEQIN:
-		state->col = column;
-		state->row = page;
-		state->buf_ptr = 0;
-		break;
-	/* PAGEPROG reuses all of the setup from SEQIN and adds the length */
-	case NAND_CMD_PAGEPROG:
-		spinand_program_page(info->spi, state->row, state->col,
-				state->buf_ptr, state->buf);
-		break;
-	case NAND_CMD_STATUS:
-		spinand_get_otp(info->spi, state->buf);
-		if (!(state->buf[0] & 0x80))
-			state->buf[0] = 0x80;
-		state->buf_ptr = 0;
-		break;
-	/* RESET command */
-	case NAND_CMD_RESET:
-		if (wait_till_ready(info->spi))
-			dev_err(&info->spi->dev, "WAIT timedout!!!\n");
-		/* a minimum of 250us must elapse before issuing RESET cmd*/
-		udelay(250);
-		spinand_reset(info->spi);
-		break;
-	default:
-		dev_err(&mtd->dev, "Unknown CMD: 0x%x\n", command);
-	}
-}
-
-/**
- * spinand_lock_block- send write register 0x1f command to the Nand device
- *
- * Description:
- *    After power up, all the Nand blocks are locked.  This function allows
- *    one to unlock the blocks, and so it can be written or erased.
- */
-static int spinand_lock_block(struct spi_device *spi_nand, u8 lock)
-{
-	struct spinand_cmd cmd = {0};
-	int ret;
-	u8 otp = 0;
-
-	ret = spinand_get_otp(spi_nand, &otp);
-
-	cmd.cmd = CMD_WRITE_REG;
-	cmd.n_addr = 1;
-	cmd.addr[0] = REG_BLOCK_LOCK;
-	cmd.n_tx = 1;
-	cmd.tx_buf = &lock;
-
-	ret = spinand_cmd(spi_nand, &cmd);
-	if (ret < 0)
-		dev_err(&spi_nand->dev, "error %d lock block\n", ret);
-
-	return ret;
-}
-/*
  * spinand_probe - [spinand Interface]
  * @spi_nand: registered device driver.
  *
  * Description:
  *   To set up the device driver parameters to make the device available.
  */
-static int spinand_probe(struct spi_device *spi_nand)
+static int mt29f_probe(struct spi_device *spi)
 {
-	struct mtd_info *mtd;
+	struct spi_nand_chip *spi_chip;
 	struct nand_chip *chip;
-	struct spinand_info *info;
-	struct spinand_state *state;
-	struct mtd_part_parser_data ppdata;
-
-	info  = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_info),
-			GFP_KERNEL);
-	if (!info)
-		return -ENOMEM;
-
-	info->spi = spi_nand;
-
-	spinand_lock_block(spi_nand, BL_ALL_UNLOCKED);
 
-	state = devm_kzalloc(&spi_nand->dev, sizeof(struct spinand_state),
-			GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
-
-	info->priv	= state;
-	state->buf_ptr	= 0;
-	state->buf	= devm_kzalloc(&spi_nand->dev, BUFSIZE, GFP_KERNEL);
-	if (!state->buf)
-		return -ENOMEM;
-
-	chip = devm_kzalloc(&spi_nand->dev, sizeof(struct nand_chip),
-			GFP_KERNEL);
-	if (!chip)
-		return -ENOMEM;
+	spi_chip = spinand_alloc_chip(spi);
+	if (IS_ERR(spi_chip))
+		return PTR_ERR(spi_chip);
 
+	chip  = &spi_chip->chip;
 #ifdef CONFIG_MTD_SPINAND_ONDIEECC
-	chip->ecc.mode	= NAND_ECC_HW;
 	chip->ecc.size	= 0x200;
 	chip->ecc.bytes	= 0x6;
 	chip->ecc.steps	= 0x4;
@@ -873,39 +88,12 @@ static int spinand_probe(struct spi_device *spi_nand)
 	chip->ecc.strength = 1;
 	chip->ecc.total	= chip->ecc.steps * chip->ecc.bytes;
 	chip->ecc.layout = &spinand_oob_64;
-	chip->ecc.read_page = spinand_read_page_hwecc;
-	chip->ecc.write_page = spinand_write_page_hwecc;
-#else
-	chip->ecc.mode	= NAND_ECC_SOFT;
-	if (spinand_disable_ecc(spi_nand) < 0)
-		pr_info("%s: disable ecc failed!\n", __func__);
 #endif
+	chip->init_size = spinand_init_size;
+	spinand_set_buffer_size(spi_chip, 10*2048*64, 2048+64);
+	spinand_set_plane_info(spi_chip, 1, 6);
 
-	chip->priv	= info;
-	chip->read_buf	= spinand_read_buf;
-	chip->write_buf	= spinand_write_buf;
-	chip->read_byte	= spinand_read_byte;
-	chip->cmdfunc	= spinand_cmdfunc;
-	chip->waitfunc	= spinand_wait;
-	chip->options	|= NAND_CACHEPRG;
-	chip->select_chip = spinand_select_chip;
-
-	mtd = devm_kzalloc(&spi_nand->dev, sizeof(struct mtd_info), GFP_KERNEL);
-	if (!mtd)
-		return -ENOMEM;
-
-	dev_set_drvdata(&spi_nand->dev, mtd);
-
-	mtd->priv = chip;
-	mtd->name = dev_name(&spi_nand->dev);
-	mtd->owner = THIS_MODULE;
-	mtd->oobsize = 64;
-
-	if (nand_scan(mtd, 1))
-		return -ENXIO;
-
-	ppdata.of_node = spi_nand->dev.of_node;
-	return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+	return spinand_register_chip(spi_chip);
 }
 
 /*
@@ -937,7 +125,7 @@ static struct spi_driver spinand_driver = {
 		.owner		= THIS_MODULE,
 		.of_match_table	= spinand_dt,
 	},
-	.probe		= spinand_probe,
+	.probe		= mt29f_probe,
 	.remove		= spinand_remove,
 };
 
diff --git a/include/linux/mtd/spi-nand.h b/include/linux/mtd/spi-nand.h
new file mode 100644
index 0000000..da1c37a
--- /dev/null
+++ b/include/linux/mtd/spi-nand.h
@@ -0,0 +1,116 @@
+/*-
+ *
+ * Copyright (c) 2009-2014 Micron Technology, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Peter Pan <bpqw@micron.com>
+ *
+ * based on mt29f_spinand.h
+ */
+#ifndef __LINUX_MTD_SPI_NAND_H
+#define __LINUX_MTD_SPI_NAND_H
+
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/mtd/mtd.h>
+
+/* cmd */
+#define SPINAND_CMD_READ			0x13
+#define SPINAND_CMD_READ_RDM			0x03
+#define SPINAND_CMD_PROG_PAGE_CLRCACHE		0x02
+#define SPINAND_CMD_PROG_PAGE			0x84
+#define SPINAND_CMD_PROG_PAGE_EXC		0x10
+#define SPINAND_CMD_ERASE_BLK			0xd8
+#define SPINAND_CMD_WR_ENABLE			0x06
+#define SPINAND_CMD_WR_DISABLE			0x04
+#define SPINAND_CMD_READ_ID			0x9f
+#define SPINAND_CMD_RESET			0xff
+#define SPINAND_CMD_READ_REG			0x0f
+#define SPINAND_CMD_WRITE_REG			0x1f
+
+/* feature/ status reg */
+#define REG_BLOCK_LOCK			0xa0
+#define REG_OTP				0xb0
+#define REG_STATUS			0xc0/* timing */
+
+/* status */
+#define STATUS_OIP_MASK			0x01
+#define STATUS_READY			(0 << 0)
+#define STATUS_BUSY			(1 << 0)
+
+#define STATUS_E_FAIL_MASK		0x04
+#define STATUS_E_FAIL			(1 << 2)
+
+#define STATUS_P_FAIL_MASK		0x08
+#define STATUS_P_FAIL			(1 << 3)
+
+#define STATUS_ECC_MASK			0x30
+#define STATUS_ECC_1BIT_CORRECTED	(1 << 4)
+#define STATUS_ECC_ERROR		(2 << 4)
+#define STATUS_ECC_RESERVED		(3 << 4)
+
+/*ECC enable defines*/
+#define OTP_ECC_MASK			0x10
+#define OTP_ECC_OFF			0
+#define OTP_ECC_ON			1
+
+#define ECC_DISABLED
+#define ECC_IN_NAND
+#define ECC_SOFT
+
+/* block lock */
+#define BL_ALL_LOCKED      0x38
+#define BL_1_2_LOCKED      0x30
+#define BL_1_4_LOCKED      0x28
+#define BL_1_8_LOCKED      0x20
+#define BL_1_16_LOCKED     0x18
+#define BL_1_32_LOCKED     0x10
+#define BL_1_64_LOCKED     0x08
+#define BL_ALL_UNLOCKED    0
+
+struct spi_nand_chip {
+	struct nand_chip chip;
+	struct spi_device *spi;
+	u8		*buf;
+	u32		buf_size;
+	int		buf_ptr;
+	uint32_t	col;
+	uint32_t	row;
+	u32		cache_size;
+	u16		plane_sel;
+	u16		plane_bit;
+#ifdef CONFIG_MTD_SPINAND_ONDIEECC
+	u32		enable_hw_ecc;
+	u32		enable_read_hw_ecc;
+	u8		*ecc_buf;
+	struct nand_ecclayout *ecclayout;
+#endif
+};
+
+struct spinand_cmd {
+	u8		cmd;
+	u32		n_addr;		/* Number of address */
+	u8		addr[3];	/* Reg Offset */
+	u32		n_dummy;	/* Dummy use */
+	u32		n_tx;		/* Number of tx bytes */
+	u8		*tx_buf;	/* Tx buf */
+	u32		n_rx;		/* Number of rx bytes */
+	u8		*rx_buf;	/* Rx buf */
+};
+
+struct spi_nand_chip *spinand_alloc_chip(struct spi_device *spi);
+int spinand_register_chip(struct spi_nand_chip *spi_chip);
+int spinand_set_buffer_size(struct spi_nand_chip *spi_chip, u32 buf_size,
+				u32 cache_size);
+int spinand_set_plane_info(struct spi_nand_chip *spi_chip, u16 plane_sel,
+				u16 plane_bit);
+
+#endif /* __LINUX_MTD_SPI_NAND_H */
-- 
1.9.1

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash
  2014-11-25  7:02   ` bpqw
@ 2014-11-25 16:59     ` Ezequiel Garcia
  0 siblings, 0 replies; 16+ messages in thread
From: Ezequiel Garcia @ 2014-11-25 16:59 UTC (permalink / raw)
  To: bpqw, Brian Norris, arnaud.mouiche@invoxia.com,
	linux-mtd@lists.infradead.org
  Cc: ionela.voinescu@imgtec.com



On 11/25/2014 04:02 AM, bpqw wrote:
>> Yeah, I've been thinking about this for some time. Right now, I think that
>> SPI NAND is just that: a NAND over SPI, so I'm doing some experiments
>> around this design:
>>
>>    Userspace
>>  ------------------
>>    MTD
>>  ------------------
>>    NAND core
>>  ------------------
>>    SPI NAND core
>>  ------------------
>>    SPI NAND device
>>  ------------------
>>    SPI core
>>  ------------------
>>    SPI master
>>  ------------------
>>    Hardware
> 
> I have finished a initial version of SPI-NAND framework based on drivers/staging/
> mt29f_spinand/mt29f_spinand.c . The structure is the same as yours, just treate SPI
> NAND as a NAND over SPI, put SPI NAND core under NAND core. Do you think it is a
> good structure to start with? Because it is a quick product, I even do not finish
> the unregisger function. So just care about the structure. Any suggestion about the
> patch is welcomed.
> 

Hm.. interesting. Ionela and I have started a similar work. However,
we've splitted the code in two: spi-nand-base.c and spi-nand-device.c.
The former handles the NAND logic, and the latter implements the
specific SPI commands.

The idea behind this separation is to allow for better evolution of the
code, given we are not sure the direction the SPI NAND devices will take.

I'm not sure how to handle a parallel effort like this and I don't want
to stop you from working. I'll have some code submitted by this week.

Maybe we can discuss it as well?
-- 
Ezequiel

^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2014-11-25 17:01 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <mailman.22397.1416508326.22890.linux-mtd@lists.infradead.org>
2014-11-21  1:16 ` [PATCH 0/2] staging: mtd: Support for GigaDevice SPI NAND flash Qi Wang 王起 (qiwang)
2014-11-21  9:24   ` arnaud.mouiche
2014-11-21 11:51   ` Ezequiel Garcia
2014-11-20  8:39 bpqw
2014-11-20 13:18 ` Ezequiel Garcia
2014-11-25  7:02   ` bpqw
2014-11-25 16:59     ` Ezequiel Garcia
  -- strict thread matches above, loose matches on Subject: below --
2014-11-06 15:51 Ionela Voinescu
2014-11-06 16:05 ` Greg KH
2014-11-06 17:32   ` Ionela Voinescu
2014-11-06 17:44     ` Greg KH
2014-11-06 18:03       ` Ionela Voinescu
2014-11-06 18:17         ` Ezequiel Garcia
2014-11-06 19:20           ` Brian Norris
2014-11-07 13:00             ` Ionela Voinescu
2014-11-10  9:00             ` arnaud.mouiche

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).