2018-11-11 08:55:09 +01:00
// SPDX-License-Identifier: GPL-2.0
2006-05-21 18:11:55 +01:00
/*
* Copyright ( C ) 2006 Jonathan McDowell < noodles @ earth . li >
*
2018-02-05 23:02:02 +01:00
* Derived from drivers / mtd / nand / toto . c ( removed in v2 .6 .28 )
2018-02-05 23:02:03 +01:00
* Copyright ( c ) 2003 Texas Instruments
* Copyright ( c ) 2002 Thomas Gleixner < tgxl @ linutronix . de >
*
2010-12-14 21:09:40 +01:00
* Converted to platform driver by Janusz Krzysztofik < jkrzyszt @ tis . icnet . pl >
2018-02-05 23:02:00 +01:00
* Partially stolen from plat_nand . c
2006-05-21 18:11:55 +01:00
*
* Overview :
* This is a device driver for the NAND flash device found on the
* Amstrad E3 ( Delta ) .
*/
# include <linux/slab.h>
# include <linux/module.h>
# include <linux/delay.h>
2018-09-20 00:17:29 +02:00
# include <linux/gpio/consumer.h>
2006-05-21 18:11:55 +01:00
# include <linux/mtd/mtd.h>
2020-02-12 01:39:17 +01:00
# include <linux/mtd/nand-gpio.h>
2017-08-04 17:29:10 +02:00
# include <linux/mtd/rawnand.h>
2006-05-21 18:11:55 +01:00
# include <linux/mtd/partitions.h>
2020-02-12 01:39:26 +01:00
# include <linux/of_device.h>
2018-11-21 12:08:05 +01:00
# include <linux/platform_device.h>
2018-11-11 08:55:08 +01:00
# include <linux/sizes.h>
2006-05-21 18:11:55 +01:00
/*
* MTD structure for E3 ( Delta )
*/
2020-02-12 01:39:29 +01:00
struct gpio_nand {
2018-11-11 08:55:13 +01:00
struct nand_controller base ;
2018-09-20 00:52:54 +02:00
struct nand_chip nand_chip ;
struct gpio_desc * gpiod_rdy ;
struct gpio_desc * gpiod_nce ;
struct gpio_desc * gpiod_nre ;
struct gpio_desc * gpiod_nwp ;
struct gpio_desc * gpiod_nwe ;
struct gpio_desc * gpiod_ale ;
struct gpio_desc * gpiod_cle ;
2018-11-21 12:08:05 +01:00
struct gpio_descs * data_gpiods ;
2018-09-20 00:52:55 +02:00
bool data_in ;
2020-02-12 01:39:22 +01:00
unsigned int tRP ;
unsigned int tWP ;
2020-02-12 01:39:29 +01:00
u8 ( * io_read ) ( struct gpio_nand * this ) ;
void ( * io_write ) ( struct gpio_nand * this , u8 byte ) ;
2018-09-20 00:52:54 +02:00
} ;
2006-05-21 18:11:55 +01:00
2020-02-12 01:39:29 +01:00
static void gpio_nand_write_commit ( struct gpio_nand * priv )
2006-05-21 18:11:55 +01:00
{
2018-09-20 00:52:54 +02:00
gpiod_set_value ( priv - > gpiod_nwe , 1 ) ;
2020-02-12 01:39:22 +01:00
ndelay ( priv - > tWP ) ;
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nwe , 0 ) ;
2006-05-21 18:11:55 +01:00
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_io_write ( struct gpio_nand * priv , u8 byte )
2018-11-21 12:08:05 +01:00
{
struct gpio_descs * data_gpiods = priv - > data_gpiods ;
DECLARE_BITMAP ( values , BITS_PER_TYPE ( byte ) ) = { byte , } ;
gpiod_set_raw_array_value ( data_gpiods - > ndescs , data_gpiods - > desc ,
data_gpiods - > info , values ) ;
2020-02-12 01:39:29 +01:00
gpio_nand_write_commit ( priv ) ;
2018-11-21 12:08:05 +01:00
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_dir_output ( struct gpio_nand * priv , u8 byte )
2018-11-21 12:08:05 +01:00
{
struct gpio_descs * data_gpiods = priv - > data_gpiods ;
DECLARE_BITMAP ( values , BITS_PER_TYPE ( byte ) ) = { byte , } ;
int i ;
for ( i = 0 ; i < data_gpiods - > ndescs ; i + + )
gpiod_direction_output_raw ( data_gpiods - > desc [ i ] ,
test_bit ( i , values ) ) ;
2020-02-12 01:39:29 +01:00
gpio_nand_write_commit ( priv ) ;
2018-11-21 12:08:05 +01:00
priv - > data_in = false ;
}
2020-02-12 01:39:29 +01:00
static u8 gpio_nand_io_read ( struct gpio_nand * priv )
2006-05-21 18:11:55 +01:00
{
2018-11-11 08:55:10 +01:00
u8 res ;
2018-11-21 12:08:05 +01:00
struct gpio_descs * data_gpiods = priv - > data_gpiods ;
DECLARE_BITMAP ( values , BITS_PER_TYPE ( res ) ) = { 0 , } ;
2006-05-21 18:11:55 +01:00
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nre , 1 ) ;
2020-02-12 01:39:22 +01:00
ndelay ( priv - > tRP ) ;
2018-11-21 12:08:05 +01:00
gpiod_get_raw_array_value ( data_gpiods - > ndescs , data_gpiods - > desc ,
data_gpiods - > info , values ) ;
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nre , 0 ) ;
2006-05-21 18:11:55 +01:00
2018-11-21 12:08:05 +01:00
res = values [ 0 ] ;
2006-05-21 18:11:55 +01:00
return res ;
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_dir_input ( struct gpio_nand * priv )
2018-09-20 00:52:55 +02:00
{
2018-11-21 12:08:05 +01:00
struct gpio_descs * data_gpiods = priv - > data_gpiods ;
int i ;
for ( i = 0 ; i < data_gpiods - > ndescs ; i + + )
gpiod_direction_input ( data_gpiods - > desc [ i ] ) ;
priv - > data_in = true ;
2018-09-20 00:52:55 +02:00
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_write_buf ( struct gpio_nand * priv , const u8 * buf , int len )
2006-05-21 18:11:55 +01:00
{
2018-11-21 12:08:05 +01:00
int i = 0 ;
2006-05-21 18:11:55 +01:00
2018-11-21 12:08:05 +01:00
if ( len > 0 & & priv - > data_in )
2020-02-12 01:39:29 +01:00
gpio_nand_dir_output ( priv , buf [ i + + ] ) ;
2018-09-20 00:52:55 +02:00
2018-11-21 12:08:05 +01:00
while ( i < len )
2020-02-12 01:39:28 +01:00
priv - > io_write ( priv , buf [ i + + ] ) ;
2006-05-21 18:11:55 +01:00
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_read_buf ( struct gpio_nand * priv , u8 * buf , int len )
2006-05-21 18:11:55 +01:00
{
int i ;
2020-02-12 01:39:28 +01:00
if ( priv - > data_gpiods & & ! priv - > data_in )
2020-02-12 01:39:29 +01:00
gpio_nand_dir_input ( priv ) ;
2018-09-20 00:52:55 +02:00
for ( i = 0 ; i < len ; i + + )
2020-02-12 01:39:28 +01:00
buf [ i ] = priv - > io_read ( priv ) ;
2018-09-20 00:52:55 +02:00
}
2020-02-12 01:39:29 +01:00
static void gpio_nand_ctrl_cs ( struct gpio_nand * priv , bool assert )
2006-05-23 23:25:53 +02:00
{
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nce , assert ) ;
2006-05-23 23:25:53 +02:00
}
2020-02-12 01:39:29 +01:00
static int gpio_nand_exec_op ( struct nand_chip * this ,
2018-10-15 21:41:30 +02:00
const struct nand_operation * op , bool check_only )
2006-05-21 18:11:55 +01:00
{
2020-02-12 01:39:29 +01:00
struct gpio_nand * priv = nand_get_controller_data ( this ) ;
2018-10-15 21:41:30 +02:00
const struct nand_op_instr * instr ;
int ret = 0 ;
if ( check_only )
return 0 ;
2020-02-12 01:39:29 +01:00
gpio_nand_ctrl_cs ( priv , 1 ) ;
2018-11-11 08:55:21 +01:00
2018-10-15 21:41:30 +02:00
for ( instr = op - > instrs ; instr < op - > instrs + op - > ninstrs ; instr + + ) {
switch ( instr - > type ) {
case NAND_OP_CMD_INSTR :
gpiod_set_value ( priv - > gpiod_cle , 1 ) ;
2020-02-12 01:39:29 +01:00
gpio_nand_write_buf ( priv , & instr - > ctx . cmd . opcode , 1 ) ;
2018-10-15 21:41:30 +02:00
gpiod_set_value ( priv - > gpiod_cle , 0 ) ;
break ;
case NAND_OP_ADDR_INSTR :
gpiod_set_value ( priv - > gpiod_ale , 1 ) ;
2020-02-12 01:39:29 +01:00
gpio_nand_write_buf ( priv , instr - > ctx . addr . addrs ,
2018-10-15 21:41:30 +02:00
instr - > ctx . addr . naddrs ) ;
gpiod_set_value ( priv - > gpiod_ale , 0 ) ;
break ;
case NAND_OP_DATA_IN_INSTR :
2020-02-12 01:39:29 +01:00
gpio_nand_read_buf ( priv , instr - > ctx . data . buf . in ,
2018-10-15 21:41:30 +02:00
instr - > ctx . data . len ) ;
break ;
case NAND_OP_DATA_OUT_INSTR :
2020-02-12 01:39:29 +01:00
gpio_nand_write_buf ( priv , instr - > ctx . data . buf . out ,
2018-10-15 21:41:30 +02:00
instr - > ctx . data . len ) ;
break ;
case NAND_OP_WAITRDY_INSTR :
ret = priv - > gpiod_rdy ?
nand_gpio_waitrdy ( this , priv - > gpiod_rdy ,
instr - > ctx . waitrdy . timeout_ms ) :
nand_soft_waitrdy ( this ,
instr - > ctx . waitrdy . timeout_ms ) ;
break ;
}
if ( ret )
break ;
}
2018-09-20 00:52:54 +02:00
2020-02-12 01:39:29 +01:00
gpio_nand_ctrl_cs ( priv , 0 ) ;
2018-11-11 08:55:21 +01:00
2018-10-15 21:41:30 +02:00
return ret ;
2006-05-21 18:11:55 +01:00
}
2020-05-29 13:13:13 +02:00
static int gpio_nand_setup_interface ( struct nand_chip * this , int csline ,
const struct nand_interface_config * cf )
2020-02-12 01:39:22 +01:00
{
2020-02-12 01:39:29 +01:00
struct gpio_nand * priv = nand_get_controller_data ( this ) ;
2020-02-12 01:39:22 +01:00
const struct nand_sdr_timings * sdr = nand_get_sdr_timings ( cf ) ;
struct device * dev = & nand_to_mtd ( this ) - > dev ;
if ( IS_ERR ( sdr ) )
return PTR_ERR ( sdr ) ;
if ( csline = = NAND_DATA_IFACE_CHECK_ONLY )
return 0 ;
2020-02-12 01:39:23 +01:00
if ( priv - > gpiod_nre ) {
priv - > tRP = DIV_ROUND_UP ( sdr - > tRP_min , 1000 ) ;
dev_dbg ( dev , " using %u ns read pulse width \n " , priv - > tRP ) ;
}
2020-02-12 01:39:22 +01:00
priv - > tWP = DIV_ROUND_UP ( sdr - > tWP_min , 1000 ) ;
dev_dbg ( dev , " using %u ns write pulse width \n " , priv - > tWP ) ;
return 0 ;
}
2020-11-13 13:34:08 +01:00
static int gpio_nand_attach_chip ( struct nand_chip * chip )
{
2021-09-29 00:22:40 +02:00
if ( chip - > ecc . engine_type = = NAND_ECC_ENGINE_TYPE_SOFT & &
chip - > ecc . algo = = NAND_ECC_ALGO_UNKNOWN )
2020-12-03 20:03:32 +01:00
chip - > ecc . algo = NAND_ECC_ALGO_HAMMING ;
2020-11-13 13:34:08 +01:00
return 0 ;
}
2020-02-12 01:39:29 +01:00
static const struct nand_controller_ops gpio_nand_ops = {
. exec_op = gpio_nand_exec_op ,
2020-11-13 13:34:08 +01:00
. attach_chip = gpio_nand_attach_chip ,
2020-05-29 13:13:13 +02:00
. setup_interface = gpio_nand_setup_interface ,
2018-11-11 08:55:23 +01:00
} ;
2006-05-21 18:11:55 +01:00
/*
* Main initialization routine
*/
2020-02-12 01:39:29 +01:00
static int gpio_nand_probe ( struct platform_device * pdev )
2006-05-21 18:11:55 +01:00
{
2020-02-12 01:39:17 +01:00
struct gpio_nand_platdata * pdata = dev_get_platdata ( & pdev - > dev ) ;
2020-02-12 01:39:19 +01:00
const struct mtd_partition * partitions = NULL ;
int num_partitions = 0 ;
2020-02-12 01:39:29 +01:00
struct gpio_nand * priv ;
2006-05-21 18:11:55 +01:00
struct nand_chip * this ;
2018-09-20 00:52:54 +02:00
struct mtd_info * mtd ;
2020-02-12 01:39:29 +01:00
int ( * probe ) ( struct platform_device * pdev , struct gpio_nand * priv ) ;
2006-05-21 18:11:55 +01:00
int err = 0 ;
2020-02-12 01:39:17 +01:00
if ( pdata ) {
partitions = pdata - > parts ;
num_partitions = pdata - > num_parts ;
}
2006-05-21 18:11:55 +01:00
/* Allocate memory for MTD device structure and private data */
2020-02-12 01:39:29 +01:00
priv = devm_kzalloc ( & pdev - > dev , sizeof ( struct gpio_nand ) ,
2018-09-20 00:52:54 +02:00
GFP_KERNEL ) ;
2018-11-11 08:55:10 +01:00
if ( ! priv )
2018-09-20 00:52:54 +02:00
return - ENOMEM ;
2018-11-11 08:55:10 +01:00
2018-09-20 00:52:54 +02:00
this = & priv - > nand_chip ;
2006-05-21 18:11:55 +01:00
2018-09-20 00:52:54 +02:00
mtd = nand_to_mtd ( this ) ;
mtd - > dev . parent = & pdev - > dev ;
2006-05-21 18:11:55 +01:00
2018-09-20 00:52:54 +02:00
nand_set_controller_data ( this , priv ) ;
2020-02-12 01:39:20 +01:00
nand_set_flash_node ( this , pdev - > dev . of_node ) ;
2010-12-15 15:43:44 +01:00
2018-09-20 00:52:54 +02:00
priv - > gpiod_rdy = devm_gpiod_get_optional ( & pdev - > dev , " rdy " , GPIOD_IN ) ;
if ( IS_ERR ( priv - > gpiod_rdy ) ) {
err = PTR_ERR ( priv - > gpiod_rdy ) ;
2018-09-20 00:17:29 +02:00
dev_warn ( & pdev - > dev , " RDY GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2006-05-21 18:11:55 +01:00
}
2018-09-20 00:17:29 +02:00
2018-09-20 00:52:54 +02:00
platform_set_drvdata ( pdev , priv ) ;
2010-12-15 15:43:44 +01:00
2020-02-12 01:39:16 +01:00
/* Set chip enabled but write protected */
2020-02-12 01:39:24 +01:00
priv - > gpiod_nwp = devm_gpiod_get_optional ( & pdev - > dev , " nwp " ,
GPIOD_OUT_HIGH ) ;
2018-09-20 00:52:54 +02:00
if ( IS_ERR ( priv - > gpiod_nwp ) ) {
err = PTR_ERR ( priv - > gpiod_nwp ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " NWP GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2020-02-12 01:39:24 +01:00
priv - > gpiod_nce = devm_gpiod_get_optional ( & pdev - > dev , " nce " ,
GPIOD_OUT_LOW ) ;
2018-09-20 00:52:54 +02:00
if ( IS_ERR ( priv - > gpiod_nce ) ) {
err = PTR_ERR ( priv - > gpiod_nce ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " NCE GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2020-02-12 01:39:23 +01:00
priv - > gpiod_nre = devm_gpiod_get_optional ( & pdev - > dev , " nre " ,
GPIOD_OUT_LOW ) ;
2018-09-20 00:52:54 +02:00
if ( IS_ERR ( priv - > gpiod_nre ) ) {
err = PTR_ERR ( priv - > gpiod_nre ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " NRE GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2020-02-12 01:39:28 +01:00
priv - > gpiod_nwe = devm_gpiod_get_optional ( & pdev - > dev , " nwe " ,
GPIOD_OUT_LOW ) ;
2018-09-20 00:52:54 +02:00
if ( IS_ERR ( priv - > gpiod_nwe ) ) {
err = PTR_ERR ( priv - > gpiod_nwe ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " NWE GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2018-09-20 00:52:54 +02:00
priv - > gpiod_ale = devm_gpiod_get ( & pdev - > dev , " ale " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( priv - > gpiod_ale ) ) {
err = PTR_ERR ( priv - > gpiod_ale ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " ALE GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2018-09-20 00:52:54 +02:00
priv - > gpiod_cle = devm_gpiod_get ( & pdev - > dev , " cle " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( priv - > gpiod_cle ) ) {
err = PTR_ERR ( priv - > gpiod_cle ) ;
2018-09-20 00:17:29 +02:00
dev_err ( & pdev - > dev , " CLE GPIO request failed (%d) \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-09-20 00:17:29 +02:00
}
2006-05-21 18:11:55 +01:00
2018-11-21 12:08:04 +01:00
/* Request array of data pins, initialize them as input */
2020-02-12 01:39:28 +01:00
priv - > data_gpiods = devm_gpiod_get_array_optional ( & pdev - > dev , " data " ,
GPIOD_IN ) ;
2020-02-12 01:39:27 +01:00
if ( IS_ERR ( priv - > data_gpiods ) ) {
err = PTR_ERR ( priv - > data_gpiods ) ;
2018-11-21 12:08:04 +01:00
dev_err ( & pdev - > dev , " data GPIO request failed: %d \n " , err ) ;
2018-11-21 12:08:05 +01:00
return err ;
2018-11-21 12:08:04 +01:00
}
2020-02-12 01:39:28 +01:00
if ( priv - > data_gpiods ) {
if ( ! priv - > gpiod_nwe ) {
dev_err ( & pdev - > dev ,
" mandatory NWE pin not provided by platform \n " ) ;
return - ENODEV ;
}
2020-02-12 01:39:29 +01:00
priv - > io_read = gpio_nand_io_read ;
priv - > io_write = gpio_nand_io_write ;
2020-02-12 01:39:28 +01:00
priv - > data_in = true ;
}
2018-09-20 00:52:55 +02:00
2020-02-12 01:39:26 +01:00
if ( pdev - > id_entry )
probe = ( void * ) pdev - > id_entry - > driver_data ;
else
probe = of_device_get_match_data ( & pdev - > dev ) ;
if ( probe )
err = probe ( pdev , priv ) ;
if ( err )
return err ;
2020-02-12 01:39:28 +01:00
if ( ! priv - > io_read | | ! priv - > io_write ) {
dev_err ( & pdev - > dev , " incomplete device configuration \n " ) ;
return - ENODEV ;
}
2020-02-12 01:39:29 +01:00
/* Initialize the NAND controller object embedded in gpio_nand. */
priv - > base . ops = & gpio_nand_ops ;
2018-11-11 08:55:13 +01:00
nand_controller_init ( & priv - > base ) ;
this - > controller = & priv - > base ;
2020-02-12 01:39:16 +01:00
/*
* FIXME : We should release write protection only after nand_scan ( ) to
* be on the safe side but we can ' t do that until we have a generic way
* to assert / deassert WP from the core . Even if the core shouldn ' t
* write things in the nand_scan ( ) path , it should have control on this
* pin just in case we ever need to disable write protection during
* chip detection / initialization .
*/
/* Release write protection */
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nwp , 0 ) ;
2020-02-12 01:39:16 +01:00
2021-09-29 00:22:40 +02:00
/*
* This driver assumes that the default ECC engine should be TYPE_SOFT .
* Set - > engine_type before registering the NAND devices in order to
* provide a driver specific default value .
*/
this - > ecc . engine_type = NAND_ECC_ENGINE_TYPE_SOFT ;
2011-03-30 22:57:33 -03:00
/* Scan to find existence of the device */
2018-09-06 14:05:14 +02:00
err = nand_scan ( this , 1 ) ;
2016-11-04 19:42:49 +09:00
if ( err )
2018-11-21 12:08:05 +01:00
return err ;
2006-05-21 18:11:55 +01:00
/* Register the partitions */
2020-02-12 01:39:17 +01:00
err = mtd_device_register ( mtd , partitions , num_partitions ) ;
2018-11-11 08:55:12 +01:00
if ( err )
goto err_nand_cleanup ;
2006-05-21 18:11:55 +01:00
2018-11-11 08:55:11 +01:00
return 0 ;
2006-05-21 18:11:55 +01:00
2018-11-11 08:55:12 +01:00
err_nand_cleanup :
nand_cleanup ( this ) ;
2006-05-21 18:11:55 +01:00
return err ;
}
/*
* Clean up routine
*/
2020-02-12 01:39:29 +01:00
static int gpio_nand_remove ( struct platform_device * pdev )
2006-05-21 18:11:55 +01:00
{
2020-02-12 01:39:29 +01:00
struct gpio_nand * priv = platform_get_drvdata ( pdev ) ;
2018-09-20 00:52:54 +02:00
struct mtd_info * mtd = nand_to_mtd ( & priv - > nand_chip ) ;
2020-05-19 14:59:34 +02:00
int ret ;
2010-12-15 15:43:44 +01:00
2020-02-12 01:39:16 +01:00
/* Apply write protection */
2020-02-12 01:39:21 +01:00
gpiod_set_value ( priv - > gpiod_nwp , 1 ) ;
2020-02-12 01:39:16 +01:00
2018-11-21 12:08:05 +01:00
/* Unregister device */
2020-05-19 14:59:34 +02:00
ret = mtd_device_unregister ( mtd ) ;
WARN_ON ( ret ) ;
nand_cleanup ( mtd_to_nand ( mtd ) ) ;
2006-05-21 18:11:55 +01:00
2010-12-14 21:09:40 +01:00
return 0 ;
}
2020-09-19 10:04:03 +02:00
# ifdef CONFIG_OF
2020-02-12 01:39:25 +01:00
static const struct of_device_id gpio_nand_of_id_table [ ] = {
{
/* sentinel */
} ,
} ;
MODULE_DEVICE_TABLE ( of , gpio_nand_of_id_table ) ;
2020-09-19 10:04:03 +02:00
# endif
2020-02-12 01:39:25 +01:00
static const struct platform_device_id gpio_nand_plat_id_table [ ] = {
{
. name = " ams-delta-nand " ,
} , {
/* sentinel */
} ,
} ;
MODULE_DEVICE_TABLE ( platform , gpio_nand_plat_id_table ) ;
2020-02-12 01:39:29 +01:00
static struct platform_driver gpio_nand_driver = {
. probe = gpio_nand_probe ,
. remove = gpio_nand_remove ,
2020-02-12 01:39:25 +01:00
. id_table = gpio_nand_plat_id_table ,
2010-12-14 21:09:40 +01:00
. driver = {
. name = " ams-delta-nand " ,
2020-02-12 01:39:25 +01:00
. of_match_table = of_match_ptr ( gpio_nand_of_id_table ) ,
2010-12-14 21:09:40 +01:00
} ,
} ;
2020-02-12 01:39:29 +01:00
module_platform_driver ( gpio_nand_driver ) ;
2006-05-21 18:11:55 +01:00
2018-11-11 08:55:09 +01:00
MODULE_LICENSE ( " GPL v2 " ) ;
2006-05-21 18:11:55 +01:00
MODULE_AUTHOR ( " Jonathan McDowell <noodles@earth.li> " ) ;
MODULE_DESCRIPTION ( " Glue layer for NAND flash on Amstrad E3 (Delta) " ) ;