2018-03-23 19:15:02 +03:00
// SPDX-License-Identifier: GPL-2.0+
2008-07-15 00:38:35 +04:00
/*
* at24 . c - handle most I2C EEPROMs
*
* Copyright ( C ) 2005 - 2007 David Brownell
* Copyright ( C ) 2008 Wolfram Sang , Pengutronix
*/
2018-03-23 19:15:02 +03:00
2008-07-15 00:38:35 +04:00
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/module.h>
2017-10-01 13:49:48 +03:00
# include <linux/of_device.h>
2008-07-15 00:38:35 +04:00
# include <linux/slab.h>
# include <linux/delay.h>
# include <linux/mutex.h>
# include <linux/mod_devicetable.h>
# include <linux/log2.h>
# include <linux/bitops.h>
# include <linux/jiffies.h>
misc: eeprom: at24: use device_property_*() functions instead of of_get_property()
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2017-02-09 20:36:08 +03:00
# include <linux/property.h>
2015-10-23 12:16:44 +03:00
# include <linux/acpi.h>
2008-07-15 00:38:35 +04:00
# include <linux/i2c.h>
2016-02-26 22:59:20 +03:00
# include <linux/nvmem-provider.h>
2017-11-28 23:51:40 +03:00
# include <linux/regmap.h>
2013-09-27 23:06:28 +04:00
# include <linux/platform_data/at24.h>
2017-10-10 09:00:37 +03:00
# include <linux/pm_runtime.h>
2017-12-19 13:28:54 +03:00
# include <linux/gpio/consumer.h>
2008-07-15 00:38:35 +04:00
/*
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable .
* Differences between different vendor product lines ( like Atmel AT24C or
* MicroChip 24L C , etc ) won ' t much matter for typical read / write access .
* There are also I2C RAM chips , likewise interchangeable . One example
* would be the PCF8570 , which acts like a 24 c02 EEPROM ( 256 bytes ) .
*
* However , misconfiguration can lose data . " Set 16-bit memory address "
* to a part with 8 - bit addressing will overwrite data . Writing with too
* big a page size also loses data . And it ' s not safe to assume that the
* conventional addresses 0x50 . .0 x57 only hold eeproms ; a PCF8563 RTC
* uses 0x51 , for just one example .
*
* Accordingly , explicit board - specific configuration data should be used
* in almost all cases . ( One partial exception is an SMBus used to access
* " SPD " data for DRAM sticks . Those only use 24 c02 EEPROMs . )
*
* So this driver uses " new style " I2C driver binding , expecting to be
* told what devices exist . That may be in arch / X / mach - Y / board - Z . c or
* similar kernel - resident tables ; or , configuration data coming from
* a bootloader .
*
* Other than binding model , current differences from " eeprom " driver are
* that this one handles write access and isn ' t restricted to 24 c02 devices .
* It also handles larger devices ( 32 kbit and up ) with two - byte addresses ,
* which won ' t work on pure SMBus systems .
*/
2017-11-28 23:51:40 +03:00
struct at24_client {
struct i2c_client * client ;
struct regmap * regmap ;
} ;
2008-07-15 00:38:35 +04:00
struct at24_data {
/*
* Lock protects against activities from other Linux tasks ,
* but not from changes by other I2C masters .
*/
struct mutex lock ;
2017-12-13 13:56:23 +03:00
unsigned int write_max ;
unsigned int num_addresses ;
2017-11-28 23:51:50 +03:00
unsigned int offset_adj ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:17 +03:00
u32 byte_len ;
u16 page_size ;
u8 flags ;
2016-02-26 22:59:20 +03:00
struct nvmem_device * nvmem ;
2017-12-19 13:28:54 +03:00
struct gpio_desc * wp_gpio ;
2008-07-15 00:38:35 +04:00
/*
* Some chips tie up multiple I2C addresses ; dummy devices reserve
* them for us , and we ' ll use them with SMBus calls .
*/
2017-11-28 23:51:40 +03:00
struct at24_client client [ ] ;
2008-07-15 00:38:35 +04:00
} ;
/*
* This parameter is to help this driver avoid blocking other drivers out
* of I2C for potentially troublesome amounts of time . With a 100 kHz I2C
* clock , one 256 byte read takes about 1 / 43 second which is excessive ;
* but the 1 / 170 second it takes at 400 kHz may be quite reasonable ; and
* at 1 MHz ( Fm + ) a 1 / 430 second delay could easily be invisible .
*
* This value is forced to be a power of two so that writes align on pages .
*/
2017-12-18 20:16:46 +03:00
static unsigned int at24_io_limit = 128 ;
module_param_named ( io_limit , at24_io_limit , uint , 0 ) ;
MODULE_PARM_DESC ( at24_io_limit , " Maximum bytes per I/O (default 128) " ) ;
2008-07-15 00:38:35 +04:00
/*
* Specs often allow 5 msec for a page write , sometimes 20 msec ;
* it ' s important to recover from write timeouts .
*/
2017-12-18 20:16:46 +03:00
static unsigned int at24_write_timeout = 25 ;
module_param_named ( write_timeout , at24_write_timeout , uint , 0 ) ;
MODULE_PARM_DESC ( at24_write_timeout , " Time (in ms) to try writes (default 25) " ) ;
2008-07-15 00:38:35 +04:00
2016-06-06 11:48:47 +03:00
/*
* Both reads and writes fail if the previous write didn ' t complete yet . This
* macro loops a few times waiting at least long enough for one entire page
2016-07-17 21:40:06 +03:00
* write to work while making sure that at least one iteration is run before
* checking the break condition .
2016-06-06 11:48:47 +03:00
*
* It takes two parameters : a variable in which the future timeout in jiffies
* will be stored and a temporary variable holding the time of the last
* iteration of processing the request . Both should be unsigned integers
* holding at least 32 bits .
*/
2017-12-18 20:16:46 +03:00
# define at24_loop_until_timeout(tout, op_time) \
for ( tout = jiffies + msecs_to_jiffies ( at24_write_timeout ) , \
op_time = 0 ; \
2016-07-17 21:40:06 +03:00
op_time ? time_before ( op_time , tout ) : true ; \
2016-06-06 11:48:47 +03:00
usleep_range ( 1000 , 1500 ) , op_time = jiffies )
2017-12-20 19:48:56 +03:00
struct at24_chip_data {
/*
* these fields mirror their equivalents in
* struct at24_platform_data
*/
u32 byte_len ;
u8 flags ;
} ;
# define AT24_CHIP_DATA(_name, _len, _flags) \
static const struct at24_chip_data _name = { \
. byte_len = _len , . flags = _flags , \
}
/* needs 8 addresses as A0-A2 are ignored */
AT24_CHIP_DATA ( at24_data_24c00 , 128 / 8 , AT24_FLAG_TAKE8ADDR ) ;
/* old variants can't be handled with this generic entry! */
AT24_CHIP_DATA ( at24_data_24c01 , 1024 / 8 , 0 ) ;
AT24_CHIP_DATA ( at24_data_24cs01 , 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24c02 , 2048 / 8 , 0 ) ;
AT24_CHIP_DATA ( at24_data_24cs02 , 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24mac402 , 48 / 8 ,
AT24_FLAG_MAC | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24mac602 , 64 / 8 ,
AT24_FLAG_MAC | AT24_FLAG_READONLY ) ;
/* spd is a 24c02 in memory DIMMs */
AT24_CHIP_DATA ( at24_data_spd , 2048 / 8 ,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO ) ;
AT24_CHIP_DATA ( at24_data_24c04 , 4096 / 8 , 0 ) ;
AT24_CHIP_DATA ( at24_data_24cs04 , 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
/* 24rf08 quirk is handled at i2c-core */
AT24_CHIP_DATA ( at24_data_24c08 , 8192 / 8 , 0 ) ;
AT24_CHIP_DATA ( at24_data_24cs08 , 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24c16 , 16384 / 8 , 0 ) ;
AT24_CHIP_DATA ( at24_data_24cs16 , 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24c32 , 32768 / 8 , AT24_FLAG_ADDR16 ) ;
AT24_CHIP_DATA ( at24_data_24cs32 , 16 ,
AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24c64 , 65536 / 8 , AT24_FLAG_ADDR16 ) ;
AT24_CHIP_DATA ( at24_data_24cs64 , 16 ,
AT24_FLAG_ADDR16 | AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) ;
AT24_CHIP_DATA ( at24_data_24c128 , 131072 / 8 , AT24_FLAG_ADDR16 ) ;
AT24_CHIP_DATA ( at24_data_24c256 , 262144 / 8 , AT24_FLAG_ADDR16 ) ;
AT24_CHIP_DATA ( at24_data_24c512 , 524288 / 8 , AT24_FLAG_ADDR16 ) ;
AT24_CHIP_DATA ( at24_data_24c1024 , 1048576 / 8 , AT24_FLAG_ADDR16 ) ;
/* identical to 24c08 ? */
AT24_CHIP_DATA ( at24_data_INT3499 , 8192 / 8 , 0 ) ;
2008-07-15 00:38:35 +04:00
static const struct i2c_device_id at24_ids [ ] = {
2017-12-20 19:48:56 +03:00
{ " 24c00 " , ( kernel_ulong_t ) & at24_data_24c00 } ,
{ " 24c01 " , ( kernel_ulong_t ) & at24_data_24c01 } ,
{ " 24cs01 " , ( kernel_ulong_t ) & at24_data_24cs01 } ,
{ " 24c02 " , ( kernel_ulong_t ) & at24_data_24c02 } ,
{ " 24cs02 " , ( kernel_ulong_t ) & at24_data_24cs02 } ,
{ " 24mac402 " , ( kernel_ulong_t ) & at24_data_24mac402 } ,
{ " 24mac602 " , ( kernel_ulong_t ) & at24_data_24mac602 } ,
{ " spd " , ( kernel_ulong_t ) & at24_data_spd } ,
{ " 24c04 " , ( kernel_ulong_t ) & at24_data_24c04 } ,
{ " 24cs04 " , ( kernel_ulong_t ) & at24_data_24cs04 } ,
{ " 24c08 " , ( kernel_ulong_t ) & at24_data_24c08 } ,
{ " 24cs08 " , ( kernel_ulong_t ) & at24_data_24cs08 } ,
{ " 24c16 " , ( kernel_ulong_t ) & at24_data_24c16 } ,
{ " 24cs16 " , ( kernel_ulong_t ) & at24_data_24cs16 } ,
{ " 24c32 " , ( kernel_ulong_t ) & at24_data_24c32 } ,
{ " 24cs32 " , ( kernel_ulong_t ) & at24_data_24cs32 } ,
{ " 24c64 " , ( kernel_ulong_t ) & at24_data_24c64 } ,
{ " 24cs64 " , ( kernel_ulong_t ) & at24_data_24cs64 } ,
{ " 24c128 " , ( kernel_ulong_t ) & at24_data_24c128 } ,
{ " 24c256 " , ( kernel_ulong_t ) & at24_data_24c256 } ,
{ " 24c512 " , ( kernel_ulong_t ) & at24_data_24c512 } ,
{ " 24c1024 " , ( kernel_ulong_t ) & at24_data_24c1024 } ,
{ " at24 " , 0 } ,
2008-07-15 00:38:35 +04:00
{ /* END OF LIST */ }
} ;
MODULE_DEVICE_TABLE ( i2c , at24_ids ) ;
2017-10-01 13:49:48 +03:00
static const struct of_device_id at24_of_match [ ] = {
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c00 " , . data = & at24_data_24c00 } ,
{ . compatible = " atmel,24c01 " , . data = & at24_data_24c01 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs01 " , . data = & at24_data_24cs01 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c02 " , . data = & at24_data_24c02 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs02 " , . data = & at24_data_24cs02 } ,
{ . compatible = " atmel,24mac402 " , . data = & at24_data_24mac402 } ,
{ . compatible = " atmel,24mac602 " , . data = & at24_data_24mac602 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,spd " , . data = & at24_data_spd } ,
{ . compatible = " atmel,24c04 " , . data = & at24_data_24c04 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs04 " , . data = & at24_data_24cs04 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c08 " , . data = & at24_data_24c08 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs08 " , . data = & at24_data_24cs08 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c16 " , . data = & at24_data_24c16 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs16 " , . data = & at24_data_24cs16 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c32 " , . data = & at24_data_24c32 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs32 " , . data = & at24_data_24cs32 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c64 " , . data = & at24_data_24c64 } ,
2017-12-28 13:49:13 +03:00
{ . compatible = " atmel,24cs64 " , . data = & at24_data_24cs64 } ,
2017-12-20 19:48:56 +03:00
{ . compatible = " atmel,24c128 " , . data = & at24_data_24c128 } ,
{ . compatible = " atmel,24c256 " , . data = & at24_data_24c256 } ,
{ . compatible = " atmel,24c512 " , . data = & at24_data_24c512 } ,
{ . compatible = " atmel,24c1024 " , . data = & at24_data_24c1024 } ,
{ /* END OF LIST */ } ,
2017-10-01 13:49:48 +03:00
} ;
MODULE_DEVICE_TABLE ( of , at24_of_match ) ;
2015-10-23 12:16:44 +03:00
static const struct acpi_device_id at24_acpi_ids [ ] = {
2017-12-20 19:48:56 +03:00
{ " INT3499 " , ( kernel_ulong_t ) & at24_data_INT3499 } ,
{ /* END OF LIST */ }
2015-10-23 12:16:44 +03:00
} ;
MODULE_DEVICE_TABLE ( acpi , at24_acpi_ids ) ;
2008-07-15 00:38:35 +04:00
/*
* This routine supports chips which consume multiple I2C addresses . It
* computes the addressing information to be used for a given r / w request .
* Assumes that sanity checks for offset happened at sysfs - layer .
2016-06-06 11:48:48 +03:00
*
* Slave address and byte offset derive from the offset . Always
* set the byte address ; on a multi - master board , another master
* may have changed the chip ' s " current " address pointer .
2008-07-15 00:38:35 +04:00
*/
2017-11-28 23:51:42 +03:00
static struct at24_client * at24_translate_offset ( struct at24_data * at24 ,
unsigned int * offset )
2008-07-15 00:38:35 +04:00
{
2017-12-13 13:56:23 +03:00
unsigned int i ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:17 +03:00
if ( at24 - > flags & AT24_FLAG_ADDR16 ) {
2008-07-15 00:38:35 +04:00
i = * offset > > 16 ;
* offset & = 0xffff ;
} else {
i = * offset > > 8 ;
* offset & = 0xff ;
}
2017-11-28 23:51:42 +03:00
return & at24 - > client [ i ] ;
2008-07-15 00:38:35 +04:00
}
2018-03-19 12:17:14 +03:00
static struct device * at24_base_client_dev ( struct at24_data * at24 )
{
return & at24 - > client [ 0 ] . client - > dev ;
}
2017-12-08 19:28:30 +03:00
static size_t at24_adjust_read_count ( struct at24_data * at24 ,
unsigned int offset , size_t count )
{
unsigned int bits ;
size_t remainder ;
/*
* In case of multi - address chips that don ' t rollover reads to
* the next slave address : truncate the count to the slave boundary ,
* so that the read never straddles slaves .
*/
2018-03-19 12:17:17 +03:00
if ( at24 - > flags & AT24_FLAG_NO_RDROL ) {
bits = ( at24 - > flags & AT24_FLAG_ADDR16 ) ? 16 : 8 ;
2017-12-08 19:28:30 +03:00
remainder = BIT ( bits ) - offset ;
if ( count > remainder )
count = remainder ;
}
2017-12-18 20:16:46 +03:00
if ( count > at24_io_limit )
count = at24_io_limit ;
2017-12-08 19:28:30 +03:00
return count ;
}
2017-11-28 23:51:50 +03:00
static ssize_t at24_regmap_read ( struct at24_data * at24 , char * buf ,
unsigned int offset , size_t count )
{
unsigned long timeout , read_time ;
struct at24_client * at24_client ;
struct i2c_client * client ;
struct regmap * regmap ;
int ret ;
at24_client = at24_translate_offset ( at24 , & offset ) ;
regmap = at24_client - > regmap ;
client = at24_client - > client ;
2017-12-08 19:28:30 +03:00
count = at24_adjust_read_count ( at24 , offset , count ) ;
2017-11-28 23:51:50 +03:00
/* adjust offset for mac and serial read ops */
offset + = at24 - > offset_adj ;
2017-12-18 20:16:46 +03:00
at24_loop_until_timeout ( timeout , read_time ) {
2017-11-28 23:51:50 +03:00
ret = regmap_bulk_read ( regmap , offset , buf , count ) ;
dev_dbg ( & client - > dev , " read %zu@%d --> %d (%ld) \n " ,
count , offset , ret , jiffies ) ;
if ( ! ret )
return count ;
}
return - ETIMEDOUT ;
}
2008-07-15 00:38:35 +04:00
/*
* Note that if the hardware write - protect pin is pulled high , the whole
* chip is normally write protected . But there are plenty of product
* variants here , including OTP fuses and partial chip protect .
*
2016-06-06 11:48:49 +03:00
* We only use page mode writes ; the alternative is sloooow . These routines
* write at most one page .
2008-07-15 00:38:35 +04:00
*/
2016-06-06 11:48:49 +03:00
static size_t at24_adjust_write_count ( struct at24_data * at24 ,
unsigned int offset , size_t count )
2008-07-15 00:38:35 +04:00
{
2017-12-13 13:56:23 +03:00
unsigned int next_page ;
2008-07-15 00:38:35 +04:00
/* write_max is at most a page */
if ( count > at24 - > write_max )
count = at24 - > write_max ;
/* Never roll over backwards, to the start of this page */
2018-03-19 12:17:17 +03:00
next_page = roundup ( offset + 1 , at24 - > page_size ) ;
2008-07-15 00:38:35 +04:00
if ( offset + count > next_page )
count = next_page - offset ;
2016-06-06 11:48:49 +03:00
return count ;
}
2017-11-28 23:51:45 +03:00
static ssize_t at24_regmap_write ( struct at24_data * at24 , const char * buf ,
unsigned int offset , size_t count )
{
unsigned long timeout , write_time ;
struct at24_client * at24_client ;
struct i2c_client * client ;
struct regmap * regmap ;
int ret ;
at24_client = at24_translate_offset ( at24 , & offset ) ;
regmap = at24_client - > regmap ;
client = at24_client - > client ;
count = at24_adjust_write_count ( at24 , offset , count ) ;
2017-12-18 20:16:46 +03:00
at24_loop_until_timeout ( timeout , write_time ) {
2017-11-28 23:51:45 +03:00
ret = regmap_bulk_write ( regmap , offset , buf , count ) ;
dev_dbg ( & client - > dev , " write %zu@%d --> %d (%ld) \n " ,
count , offset , ret , jiffies ) ;
if ( ! ret )
return count ;
}
return - ETIMEDOUT ;
}
2016-06-06 11:48:44 +03:00
static int at24_read ( void * priv , unsigned int off , void * val , size_t count )
{
2018-03-19 12:17:03 +03:00
struct at24_data * at24 ;
struct device * dev ;
2016-06-06 11:48:44 +03:00
char * buf = val ;
2017-10-10 09:00:37 +03:00
int ret ;
2016-06-06 11:48:44 +03:00
2018-03-19 12:17:03 +03:00
at24 = priv ;
2018-03-19 12:17:14 +03:00
dev = at24_base_client_dev ( at24 ) ;
2018-03-19 12:17:03 +03:00
2016-06-06 11:48:44 +03:00
if ( unlikely ( ! count ) )
return count ;
2018-03-19 12:17:17 +03:00
if ( off + count > at24 - > byte_len )
2017-11-24 09:47:50 +03:00
return - EINVAL ;
2017-12-01 21:37:12 +03:00
ret = pm_runtime_get_sync ( dev ) ;
2017-10-10 09:00:37 +03:00
if ( ret < 0 ) {
2017-12-01 21:37:12 +03:00
pm_runtime_put_noidle ( dev ) ;
2017-10-10 09:00:37 +03:00
return ret ;
}
2016-06-06 11:48:44 +03:00
/*
* Read data from chip , protecting against concurrent updates
* from this host , but not from other I2C masters .
*/
mutex_lock ( & at24 - > lock ) ;
while ( count ) {
2018-03-19 12:17:06 +03:00
ret = at24_regmap_read ( at24 , buf , off , count ) ;
if ( ret < 0 ) {
2016-06-06 11:48:44 +03:00
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2018-03-19 12:17:06 +03:00
return ret ;
2016-06-06 11:48:44 +03:00
}
2018-03-19 12:17:06 +03:00
buf + = ret ;
off + = ret ;
count - = ret ;
2016-06-06 11:48:44 +03:00
}
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2017-10-10 09:00:37 +03:00
2016-06-06 11:48:44 +03:00
return 0 ;
}
2016-04-24 22:28:06 +03:00
static int at24_write ( void * priv , unsigned int off , void * val , size_t count )
2008-07-15 00:38:35 +04:00
{
2018-03-19 12:17:03 +03:00
struct at24_data * at24 ;
struct device * dev ;
2016-04-24 22:28:06 +03:00
char * buf = val ;
2017-10-10 09:00:37 +03:00
int ret ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:03 +03:00
at24 = priv ;
2018-03-19 12:17:14 +03:00
dev = at24_base_client_dev ( at24 ) ;
2018-03-19 12:17:03 +03:00
2008-07-15 00:38:35 +04:00
if ( unlikely ( ! count ) )
2016-04-24 22:28:06 +03:00
return - EINVAL ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:17 +03:00
if ( off + count > at24 - > byte_len )
2017-11-24 09:47:50 +03:00
return - EINVAL ;
2017-12-01 21:37:12 +03:00
ret = pm_runtime_get_sync ( dev ) ;
2017-10-10 09:00:37 +03:00
if ( ret < 0 ) {
2017-12-01 21:37:12 +03:00
pm_runtime_put_noidle ( dev ) ;
2017-10-10 09:00:37 +03:00
return ret ;
}
2008-07-15 00:38:35 +04:00
/*
* Write data to chip , protecting against concurrent updates
* from this host , but not from other I2C masters .
*/
mutex_lock ( & at24 - > lock ) ;
2017-12-19 13:28:54 +03:00
gpiod_set_value_cansleep ( at24 - > wp_gpio , 0 ) ;
2008-07-15 00:38:35 +04:00
while ( count ) {
2018-03-19 12:17:07 +03:00
ret = at24_regmap_write ( at24 , buf , off , count ) ;
if ( ret < 0 ) {
2017-12-19 13:28:54 +03:00
gpiod_set_value_cansleep ( at24 - > wp_gpio , 1 ) ;
2016-04-24 22:28:06 +03:00
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2018-03-19 12:17:07 +03:00
return ret ;
2008-07-15 00:38:35 +04:00
}
2018-03-19 12:17:07 +03:00
buf + = ret ;
off + = ret ;
count - = ret ;
2008-07-15 00:38:35 +04:00
}
2017-12-19 13:28:54 +03:00
gpiod_set_value_cansleep ( at24 - > wp_gpio , 1 ) ;
2008-07-15 00:38:35 +04:00
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2017-10-10 09:00:37 +03:00
2016-02-26 22:59:20 +03:00
return 0 ;
}
2018-03-19 12:17:10 +03:00
static void at24_properties_to_pdata ( struct device * dev ,
struct at24_platform_data * chip )
2010-11-17 15:00:48 +03:00
{
misc: eeprom: at24: use device_property_*() functions instead of of_get_property()
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2017-02-09 20:36:08 +03:00
int err ;
u32 val ;
if ( device_property_present ( dev , " read-only " ) )
chip - > flags | = AT24_FLAG_READONLY ;
2017-12-08 19:28:30 +03:00
if ( device_property_present ( dev , " no-read-rollover " ) )
chip - > flags | = AT24_FLAG_NO_RDROL ;
misc: eeprom: at24: use device_property_*() functions instead of of_get_property()
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2017-02-09 20:36:08 +03:00
2017-10-10 09:00:36 +03:00
err = device_property_read_u32 ( dev , " size " , & val ) ;
if ( ! err )
chip - > byte_len = val ;
misc: eeprom: at24: use device_property_*() functions instead of of_get_property()
Allow the at24 driver to get configuration information from both OF and
ACPI by using the more generic device_property functions.
This change was inspired by the at25.c driver.
I have a custom board with a ST M24C02 EEPROM attached to an I2C bus.
With the following ACPI construct, this patch instantiates a working
instance of the driver.
Device (EEP0) {
Name (_HID, "PRP0001")
Name (_DSD, Package () {
ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
Package () {
Package () {"compatible", Package () {"st,24c02"}},
Package () {"pagesize", 16},
},
})
Name (_CRS, ResourceTemplate () {
I2cSerialBus (
0x0057, ControllerInitiated, 400000,
AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00,
ResourceConsumer,,)
})
}
Signed-off-by: Ben Gardner <gardner.ben@gmail.com>
Reviewed-by: Andy Shevchenko <andy.shevchenko@gmail.com>
Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
2017-02-09 20:36:08 +03:00
err = device_property_read_u32 ( dev , " pagesize " , & val ) ;
if ( ! err ) {
chip - > page_size = val ;
} else {
/*
* This is slow , but we can ' t know all eeproms , so we better
* play safe . Specifying custom eeprom - types via platform_data
* is recommended anyhow .
*/
chip - > page_size = 1 ;
2010-11-17 15:00:48 +03:00
}
}
2018-03-19 12:17:16 +03:00
static int at24_get_pdata ( struct device * dev , struct at24_platform_data * pdata )
{
struct device_node * of_node = dev - > of_node ;
const struct at24_chip_data * cdata ;
const struct i2c_device_id * id ;
struct at24_platform_data * pd ;
pd = dev_get_platdata ( dev ) ;
if ( pd ) {
memcpy ( pdata , pd , sizeof ( * pdata ) ) ;
return 0 ;
}
id = i2c_match_id ( at24_ids , to_i2c_client ( dev ) ) ;
/*
* The I2C core allows OF nodes compatibles to match against the
* I2C device ID table as a fallback , so check not only if an OF
* node is present but also if it matches an OF device ID entry .
*/
if ( of_node & & of_match_device ( at24_of_match , dev ) )
cdata = of_device_get_match_data ( dev ) ;
else if ( id )
2018-05-07 13:08:37 +03:00
cdata = ( void * ) id - > driver_data ;
2018-03-19 12:17:16 +03:00
else
cdata = acpi_device_get_match_data ( dev ) ;
if ( ! cdata )
return - ENODEV ;
pdata - > byte_len = cdata - > byte_len ;
pdata - > flags = cdata - > flags ;
at24_properties_to_pdata ( dev , pdata ) ;
return 0 ;
}
2017-11-28 23:51:50 +03:00
static unsigned int at24_get_offset_adj ( u8 flags , unsigned int byte_len )
{
if ( flags & AT24_FLAG_MAC ) {
/* EUI-48 starts from 0x9a, EUI-64 from 0x98 */
return 0xa0 - byte_len ;
} else if ( flags & AT24_FLAG_SERIAL & & flags & AT24_FLAG_ADDR16 ) {
/*
* For 16 bit address pointers , the word address must contain
* a ' 10 ' sequence in bits 11 and 10 regardless of the
* intended position of the address pointer .
*/
return 0x0800 ;
} else if ( flags & AT24_FLAG_SERIAL ) {
/*
* Otherwise the word address must begin with a ' 10 ' sequence ,
* regardless of the intended address .
*/
return 0x0080 ;
} else {
return 0 ;
}
}
2018-03-19 12:17:15 +03:00
static int at24_probe ( struct i2c_client * client )
2008-07-15 00:38:35 +04:00
{
2017-12-18 20:24:43 +03:00
struct regmap_config regmap_config = { } ;
2018-03-19 12:17:02 +03:00
struct nvmem_config nvmem_config = { } ;
2018-03-19 12:17:11 +03:00
struct at24_platform_data pdata = { } ;
2018-03-19 12:17:12 +03:00
struct device * dev = & client - > dev ;
2018-03-19 12:17:21 +03:00
bool i2c_fn_i2c , i2c_fn_block ;
2018-03-19 12:17:03 +03:00
unsigned int i , num_addresses ;
struct at24_data * at24 ;
2018-03-19 12:17:18 +03:00
struct regmap * regmap ;
2018-03-19 12:17:13 +03:00
size_t at24_size ;
2018-03-19 12:17:03 +03:00
bool writable ;
2016-08-12 14:32:57 +03:00
u8 test_byte ;
2018-03-19 12:17:03 +03:00
int err ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:21 +03:00
i2c_fn_i2c = i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) ;
i2c_fn_block = i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK ) ;
2018-03-19 12:17:16 +03:00
err = at24_get_pdata ( dev , & pdata ) ;
if ( err )
return err ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:21 +03:00
if ( ! i2c_fn_i2c & & ! i2c_fn_block )
2018-03-19 12:17:18 +03:00
pdata . page_size = 1 ;
2018-03-19 12:17:11 +03:00
if ( ! pdata . page_size ) {
2018-03-19 12:17:12 +03:00
dev_err ( dev , " page_size must not be 0! \n " ) ;
2013-05-29 00:00:20 +04:00
return - EINVAL ;
2010-11-17 15:00:49 +03:00
}
2018-03-19 12:17:19 +03:00
2018-03-19 12:17:11 +03:00
if ( ! is_power_of_2 ( pdata . page_size ) )
2018-03-19 12:17:12 +03:00
dev_warn ( dev , " page_size looks suspicious (no power of 2)! \n " ) ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:11 +03:00
if ( pdata . flags & AT24_FLAG_TAKE8ADDR )
2008-07-15 00:38:35 +04:00
num_addresses = 8 ;
else
2018-03-19 12:17:11 +03:00
num_addresses = DIV_ROUND_UP ( pdata . byte_len ,
( pdata . flags & AT24_FLAG_ADDR16 ) ? 65536 : 256 ) ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:18 +03:00
if ( ( pdata . flags & AT24_FLAG_SERIAL ) & & ( pdata . flags & AT24_FLAG_MAC ) ) {
dev_err ( dev ,
" invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC. " ) ;
return - EINVAL ;
}
2017-12-18 20:24:43 +03:00
regmap_config . val_bits = 8 ;
2018-03-19 12:17:11 +03:00
regmap_config . reg_bits = ( pdata . flags & AT24_FLAG_ADDR16 ) ? 16 : 8 ;
2018-03-19 12:17:01 +03:00
regmap_config . disable_locking = true ;
2017-11-28 23:51:40 +03:00
2018-03-19 12:17:18 +03:00
regmap = devm_regmap_init_i2c ( client , & regmap_config ) ;
if ( IS_ERR ( regmap ) )
return PTR_ERR ( regmap ) ;
2018-03-19 12:17:13 +03:00
at24_size = sizeof ( * at24 ) + num_addresses * sizeof ( struct at24_client ) ;
at24 = devm_kzalloc ( dev , at24_size , GFP_KERNEL ) ;
2013-05-29 00:00:20 +04:00
if ( ! at24 )
return - ENOMEM ;
2008-07-15 00:38:35 +04:00
mutex_init ( & at24 - > lock ) ;
2018-03-19 12:17:17 +03:00
at24 - > byte_len = pdata . byte_len ;
at24 - > page_size = pdata . page_size ;
at24 - > flags = pdata . flags ;
2008-07-15 00:38:35 +04:00
at24 - > num_addresses = num_addresses ;
2018-03-19 12:17:11 +03:00
at24 - > offset_adj = at24_get_offset_adj ( pdata . flags , pdata . byte_len ) ;
2018-03-19 12:17:18 +03:00
at24 - > client [ 0 ] . client = client ;
at24 - > client [ 0 ] . regmap = regmap ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:12 +03:00
at24 - > wp_gpio = devm_gpiod_get_optional ( dev , " wp " , GPIOD_OUT_HIGH ) ;
2017-12-19 13:28:54 +03:00
if ( IS_ERR ( at24 - > wp_gpio ) )
return PTR_ERR ( at24 - > wp_gpio ) ;
2018-03-19 12:17:11 +03:00
writable = ! ( pdata . flags & AT24_FLAG_READONLY ) ;
2008-07-15 00:38:35 +04:00
if ( writable ) {
2017-12-18 20:16:46 +03:00
at24 - > write_max = min_t ( unsigned int ,
2018-03-19 12:17:11 +03:00
pdata . page_size , at24_io_limit ) ;
2018-03-19 12:17:21 +03:00
if ( ! i2c_fn_i2c & & at24 - > write_max > I2C_SMBUS_BLOCK_MAX )
2017-11-28 23:51:54 +03:00
at24 - > write_max = I2C_SMBUS_BLOCK_MAX ;
2008-07-15 00:38:35 +04:00
}
/* use dummy devices for multiple-address chips */
for ( i = 1 ; i < num_addresses ; i + + ) {
2017-11-28 23:51:40 +03:00
at24 - > client [ i ] . client = i2c_new_dummy ( client - > adapter ,
client - > addr + i ) ;
if ( ! at24 - > client [ i ] . client ) {
2018-03-19 12:17:12 +03:00
dev_err ( dev , " address 0x%02x unavailable \n " ,
client - > addr + i ) ;
2008-07-15 00:38:35 +04:00
err = - EADDRINUSE ;
goto err_clients ;
}
2017-11-28 23:51:40 +03:00
at24 - > client [ i ] . regmap = devm_regmap_init_i2c (
2017-12-18 20:24:43 +03:00
at24 - > client [ i ] . client ,
& regmap_config ) ;
2017-11-28 23:51:40 +03:00
if ( IS_ERR ( at24 - > client [ i ] . regmap ) ) {
err = PTR_ERR ( at24 - > client [ i ] . regmap ) ;
goto err_clients ;
}
2008-07-15 00:38:35 +04:00
}
2016-08-12 14:32:57 +03:00
i2c_set_clientdata ( client , at24 ) ;
2017-10-10 09:00:37 +03:00
/* enable runtime pm */
2018-03-19 12:17:12 +03:00
pm_runtime_set_active ( dev ) ;
pm_runtime_enable ( dev ) ;
2017-10-10 09:00:37 +03:00
2016-08-12 14:32:57 +03:00
/*
* Perform a one - byte test read to verify that the
* chip is functional .
*/
err = at24_read ( at24 , 0 , & test_byte , 1 ) ;
2018-03-19 12:17:12 +03:00
pm_runtime_idle ( dev ) ;
2016-08-12 14:32:57 +03:00
if ( err ) {
err = - ENODEV ;
goto err_clients ;
}
2018-03-19 12:17:12 +03:00
nvmem_config . name = dev_name ( dev ) ;
nvmem_config . dev = dev ;
2018-03-19 12:17:02 +03:00
nvmem_config . read_only = ! writable ;
nvmem_config . root_only = true ;
nvmem_config . owner = THIS_MODULE ;
nvmem_config . compat = true ;
2018-03-19 12:17:12 +03:00
nvmem_config . base_dev = dev ;
2018-03-19 12:17:02 +03:00
nvmem_config . reg_read = at24_read ;
nvmem_config . reg_write = at24_write ;
nvmem_config . priv = at24 ;
nvmem_config . stride = 1 ;
nvmem_config . word_size = 1 ;
2018-03-19 12:17:11 +03:00
nvmem_config . size = pdata . byte_len ;
2018-03-19 12:17:02 +03:00
at24 - > nvmem = nvmem_register ( & nvmem_config ) ;
2016-02-26 22:59:20 +03:00
if ( IS_ERR ( at24 - > nvmem ) ) {
err = PTR_ERR ( at24 - > nvmem ) ;
goto err_clients ;
}
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:12 +03:00
dev_info ( dev , " %u byte %s EEPROM, %s, %u bytes/write \n " ,
2018-03-19 12:17:20 +03:00
pdata . byte_len , client - > name ,
writable ? " writable " : " read-only " , at24 - > write_max ) ;
2008-07-15 00:38:35 +04:00
2009-04-03 03:56:57 +04:00
/* export data to kernel code */
2018-03-19 12:17:11 +03:00
if ( pdata . setup )
pdata . setup ( at24 - > nvmem , pdata . context ) ;
2009-04-03 03:56:57 +04:00
2008-07-15 00:38:35 +04:00
return 0 ;
err_clients :
for ( i = 1 ; i < num_addresses ; i + + )
2017-11-28 23:51:40 +03:00
if ( at24 - > client [ i ] . client )
i2c_unregister_device ( at24 - > client [ i ] . client ) ;
2008-07-15 00:38:35 +04:00
2018-03-19 12:17:12 +03:00
pm_runtime_disable ( dev ) ;
2017-10-10 09:00:37 +03:00
2008-07-15 00:38:35 +04:00
return err ;
}
2012-11-19 22:26:02 +04:00
static int at24_remove ( struct i2c_client * client )
2008-07-15 00:38:35 +04:00
{
struct at24_data * at24 ;
int i ;
at24 = i2c_get_clientdata ( client ) ;
2016-02-26 22:59:20 +03:00
nvmem_unregister ( at24 - > nvmem ) ;
2008-07-15 00:38:35 +04:00
for ( i = 1 ; i < at24 - > num_addresses ; i + + )
2017-11-28 23:51:40 +03:00
i2c_unregister_device ( at24 - > client [ i ] . client ) ;
2008-07-15 00:38:35 +04:00
2017-10-10 09:00:37 +03:00
pm_runtime_disable ( & client - > dev ) ;
pm_runtime_set_suspended ( & client - > dev ) ;
2008-07-15 00:38:35 +04:00
return 0 ;
}
static struct i2c_driver at24_driver = {
. driver = {
. name = " at24 " ,
2017-10-01 13:49:48 +03:00
. of_match_table = at24_of_match ,
2015-10-23 12:16:44 +03:00
. acpi_match_table = ACPI_PTR ( at24_acpi_ids ) ,
2008-07-15 00:38:35 +04:00
} ,
2018-03-19 12:17:15 +03:00
. probe_new = at24_probe ,
2012-11-19 22:21:23 +04:00
. remove = at24_remove ,
2008-07-15 00:38:35 +04:00
. id_table = at24_ids ,
} ;
static int __init at24_init ( void )
{
2017-12-18 20:16:46 +03:00
if ( ! at24_io_limit ) {
pr_err ( " at24: at24_io_limit must not be 0! \n " ) ;
2010-11-17 15:00:49 +03:00
return - EINVAL ;
}
2017-12-18 20:16:46 +03:00
at24_io_limit = rounddown_pow_of_two ( at24_io_limit ) ;
2008-07-15 00:38:35 +04:00
return i2c_add_driver ( & at24_driver ) ;
}
module_init ( at24_init ) ;
static void __exit at24_exit ( void )
{
i2c_del_driver ( & at24_driver ) ;
}
module_exit ( at24_exit ) ;
MODULE_DESCRIPTION ( " Driver for most I2C EEPROMs " ) ;
MODULE_AUTHOR ( " David Brownell and Wolfram Sang " ) ;
MODULE_LICENSE ( " GPL " ) ;