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
*
* 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 .
*/
# 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>
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 {
struct at24_platform_data chip ;
2016-06-06 11:48:46 +03:00
2008-07-15 00:38:35 +04:00
/*
* 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
2016-02-26 22:59:20 +03:00
struct nvmem_config nvmem_config ;
struct nvmem_device * nvmem ;
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
# define AT24_SIZE_BYTELEN 5
# define AT24_SIZE_FLAGS 8
# define AT24_BITMASK(x) (BIT(x) - 1)
/* create non-zero magic value for given eeprom parameters */
2017-12-13 13:56:23 +03:00
# define AT24_DEVICE_MAGIC(_len, _flags) \
( ( 1 < < AT24_SIZE_FLAGS | ( _flags ) ) \
2008-07-15 00:38:35 +04:00
< < AT24_SIZE_BYTELEN | ilog2 ( _len ) )
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 )
2008-07-15 00:38:35 +04:00
static const struct i2c_device_id at24_ids [ ] = {
/* needs 8 addresses as A0-A2 are ignored */
2016-06-06 11:48:43 +03:00
{ " 24c00 " , AT24_DEVICE_MAGIC ( 128 / 8 , AT24_FLAG_TAKE8ADDR ) } ,
2008-07-15 00:38:35 +04:00
/* old variants can't be handled with this generic entry! */
2016-06-06 11:48:43 +03:00
{ " 24c01 " , AT24_DEVICE_MAGIC ( 1024 / 8 , 0 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs01 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:43 +03:00
{ " 24c02 " , AT24_DEVICE_MAGIC ( 2048 / 8 , 0 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs02 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:54 +03:00
{ " 24mac402 " , AT24_DEVICE_MAGIC ( 48 / 8 ,
AT24_FLAG_MAC | AT24_FLAG_READONLY ) } ,
{ " 24mac602 " , AT24_DEVICE_MAGIC ( 64 / 8 ,
AT24_FLAG_MAC | AT24_FLAG_READONLY ) } ,
2008-07-15 00:38:35 +04:00
/* spd is a 24c02 in memory DIMMs */
2016-06-06 11:48:43 +03:00
{ " spd " , AT24_DEVICE_MAGIC ( 2048 / 8 ,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO ) } ,
{ " 24c04 " , AT24_DEVICE_MAGIC ( 4096 / 8 , 0 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs04 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) } ,
2008-07-15 00:38:35 +04:00
/* 24rf08 quirk is handled at i2c-core */
2016-06-06 11:48:43 +03:00
{ " 24c08 " , AT24_DEVICE_MAGIC ( 8192 / 8 , 0 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs08 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:43 +03:00
{ " 24c16 " , AT24_DEVICE_MAGIC ( 16384 / 8 , 0 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs16 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_SERIAL | AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:43 +03:00
{ " 24c32 " , AT24_DEVICE_MAGIC ( 32768 / 8 , AT24_FLAG_ADDR16 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs32 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_ADDR16 |
AT24_FLAG_SERIAL |
AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:43 +03:00
{ " 24c64 " , AT24_DEVICE_MAGIC ( 65536 / 8 , AT24_FLAG_ADDR16 ) } ,
2016-06-06 11:48:51 +03:00
{ " 24cs64 " , AT24_DEVICE_MAGIC ( 16 ,
AT24_FLAG_ADDR16 |
AT24_FLAG_SERIAL |
AT24_FLAG_READONLY ) } ,
2016-06-06 11:48:43 +03:00
{ " 24c128 " , AT24_DEVICE_MAGIC ( 131072 / 8 , AT24_FLAG_ADDR16 ) } ,
{ " 24c256 " , AT24_DEVICE_MAGIC ( 262144 / 8 , AT24_FLAG_ADDR16 ) } ,
{ " 24c512 " , AT24_DEVICE_MAGIC ( 524288 / 8 , AT24_FLAG_ADDR16 ) } ,
{ " 24c1024 " , AT24_DEVICE_MAGIC ( 1048576 / 8 , AT24_FLAG_ADDR16 ) } ,
2008-07-15 00:38:35 +04:00
{ " at24 " , 0 } ,
{ /* 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 [ ] = {
{
. compatible = " atmel,24c00 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 128 / 8 , AT24_FLAG_TAKE8ADDR )
} ,
{
. compatible = " atmel,24c01 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 1024 / 8 , 0 )
} ,
{
. compatible = " atmel,24c02 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 2048 / 8 , 0 )
} ,
{
. compatible = " atmel,spd " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 2048 / 8 ,
AT24_FLAG_READONLY | AT24_FLAG_IRUGO )
} ,
{
. compatible = " atmel,24c04 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 4096 / 8 , 0 )
} ,
{
. compatible = " atmel,24c08 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 8192 / 8 , 0 )
} ,
{
. compatible = " atmel,24c16 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 16384 / 8 , 0 )
} ,
{
. compatible = " atmel,24c32 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 32768 / 8 , AT24_FLAG_ADDR16 )
} ,
{
. compatible = " atmel,24c64 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 65536 / 8 , AT24_FLAG_ADDR16 )
} ,
{
. compatible = " atmel,24c128 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 131072 / 8 , AT24_FLAG_ADDR16 )
} ,
{
. compatible = " atmel,24c256 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 262144 / 8 , AT24_FLAG_ADDR16 )
} ,
{
. compatible = " atmel,24c512 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 524288 / 8 , AT24_FLAG_ADDR16 )
} ,
{
. compatible = " atmel,24c1024 " ,
. data = ( void * ) AT24_DEVICE_MAGIC ( 1048576 / 8 , AT24_FLAG_ADDR16 )
} ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , at24_of_match ) ;
2015-10-23 12:16:44 +03:00
static const struct acpi_device_id at24_acpi_ids [ ] = {
{ " INT3499 " , AT24_DEVICE_MAGIC ( 8192 / 8 , 0 ) } ,
{ }
} ;
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
if ( at24 - > chip . flags & AT24_FLAG_ADDR16 ) {
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
}
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 .
*/
if ( at24 - > chip . flags & AT24_FLAG_NO_RDROL ) {
bits = ( at24 - > chip . flags & AT24_FLAG_ADDR16 ) ? 16 : 8 ;
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 */
next_page = roundup ( offset + 1 , at24 - > chip . page_size ) ;
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 )
{
struct at24_data * at24 = priv ;
2017-11-28 23:51:40 +03:00
struct device * dev = & at24 - > client [ 0 ] . client - > 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
if ( unlikely ( ! count ) )
return count ;
2017-11-24 09:47:50 +03:00
if ( off + count > at24 - > chip . byte_len )
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 ) {
int status ;
2017-11-28 23:51:50 +03:00
status = at24_regmap_read ( at24 , buf , off , count ) ;
2016-06-06 11:48:44 +03:00
if ( status < 0 ) {
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2016-06-06 11:48:44 +03:00
return status ;
}
buf + = status ;
off + = status ;
count - = status ;
}
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
{
2016-04-24 22:28:06 +03:00
struct at24_data * at24 = priv ;
2017-11-28 23:51:40 +03:00
struct device * dev = & at24 - > client [ 0 ] . client - > 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
if ( unlikely ( ! count ) )
2016-04-24 22:28:06 +03:00
return - EINVAL ;
2008-07-15 00:38:35 +04:00
2017-11-24 09:47:50 +03:00
if ( off + count > at24 - > chip . byte_len )
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 ) ;
while ( count ) {
2016-04-24 22:28:06 +03:00
int status ;
2008-07-15 00:38:35 +04:00
2017-11-28 23:51:45 +03:00
status = at24_regmap_write ( at24 , buf , off , count ) ;
2016-04-24 22:28:06 +03:00
if ( status < 0 ) {
mutex_unlock ( & at24 - > lock ) ;
2017-12-01 21:37:12 +03:00
pm_runtime_put ( dev ) ;
2016-04-24 22:28:06 +03:00
return status ;
2008-07-15 00:38:35 +04:00
}
buf + = status ;
off + = status ;
count - = status ;
}
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 ;
}
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
static void at24_get_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
}
}
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 ;
}
}
2017-11-28 23:51:40 +03:00
static const struct regmap_config regmap_config_8 = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
static const struct regmap_config regmap_config_16 = {
. reg_bits = 16 ,
. val_bits = 8 ,
} ;
2008-07-15 00:38:35 +04:00
static int at24_probe ( struct i2c_client * client , const struct i2c_device_id * id )
{
struct at24_platform_data chip ;
2015-10-23 12:16:44 +03:00
kernel_ulong_t magic = 0 ;
2008-07-15 00:38:35 +04:00
bool writable ;
struct at24_data * at24 ;
int err ;
2017-12-13 13:56:23 +03:00
unsigned int i , num_addresses ;
2017-11-28 23:51:40 +03:00
const struct regmap_config * config ;
2016-08-12 14:32:57 +03:00
u8 test_byte ;
2008-07-15 00:38:35 +04:00
if ( client - > dev . platform_data ) {
chip = * ( struct at24_platform_data * ) client - > dev . platform_data ;
} else {
2017-10-01 13:49:48 +03:00
/*
* 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 ( client - > dev . of_node & &
of_match_device ( at24_of_match , & client - > dev ) ) {
magic = ( kernel_ulong_t )
of_device_get_match_data ( & client - > dev ) ;
} else if ( id ) {
2015-10-23 12:16:44 +03:00
magic = id - > driver_data ;
} else {
const struct acpi_device_id * aid ;
aid = acpi_match_device ( at24_acpi_ids , & client - > dev ) ;
if ( aid )
magic = aid - > driver_data ;
}
if ( ! magic )
2013-05-29 00:00:20 +04:00
return - ENODEV ;
2008-07-15 00:38:35 +04:00
chip . byte_len = BIT ( magic & AT24_BITMASK ( AT24_SIZE_BYTELEN ) ) ;
magic > > = AT24_SIZE_BYTELEN ;
chip . flags = magic & AT24_BITMASK ( AT24_SIZE_FLAGS ) ;
2009-04-03 03:56:57 +04: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
at24_get_pdata ( & client - > dev , & chip ) ;
2010-11-17 15:00:48 +03:00
2009-04-03 03:56:57 +04:00
chip . setup = NULL ;
chip . context = NULL ;
2008-07-15 00:38:35 +04:00
}
if ( ! is_power_of_2 ( chip . byte_len ) )
dev_warn ( & client - > dev ,
" byte_len looks suspicious (no power of 2)! \n " ) ;
2010-11-17 15:00:49 +03:00
if ( ! chip . page_size ) {
dev_err ( & client - > 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
}
2008-07-15 00:38:35 +04:00
if ( ! is_power_of_2 ( chip . page_size ) )
dev_warn ( & client - > dev ,
" page_size looks suspicious (no power of 2)! \n " ) ;
2017-11-28 00:06:13 +03:00
/*
* REVISIT : the size of the EUI - 48 byte array is 6 in at24mac402 , while
* the call to ilog2 ( ) in AT24_DEVICE_MAGIC ( ) rounds it down to 4.
*
* Eventually we ' ll get rid of the magic values altoghether in favor of
* real structs , but for now just manually set the right size .
*/
if ( chip . flags & AT24_FLAG_MAC & & chip . byte_len = = 4 )
chip . byte_len = 6 ;
2017-11-28 23:51:54 +03:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) & &
! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK ) )
chip . page_size = 1 ;
2014-10-09 13:07:58 +04:00
2008-07-15 00:38:35 +04:00
if ( chip . flags & AT24_FLAG_TAKE8ADDR )
num_addresses = 8 ;
else
num_addresses = DIV_ROUND_UP ( chip . byte_len ,
( chip . flags & AT24_FLAG_ADDR16 ) ? 65536 : 256 ) ;
2017-11-28 23:51:40 +03:00
if ( chip . flags & AT24_FLAG_ADDR16 )
config = & regmap_config_16 ;
else
config = & regmap_config_8 ;
2013-05-29 00:00:20 +04:00
at24 = devm_kzalloc ( & client - > dev , sizeof ( struct at24_data ) +
2017-11-28 23:51:40 +03:00
num_addresses * sizeof ( struct at24_client ) , 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 ) ;
at24 - > chip = chip ;
at24 - > num_addresses = num_addresses ;
2017-11-28 23:51:50 +03:00
at24 - > offset_adj = at24_get_offset_adj ( chip . flags , chip . byte_len ) ;
2008-07-15 00:38:35 +04:00
2017-11-28 23:51:40 +03:00
at24 - > client [ 0 ] . client = client ;
at24 - > client [ 0 ] . regmap = devm_regmap_init_i2c ( client , config ) ;
if ( IS_ERR ( at24 - > client [ 0 ] . regmap ) )
return PTR_ERR ( at24 - > client [ 0 ] . regmap ) ;
2016-06-06 11:48:54 +03:00
if ( ( chip . flags & AT24_FLAG_SERIAL ) & & ( chip . flags & AT24_FLAG_MAC ) ) {
dev_err ( & client - > dev ,
" invalid device data - cannot have both AT24_FLAG_SERIAL & AT24_FLAG_MAC. " ) ;
return - EINVAL ;
}
2008-07-15 00:38:35 +04:00
writable = ! ( chip . flags & AT24_FLAG_READONLY ) ;
if ( writable ) {
2017-12-18 20:16:46 +03:00
at24 - > write_max = min_t ( unsigned int ,
chip . page_size , at24_io_limit ) ;
2017-11-28 23:51:54 +03:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) & &
at24 - > write_max > I2C_SMBUS_BLOCK_MAX )
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 ) {
2008-07-15 00:38:35 +04:00
dev_err ( & client - > dev , " address 0x%02x unavailable \n " ,
client - > addr + i ) ;
err = - EADDRINUSE ;
goto err_clients ;
}
2017-11-28 23:51:40 +03:00
at24 - > client [ i ] . regmap = devm_regmap_init_i2c (
at24 - > client [ i ] . client , config ) ;
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 */
pm_runtime_set_active ( & client - > dev ) ;
pm_runtime_enable ( & client - > dev ) ;
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 ) ;
2017-10-10 09:00:37 +03:00
pm_runtime_idle ( & client - > dev ) ;
2016-08-12 14:32:57 +03:00
if ( err ) {
err = - ENODEV ;
goto err_clients ;
}
2016-02-26 22:59:20 +03:00
at24 - > nvmem_config . name = dev_name ( & client - > dev ) ;
at24 - > nvmem_config . dev = & client - > dev ;
at24 - > nvmem_config . read_only = ! writable ;
at24 - > nvmem_config . root_only = true ;
at24 - > nvmem_config . owner = THIS_MODULE ;
at24 - > nvmem_config . compat = true ;
at24 - > nvmem_config . base_dev = & client - > dev ;
2016-04-24 22:28:06 +03:00
at24 - > nvmem_config . reg_read = at24_read ;
at24 - > nvmem_config . reg_write = at24_write ;
at24 - > nvmem_config . priv = at24 ;
2017-12-04 04:54:41 +03:00
at24 - > nvmem_config . stride = 1 ;
2016-04-24 22:28:06 +03:00
at24 - > nvmem_config . word_size = 1 ;
at24 - > nvmem_config . size = chip . byte_len ;
2016-02-26 22:59:20 +03:00
at24 - > nvmem = nvmem_register ( & at24 - > nvmem_config ) ;
if ( IS_ERR ( at24 - > nvmem ) ) {
err = PTR_ERR ( at24 - > nvmem ) ;
goto err_clients ;
}
2008-07-15 00:38:35 +04:00
2016-02-26 22:59:20 +03:00
dev_info ( & client - > dev , " %u byte %s EEPROM, %s, %u bytes/write \n " ,
chip . byte_len , client - > name ,
2010-11-17 15:00:48 +03:00
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 */
if ( chip . setup )
2016-02-26 22:59:24 +03:00
chip . setup ( at24 - > nvmem , chip . 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
2017-10-10 09:00:37 +03:00
pm_runtime_disable ( & client - > dev ) ;
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
} ,
. probe = 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 " ) ;