2019-06-04 10:11:33 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2011-07-25 17:13:27 -07:00
/*
* Driver for 93 xx46 EEPROMs
*
* ( C ) 2011 DENX Software Engineering , Anatolij Gustschin < agust @ denx . de >
*/
# include <linux/delay.h>
# include <linux/device.h>
2016-02-10 14:32:08 -05:00
# include <linux/gpio/consumer.h>
2011-07-25 17:13:27 -07:00
# include <linux/kernel.h>
2021-05-11 23:07:24 +02:00
# include <linux/log2.h>
2011-07-25 17:13:27 -07:00
# include <linux/module.h>
# include <linux/mutex.h>
2016-01-06 22:55:02 -05:00
# include <linux/of.h>
# include <linux/of_device.h>
2016-02-10 14:32:08 -05:00
# include <linux/of_gpio.h>
2011-07-25 17:13:27 -07:00
# include <linux/slab.h>
# include <linux/spi/spi.h>
2016-02-26 20:59:23 +01:00
# include <linux/nvmem-provider.h>
2011-07-25 17:13:27 -07:00
# include <linux/eeprom_93xx46.h>
# define OP_START 0x4
# define OP_WRITE (OP_START | 0x1)
# define OP_READ (OP_START | 0x2)
# define ADDR_EWDS 0x00
# define ADDR_ERAL 0x20
# define ADDR_EWEN 0x30
2016-02-10 14:32:07 -05:00
struct eeprom_93xx46_devtype_data {
unsigned int quirks ;
2021-05-11 23:07:25 +02:00
unsigned char flags ;
} ;
static const struct eeprom_93xx46_devtype_data at93c46_data = {
. flags = EE_SIZE1K ,
} ;
static const struct eeprom_93xx46_devtype_data at93c56_data = {
. flags = EE_SIZE2K ,
} ;
static const struct eeprom_93xx46_devtype_data at93c66_data = {
. flags = EE_SIZE4K ,
2016-02-10 14:32:07 -05:00
} ;
static const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
2021-05-11 23:07:25 +02:00
. flags = EE_SIZE1K ,
2016-02-10 14:32:07 -05:00
. quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH ,
} ;
2021-01-05 16:28:12 +05:30
static const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
2021-05-11 23:07:25 +02:00
. flags = EE_SIZE1K ,
2021-01-05 16:28:12 +05:30
. quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE ,
} ;
2011-07-25 17:13:27 -07:00
struct eeprom_93xx46_dev {
struct spi_device * spi ;
struct eeprom_93xx46_platform_data * pdata ;
struct mutex lock ;
2016-02-26 20:59:23 +01:00
struct nvmem_config nvmem_config ;
struct nvmem_device * nvmem ;
2011-07-25 17:13:27 -07:00
int addrlen ;
2016-02-26 20:59:23 +01:00
int size ;
2011-07-25 17:13:27 -07:00
} ;
2016-02-10 14:32:07 -05:00
static inline bool has_quirk_single_word_read ( struct eeprom_93xx46_dev * edev )
{
return edev - > pdata - > quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ ;
}
static inline bool has_quirk_instruction_length ( struct eeprom_93xx46_dev * edev )
{
return edev - > pdata - > quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH ;
}
2021-01-05 16:28:12 +05:30
static inline bool has_quirk_extra_read_cycle ( struct eeprom_93xx46_dev * edev )
{
return edev - > pdata - > quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE ;
}
2016-04-24 20:28:16 +01:00
static int eeprom_93xx46_read ( void * priv , unsigned int off ,
void * val , size_t count )
2011-07-25 17:13:27 -07:00
{
2016-04-24 20:28:16 +01:00
struct eeprom_93xx46_dev * edev = priv ;
char * buf = val ;
int err = 0 ;
2021-05-11 23:07:24 +02:00
int bits ;
2011-07-25 17:13:27 -07:00
2016-02-26 20:59:23 +01:00
if ( unlikely ( off > = edev - > size ) )
return 0 ;
if ( ( off + count ) > edev - > size )
count = edev - > size - off ;
if ( unlikely ( ! count ) )
return count ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
mutex_lock ( & edev - > lock ) ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
if ( edev - > pdata - > prepare )
edev - > pdata - > prepare ( edev ) ;
2011-07-25 17:13:27 -07:00
2021-05-11 23:07:24 +02:00
/* The opcode in front of the address is three bits. */
bits = edev - > addrlen + 3 ;
2016-02-10 14:32:07 -05:00
while ( count ) {
struct spi_message m ;
struct spi_transfer t [ 2 ] = { { 0 } } ;
u16 cmd_addr = OP_READ < < edev - > addrlen ;
size_t nbytes = count ;
2021-05-11 23:07:24 +02:00
if ( edev - > pdata - > flags & EE_ADDR8 ) {
cmd_addr | = off ;
2016-02-10 14:32:07 -05:00
if ( has_quirk_single_word_read ( edev ) )
nbytes = 1 ;
} else {
2021-05-11 23:07:24 +02:00
cmd_addr | = ( off > > 1 ) ;
2016-02-10 14:32:07 -05:00
if ( has_quirk_single_word_read ( edev ) )
nbytes = 2 ;
}
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
dev_dbg ( & edev - > spi - > dev , " read cmd 0x%x, %d Hz \n " ,
cmd_addr , edev - > spi - > max_speed_hz ) ;
2011-07-25 17:13:27 -07:00
2021-01-05 16:28:12 +05:30
if ( has_quirk_extra_read_cycle ( edev ) ) {
cmd_addr < < = 1 ;
bits + = 1 ;
}
2016-02-10 14:32:07 -05:00
spi_message_init ( & m ) ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
t [ 0 ] . tx_buf = ( char * ) & cmd_addr ;
t [ 0 ] . len = 2 ;
t [ 0 ] . bits_per_word = bits ;
spi_message_add_tail ( & t [ 0 ] , & m ) ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
t [ 1 ] . rx_buf = buf ;
t [ 1 ] . len = count ;
t [ 1 ] . bits_per_word = 8 ;
spi_message_add_tail ( & t [ 1 ] , & m ) ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
err = spi_sync ( edev - > spi , & m ) ;
/* have to wait at least Tcsl ns */
ndelay ( 250 ) ;
2011-07-25 17:13:27 -07:00
2016-02-10 14:32:07 -05:00
if ( err ) {
dev_err ( & edev - > spi - > dev , " read %zu bytes at %d: err. %d \n " ,
nbytes , ( int ) off , err ) ;
break ;
}
buf + = nbytes ;
off + = nbytes ;
count - = nbytes ;
2011-07-25 17:13:27 -07:00
}
if ( edev - > pdata - > finish )
edev - > pdata - > finish ( edev ) ;
mutex_unlock ( & edev - > lock ) ;
2016-04-24 20:28:16 +01:00
return err ;
2011-07-25 17:13:27 -07:00
}
static int eeprom_93xx46_ew ( struct eeprom_93xx46_dev * edev , int is_on )
{
struct spi_message m ;
struct spi_transfer t ;
int bits , ret ;
u16 cmd_addr ;
2021-05-11 23:07:24 +02:00
/* The opcode in front of the address is three bits. */
bits = edev - > addrlen + 3 ;
2011-07-25 17:13:27 -07:00
cmd_addr = OP_START < < edev - > addrlen ;
2021-05-11 23:07:24 +02:00
if ( edev - > pdata - > flags & EE_ADDR8 )
2011-07-25 17:13:27 -07:00
cmd_addr | = ( is_on ? ADDR_EWEN : ADDR_EWDS ) < < 1 ;
2021-05-11 23:07:24 +02:00
else
2011-07-25 17:13:27 -07:00
cmd_addr | = ( is_on ? ADDR_EWEN : ADDR_EWDS ) ;
2016-02-10 14:32:07 -05:00
if ( has_quirk_instruction_length ( edev ) ) {
cmd_addr < < = 2 ;
bits + = 2 ;
}
dev_dbg ( & edev - > spi - > dev , " ew%s cmd 0x%04x, %d bits \n " ,
is_on ? " en " : " ds " , cmd_addr , bits ) ;
2011-07-25 17:13:27 -07:00
spi_message_init ( & m ) ;
memset ( & t , 0 , sizeof ( t ) ) ;
t . tx_buf = & cmd_addr ;
t . len = 2 ;
t . bits_per_word = bits ;
spi_message_add_tail ( & t , & m ) ;
mutex_lock ( & edev - > lock ) ;
if ( edev - > pdata - > prepare )
edev - > pdata - > prepare ( edev ) ;
ret = spi_sync ( edev - > spi , & m ) ;
/* have to wait at least Tcsl ns */
ndelay ( 250 ) ;
if ( ret )
dev_err ( & edev - > spi - > dev , " erase/write %sable error %d \n " ,
is_on ? " en " : " dis " , ret ) ;
if ( edev - > pdata - > finish )
edev - > pdata - > finish ( edev ) ;
mutex_unlock ( & edev - > lock ) ;
return ret ;
}
static ssize_t
eeprom_93xx46_write_word ( struct eeprom_93xx46_dev * edev ,
const char * buf , unsigned off )
{
struct spi_message m ;
struct spi_transfer t [ 2 ] ;
int bits , data_len , ret ;
u16 cmd_addr ;
2021-05-11 23:07:24 +02:00
if ( unlikely ( off > = edev - > size ) )
return - EINVAL ;
/* The opcode in front of the address is three bits. */
bits = edev - > addrlen + 3 ;
2011-07-25 17:13:27 -07:00
cmd_addr = OP_WRITE < < edev - > addrlen ;
2021-05-11 23:07:24 +02:00
if ( edev - > pdata - > flags & EE_ADDR8 ) {
cmd_addr | = off ;
2011-07-25 17:13:27 -07:00
data_len = 1 ;
} else {
2021-05-11 23:07:24 +02:00
cmd_addr | = ( off > > 1 ) ;
2011-07-25 17:13:27 -07:00
data_len = 2 ;
}
dev_dbg ( & edev - > spi - > dev , " write cmd 0x%x \n " , cmd_addr ) ;
spi_message_init ( & m ) ;
memset ( t , 0 , sizeof ( t ) ) ;
t [ 0 ] . tx_buf = ( char * ) & cmd_addr ;
t [ 0 ] . len = 2 ;
t [ 0 ] . bits_per_word = bits ;
spi_message_add_tail ( & t [ 0 ] , & m ) ;
t [ 1 ] . tx_buf = buf ;
t [ 1 ] . len = data_len ;
t [ 1 ] . bits_per_word = 8 ;
spi_message_add_tail ( & t [ 1 ] , & m ) ;
ret = spi_sync ( edev - > spi , & m ) ;
/* have to wait program cycle time Twc ms */
mdelay ( 6 ) ;
return ret ;
}
2016-04-24 20:28:16 +01:00
static int eeprom_93xx46_write ( void * priv , unsigned int off ,
void * val , size_t count )
2011-07-25 17:13:27 -07:00
{
2016-04-24 20:28:16 +01:00
struct eeprom_93xx46_dev * edev = priv ;
char * buf = val ;
2011-07-25 17:13:27 -07:00
int i , ret , step = 1 ;
2016-02-26 20:59:23 +01:00
if ( unlikely ( off > = edev - > size ) )
return - EFBIG ;
if ( ( off + count ) > edev - > size )
count = edev - > size - off ;
if ( unlikely ( ! count ) )
return count ;
2011-07-25 17:13:27 -07:00
/* only write even number of bytes on 16-bit devices */
2021-05-11 23:07:24 +02:00
if ( edev - > pdata - > flags & EE_ADDR16 ) {
2011-07-25 17:13:27 -07:00
step = 2 ;
count & = ~ 1 ;
}
/* erase/write enable */
ret = eeprom_93xx46_ew ( edev , 1 ) ;
if ( ret )
return ret ;
mutex_lock ( & edev - > lock ) ;
if ( edev - > pdata - > prepare )
edev - > pdata - > prepare ( edev ) ;
for ( i = 0 ; i < count ; i + = step ) {
ret = eeprom_93xx46_write_word ( edev , & buf [ i ] , off + i ) ;
if ( ret ) {
dev_err ( & edev - > spi - > dev , " write failed at %d: %d \n " ,
( int ) off + i , ret ) ;
break ;
}
}
if ( edev - > pdata - > finish )
edev - > pdata - > finish ( edev ) ;
mutex_unlock ( & edev - > lock ) ;
/* erase/write disable */
eeprom_93xx46_ew ( edev , 0 ) ;
2016-04-24 20:28:16 +01:00
return ret ;
2016-02-26 20:59:23 +01:00
}
2011-07-25 17:13:27 -07:00
static int eeprom_93xx46_eral ( struct eeprom_93xx46_dev * edev )
{
struct eeprom_93xx46_platform_data * pd = edev - > pdata ;
struct spi_message m ;
struct spi_transfer t ;
int bits , ret ;
u16 cmd_addr ;
2021-05-11 23:07:24 +02:00
/* The opcode in front of the address is three bits. */
bits = edev - > addrlen + 3 ;
2011-07-25 17:13:27 -07:00
cmd_addr = OP_START < < edev - > addrlen ;
2021-05-11 23:07:24 +02:00
if ( edev - > pdata - > flags & EE_ADDR8 )
2011-07-25 17:13:27 -07:00
cmd_addr | = ADDR_ERAL < < 1 ;
2021-05-11 23:07:24 +02:00
else
2011-07-25 17:13:27 -07:00
cmd_addr | = ADDR_ERAL ;
2016-02-10 14:32:07 -05:00
if ( has_quirk_instruction_length ( edev ) ) {
cmd_addr < < = 2 ;
bits + = 2 ;
}
dev_dbg ( & edev - > spi - > dev , " eral cmd 0x%04x, %d bits \n " , cmd_addr , bits ) ;
2011-07-25 17:13:27 -07:00
spi_message_init ( & m ) ;
memset ( & t , 0 , sizeof ( t ) ) ;
t . tx_buf = & cmd_addr ;
t . len = 2 ;
t . bits_per_word = bits ;
spi_message_add_tail ( & t , & m ) ;
mutex_lock ( & edev - > lock ) ;
if ( edev - > pdata - > prepare )
edev - > pdata - > prepare ( edev ) ;
ret = spi_sync ( edev - > spi , & m ) ;
if ( ret )
dev_err ( & edev - > spi - > dev , " erase error %d \n " , ret ) ;
/* have to wait erase cycle time Tec ms */
mdelay ( 6 ) ;
if ( pd - > finish )
pd - > finish ( edev ) ;
mutex_unlock ( & edev - > lock ) ;
return ret ;
}
static ssize_t eeprom_93xx46_store_erase ( struct device * dev ,
struct device_attribute * attr ,
const char * buf , size_t count )
{
struct eeprom_93xx46_dev * edev = dev_get_drvdata ( dev ) ;
int erase = 0 , ret ;
sscanf ( buf , " %d " , & erase ) ;
if ( erase ) {
ret = eeprom_93xx46_ew ( edev , 1 ) ;
if ( ret )
return ret ;
ret = eeprom_93xx46_eral ( edev ) ;
if ( ret )
return ret ;
ret = eeprom_93xx46_ew ( edev , 0 ) ;
if ( ret )
return ret ;
}
return count ;
}
static DEVICE_ATTR ( erase , S_IWUSR , NULL , eeprom_93xx46_store_erase ) ;
2016-02-10 14:32:08 -05:00
static void select_assert ( void * context )
{
struct eeprom_93xx46_dev * edev = context ;
gpiod_set_value_cansleep ( edev - > pdata - > select , 1 ) ;
}
static void select_deassert ( void * context )
{
struct eeprom_93xx46_dev * edev = context ;
gpiod_set_value_cansleep ( edev - > pdata - > select , 0 ) ;
}
2016-01-06 22:55:02 -05:00
static const struct of_device_id eeprom_93xx46_of_table [ ] = {
2021-05-11 23:07:25 +02:00
{ . compatible = " eeprom-93xx46 " , . data = & at93c46_data , } ,
{ . compatible = " atmel,at93c46 " , . data = & at93c46_data , } ,
2016-02-10 14:32:07 -05:00
{ . compatible = " atmel,at93c46d " , . data = & atmel_at93c46d_data , } ,
2021-05-11 23:07:25 +02:00
{ . compatible = " atmel,at93c56 " , . data = & at93c56_data , } ,
{ . compatible = " atmel,at93c66 " , . data = & at93c66_data , } ,
2021-01-05 16:28:12 +05:30
{ . compatible = " microchip,93lc46b " , . data = & microchip_93lc46b_data , } ,
2016-01-06 22:55:02 -05:00
{ }
} ;
MODULE_DEVICE_TABLE ( of , eeprom_93xx46_of_table ) ;
2021-09-22 19:40:48 +01:00
static const struct spi_device_id eeprom_93xx46_spi_ids [ ] = {
{ . name = " eeprom-93xx46 " ,
. driver_data = ( kernel_ulong_t ) & at93c46_data , } ,
{ . name = " at93c46 " ,
. driver_data = ( kernel_ulong_t ) & at93c46_data , } ,
{ . name = " at93c46d " ,
. driver_data = ( kernel_ulong_t ) & atmel_at93c46d_data , } ,
{ . name = " at93c56 " ,
. driver_data = ( kernel_ulong_t ) & at93c56_data , } ,
{ . name = " at93c66 " ,
. driver_data = ( kernel_ulong_t ) & at93c66_data , } ,
{ . name = " 93lc46b " ,
. driver_data = ( kernel_ulong_t ) & microchip_93lc46b_data , } ,
{ }
} ;
2021-10-14 17:37:18 +02:00
MODULE_DEVICE_TABLE ( spi , eeprom_93xx46_spi_ids ) ;
2021-09-22 19:40:48 +01:00
2016-01-06 22:55:02 -05:00
static int eeprom_93xx46_probe_dt ( struct spi_device * spi )
{
2016-02-10 14:32:07 -05:00
const struct of_device_id * of_id =
of_match_device ( eeprom_93xx46_of_table , & spi - > dev ) ;
2016-01-06 22:55:02 -05:00
struct device_node * np = spi - > dev . of_node ;
struct eeprom_93xx46_platform_data * pd ;
u32 tmp ;
int ret ;
pd = devm_kzalloc ( & spi - > dev , sizeof ( * pd ) , GFP_KERNEL ) ;
if ( ! pd )
return - ENOMEM ;
ret = of_property_read_u32 ( np , " data-size " , & tmp ) ;
if ( ret < 0 ) {
dev_err ( & spi - > dev , " data-size property not found \n " ) ;
return ret ;
}
if ( tmp = = 8 ) {
pd - > flags | = EE_ADDR8 ;
} else if ( tmp = = 16 ) {
pd - > flags | = EE_ADDR16 ;
} else {
dev_err ( & spi - > dev , " invalid data-size (%d) \n " , tmp ) ;
return - EINVAL ;
}
if ( of_property_read_bool ( np , " read-only " ) )
pd - > flags | = EE_READONLY ;
2017-07-19 23:35:28 -03:00
pd - > select = devm_gpiod_get_optional ( & spi - > dev , " select " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( pd - > select ) )
return PTR_ERR ( pd - > select ) ;
2016-02-10 14:32:08 -05:00
2017-07-19 23:35:28 -03:00
pd - > prepare = select_assert ;
pd - > finish = select_deassert ;
gpiod_direction_output ( pd - > select , 0 ) ;
2016-02-10 14:32:08 -05:00
2016-02-10 14:32:07 -05:00
if ( of_id - > data ) {
const struct eeprom_93xx46_devtype_data * data = of_id - > data ;
pd - > quirks = data - > quirks ;
2021-05-11 23:07:25 +02:00
pd - > flags | = data - > flags ;
2016-02-10 14:32:07 -05:00
}
2016-01-06 22:55:02 -05:00
spi - > dev . platform_data = pd ;
return 0 ;
}
2012-11-19 13:23:05 -05:00
static int eeprom_93xx46_probe ( struct spi_device * spi )
2011-07-25 17:13:27 -07:00
{
struct eeprom_93xx46_platform_data * pd ;
struct eeprom_93xx46_dev * edev ;
int err ;
2016-01-06 22:55:02 -05:00
if ( spi - > dev . of_node ) {
err = eeprom_93xx46_probe_dt ( spi ) ;
if ( err < 0 )
return err ;
}
2011-07-25 17:13:27 -07:00
pd = spi - > dev . platform_data ;
if ( ! pd ) {
dev_err ( & spi - > dev , " missing platform data \n " ) ;
return - ENODEV ;
}
2018-09-21 06:40:01 -07:00
edev = devm_kzalloc ( & spi - > dev , sizeof ( * edev ) , GFP_KERNEL ) ;
2011-07-25 17:13:27 -07:00
if ( ! edev )
return - ENOMEM ;
2021-05-11 23:07:25 +02:00
if ( pd - > flags & EE_SIZE1K )
edev - > size = 128 ;
else if ( pd - > flags & EE_SIZE2K )
edev - > size = 256 ;
else if ( pd - > flags & EE_SIZE4K )
edev - > size = 512 ;
else {
dev_err ( & spi - > dev , " unspecified size \n " ) ;
return - EINVAL ;
}
2021-05-11 23:07:24 +02:00
2011-07-25 17:13:27 -07:00
if ( pd - > flags & EE_ADDR8 )
2021-05-11 23:07:24 +02:00
edev - > addrlen = ilog2 ( edev - > size ) ;
2011-07-25 17:13:27 -07:00
else if ( pd - > flags & EE_ADDR16 )
2021-05-11 23:07:24 +02:00
edev - > addrlen = ilog2 ( edev - > size ) - 1 ;
2011-07-25 17:13:27 -07:00
else {
dev_err ( & spi - > dev , " unspecified address type \n " ) ;
2018-09-21 06:40:01 -07:00
return - EINVAL ;
2011-07-25 17:13:27 -07:00
}
mutex_init ( & edev - > lock ) ;
2016-04-20 10:16:36 +01:00
edev - > spi = spi ;
2011-07-25 17:13:27 -07:00
edev - > pdata = pd ;
2020-09-16 20:09:33 +03:00
edev - > nvmem_config . type = NVMEM_TYPE_EEPROM ;
2016-02-26 20:59:23 +01:00
edev - > nvmem_config . name = dev_name ( & spi - > dev ) ;
edev - > nvmem_config . dev = & spi - > dev ;
edev - > nvmem_config . read_only = pd - > flags & EE_READONLY ;
edev - > nvmem_config . root_only = true ;
edev - > nvmem_config . owner = THIS_MODULE ;
edev - > nvmem_config . compat = true ;
edev - > nvmem_config . base_dev = & spi - > dev ;
2016-04-24 20:28:16 +01:00
edev - > nvmem_config . reg_read = eeprom_93xx46_read ;
edev - > nvmem_config . reg_write = eeprom_93xx46_write ;
edev - > nvmem_config . priv = edev ;
edev - > nvmem_config . stride = 4 ;
edev - > nvmem_config . word_size = 1 ;
edev - > nvmem_config . size = edev - > size ;
2016-02-26 20:59:23 +01:00
2018-09-21 06:40:01 -07:00
edev - > nvmem = devm_nvmem_register ( & spi - > dev , & edev - > nvmem_config ) ;
if ( IS_ERR ( edev - > nvmem ) )
return PTR_ERR ( edev - > nvmem ) ;
2011-07-25 17:13:27 -07:00
2021-05-11 23:07:25 +02:00
dev_info ( & spi - > dev , " %d-bit eeprom containing %d bytes %s \n " ,
2011-07-25 17:13:27 -07:00
( pd - > flags & EE_ADDR8 ) ? 8 : 16 ,
2021-05-11 23:07:25 +02:00
edev - > size ,
2011-07-25 17:13:27 -07:00
( pd - > flags & EE_READONLY ) ? " (readonly) " : " " ) ;
if ( ! ( pd - > flags & EE_READONLY ) ) {
if ( device_create_file ( & spi - > dev , & dev_attr_erase ) )
dev_err ( & spi - > dev , " can't create erase interface \n " ) ;
}
2013-04-05 10:56:04 +09:00
spi_set_drvdata ( spi , edev ) ;
2011-07-25 17:13:27 -07:00
return 0 ;
}
2022-01-23 18:52:01 +01:00
static void eeprom_93xx46_remove ( struct spi_device * spi )
2011-07-25 17:13:27 -07:00
{
2013-04-05 10:56:04 +09:00
struct eeprom_93xx46_dev * edev = spi_get_drvdata ( spi ) ;
2011-07-25 17:13:27 -07:00
if ( ! ( edev - > pdata - > flags & EE_READONLY ) )
device_remove_file ( & spi - > dev , & dev_attr_erase ) ;
}
static struct spi_driver eeprom_93xx46_driver = {
. driver = {
. name = " 93xx46 " ,
2016-01-06 22:55:02 -05:00
. of_match_table = of_match_ptr ( eeprom_93xx46_of_table ) ,
2011-07-25 17:13:27 -07:00
} ,
. probe = eeprom_93xx46_probe ,
2012-11-19 13:21:23 -05:00
. remove = eeprom_93xx46_remove ,
2021-09-22 19:40:48 +01:00
. id_table = eeprom_93xx46_spi_ids ,
2011-07-25 17:13:27 -07:00
} ;
2012-01-22 15:38:22 +08:00
module_spi_driver ( eeprom_93xx46_driver ) ;
2011-07-25 17:13:27 -07:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Driver for 93xx46 EEPROMs " ) ;
MODULE_AUTHOR ( " Anatolij Gustschin <agust@denx.de> " ) ;
2021-01-13 10:42:52 +05:30
MODULE_ALIAS ( " spi:93xx46 " ) ;
2021-01-07 22:09:53 +05:30
MODULE_ALIAS ( " spi:eeprom-93xx46 " ) ;
2021-01-07 22:09:54 +05:30
MODULE_ALIAS ( " spi:93lc46b " ) ;