2005-06-03 21:03:27 +04:00
/*
2010-05-14 00:05:47 +04:00
* max6875 . c - driver for MAX6874 / MAX6875
*
* Copyright ( C ) 2005 Ben Gardner < bgardner @ wabtec . com >
*
* Based on eeprom . c
*
* The MAX6875 has a bank of registers and two banks of EEPROM .
* Address ranges are defined as follows :
* * 0x0000 - 0x0046 = configuration registers
* * 0x8000 - 0x8046 = configuration EEPROM
* * 0x8100 - 0x82FF = user EEPROM
*
* This driver makes the user EEPROM available for read .
*
* The registers & config EEPROM should be accessed via i2c - dev .
*
* The MAX6875 ignores the lowest address bit , so each chip responds to
* two addresses - 0x50 / 0x51 and 0x52 / 0x53 .
*
* Note that the MAX6875 uses i2c_smbus_write_byte_data ( ) to set the read
* address , so this driver is destructive if loaded for the wrong EEPROM chip .
*
* 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 ; version 2 of the License .
*/
2005-06-03 21:03:27 +04:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/slab.h>
# include <linux/i2c.h>
2006-01-19 01:16:04 +03:00
# include <linux/mutex.h>
2005-06-03 21:03:27 +04:00
/* The MAX6875 can only read/write 16 bytes at a time */
# define SLICE_SIZE 16
# define SLICE_BITS 4
/* USER EEPROM is at addresses 0x8100 - 0x82FF */
# define USER_EEPROM_BASE 0x8100
# define USER_EEPROM_SIZE 0x0200
# define USER_EEPROM_SLICES 32
/* MAX6875 commands */
2005-07-12 22:21:11 +04:00
# define MAX6875_CMD_BLK_READ 0x84
2005-06-03 21:03:27 +04:00
/* Each client has this additional data */
struct max6875_data {
2008-07-16 21:30:07 +04:00
struct i2c_client * fake_client ;
2006-01-19 01:16:04 +03:00
struct mutex update_lock ;
2005-07-12 22:21:11 +04:00
u32 valid ;
u8 data [ USER_EEPROM_SIZE ] ;
unsigned long last_updated [ USER_EEPROM_SLICES ] ;
2005-06-03 21:03:27 +04:00
} ;
2005-07-12 22:21:11 +04:00
static void max6875_update_slice ( struct i2c_client * client , int slice )
2005-06-03 21:03:27 +04:00
{
struct max6875_data * data = i2c_get_clientdata ( client ) ;
2005-07-12 22:21:11 +04:00
int i , j , addr ;
u8 * buf ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
if ( slice > = USER_EEPROM_SLICES )
return ;
2005-06-03 21:03:27 +04:00
2006-01-19 01:16:04 +03:00
mutex_lock ( & data - > update_lock ) ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
buf = & data - > data [ slice < < SLICE_BITS ] ;
if ( ! ( data - > valid & ( 1 < < slice ) ) | |
time_after ( jiffies , data - > last_updated [ slice ] ) ) {
2005-07-27 21:43:03 +04:00
dev_dbg ( & client - > dev , " Starting update of slice %u \n " , slice ) ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
data - > valid & = ~ ( 1 < < slice ) ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
addr = USER_EEPROM_BASE + ( slice < < SLICE_BITS ) ;
/* select the eeprom address */
if ( i2c_smbus_write_byte_data ( client , addr > > 8 , addr & 0xFF ) ) {
dev_err ( & client - > dev , " address set failed \n " ) ;
goto exit_up ;
2005-06-03 21:03:27 +04:00
}
2005-07-12 22:21:11 +04:00
if ( i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_READ_I2C_BLOCK ) ) {
if ( i2c_smbus_read_i2c_block_data ( client ,
MAX6875_CMD_BLK_READ ,
i2c: Fix the i2c_smbus_read_i2c_block_data() prototype
Let the drivers specify how many bytes they want to read with
i2c_smbus_read_i2c_block_data(). So far, the block count was
hard-coded to I2C_SMBUS_BLOCK_MAX (32), which did not make much sense.
Many driver authors complained about this before, and I believe it's
about time to fix it. Right now, authors have to do technically stupid
things, such as individual byte reads or full-fledged I2C messaging,
to work around the problem. We do not want to encourage that.
I even found that some bus drivers (e.g. i2c-amd8111) already
implemented I2C block read the "right" way, that is, they didn't
follow the old, broken standard. The fact that it was never noticed
before just shows how little i2c_smbus_read_i2c_block_data() was used,
which isn't that surprising given how broken its prototype was so far.
There are some obvious compatiblity considerations:
* This changes the i2c_smbus_read_i2c_block_data() prototype. Users
outside the kernel tree will notice at compilation time, and will
have to update their code.
* User-space has access to i2c_smbus_xfer() directly using i2c-dev, so
the changed expectations would affect tools such as i2cdump. In order
to preserve binary compatibility, we give I2C_SMBUS_I2C_BLOCK_DATA
a new numeric value, and define I2C_SMBUS_I2C_BLOCK_BROKEN with the
old numeric value. When i2c-dev receives a transaction with the
old value, it can convert it to the new format on the fly.
Signed-off-by: Jean Delvare <khali@linux-fr.org>
2007-07-12 16:12:29 +04:00
SLICE_SIZE ,
2005-07-12 22:21:11 +04:00
buf ) ! = SLICE_SIZE ) {
goto exit_up ;
2005-06-03 21:03:27 +04:00
}
} else {
2005-07-12 22:21:11 +04:00
for ( i = 0 ; i < SLICE_SIZE ; i + + ) {
2005-06-03 21:03:27 +04:00
j = i2c_smbus_read_byte ( client ) ;
2005-07-12 22:21:11 +04:00
if ( j < 0 ) {
goto exit_up ;
2005-06-03 21:03:27 +04:00
}
2005-07-12 22:21:11 +04:00
buf [ i ] = j ;
2005-06-03 21:03:27 +04:00
}
}
2005-07-12 22:21:11 +04:00
data - > last_updated [ slice ] = jiffies ;
data - > valid | = ( 1 < < slice ) ;
2005-06-03 21:03:27 +04:00
}
2005-07-12 22:21:11 +04:00
exit_up :
2006-01-19 01:16:04 +03:00
mutex_unlock ( & data - > update_lock ) ;
2005-06-03 21:03:27 +04:00
}
2010-05-13 05:28:57 +04:00
static ssize_t max6875_read ( struct file * filp , struct kobject * kobj ,
2007-06-09 09:57:22 +04:00
struct bin_attribute * bin_attr ,
char * buf , loff_t off , size_t count )
2005-06-03 21:03:27 +04:00
{
2005-07-12 22:21:11 +04:00
struct i2c_client * client = kobj_to_i2c_client ( kobj ) ;
2005-06-03 21:03:27 +04:00
struct max6875_data * data = i2c_get_clientdata ( client ) ;
2005-07-12 22:21:11 +04:00
int slice , max_slice ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
/* refresh slices which contain requested bytes */
max_slice = ( off + count - 1 ) > > SLICE_BITS ;
for ( slice = ( off > > SLICE_BITS ) ; slice < = max_slice ; slice + + )
max6875_update_slice ( client , slice ) ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
memcpy ( buf , & data - > data [ off ] , count ) ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
return count ;
2005-06-03 21:03:27 +04:00
}
2017-08-02 12:10:06 +03:00
static const struct bin_attribute user_eeprom_attr = {
2005-06-03 21:03:27 +04:00
. attr = {
2005-07-12 22:21:11 +04:00
. name = " eeprom " ,
. mode = S_IRUGO ,
2005-06-03 21:03:27 +04:00
} ,
2005-07-12 22:21:11 +04:00
. size = USER_EEPROM_SIZE ,
. read = max6875_read ,
2005-06-03 21:03:27 +04:00
} ;
2009-10-05 00:53:41 +04:00
static int max6875_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2005-06-03 21:03:27 +04:00
{
2008-07-16 21:30:07 +04:00
struct i2c_adapter * adapter = client - > adapter ;
2009-10-05 00:53:41 +04:00
struct max6875_data * data ;
int err ;
2005-06-03 21:03:27 +04:00
2005-07-27 21:43:14 +04:00
if ( ! i2c_check_functionality ( adapter , I2C_FUNC_SMBUS_WRITE_BYTE_DATA
2005-07-12 22:21:11 +04:00
| I2C_FUNC_SMBUS_READ_BYTE ) )
2008-07-16 21:30:07 +04:00
return - ENODEV ;
2005-07-12 22:21:11 +04:00
2009-10-05 00:53:41 +04:00
/* Only bind to even addresses */
2008-07-16 21:30:07 +04:00
if ( client - > addr & 1 )
return - ENODEV ;
2005-10-18 01:09:43 +04:00
if ( ! ( data = kzalloc ( sizeof ( struct max6875_data ) , GFP_KERNEL ) ) )
2005-07-12 22:21:11 +04:00
return - ENOMEM ;
2005-06-03 21:03:27 +04:00
2005-07-12 22:21:11 +04:00
/* A fake client is created on the odd address */
2008-07-16 21:30:07 +04:00
data - > fake_client = i2c_new_dummy ( client - > adapter , client - > addr + 1 ) ;
if ( ! data - > fake_client ) {
2005-07-12 22:21:11 +04:00
err = - ENOMEM ;
2008-07-16 21:30:07 +04:00
goto exit_kfree ;
2005-07-12 22:21:11 +04:00
}
/* Init real i2c_client */
2008-07-16 21:30:07 +04:00
i2c_set_clientdata ( client , data ) ;
2006-01-19 01:16:04 +03:00
mutex_init ( & data - > update_lock ) ;
2005-06-03 21:03:27 +04:00
2008-07-16 21:30:07 +04:00
err = sysfs_create_bin_file ( & client - > dev . kobj , & user_eeprom_attr ) ;
2006-09-04 00:20:24 +04:00
if ( err )
2008-07-16 21:30:07 +04:00
goto exit_remove_fake ;
2005-06-03 21:03:27 +04:00
return 0 ;
2008-07-16 21:30:07 +04:00
exit_remove_fake :
i2c_unregister_device ( data - > fake_client ) ;
exit_kfree :
2005-06-03 21:03:27 +04:00
kfree ( data ) ;
return err ;
}
2008-07-16 21:30:07 +04:00
static int max6875_remove ( struct i2c_client * client )
2005-06-03 21:03:27 +04:00
{
2006-09-04 00:20:24 +04:00
struct max6875_data * data = i2c_get_clientdata ( client ) ;
2008-07-16 21:30:07 +04:00
i2c_unregister_device ( data - > fake_client ) ;
2005-06-03 21:03:27 +04:00
2008-07-16 21:30:07 +04:00
sysfs_remove_bin_file ( & client - > dev . kobj , & user_eeprom_attr ) ;
kfree ( data ) ;
2006-09-04 00:20:24 +04:00
2005-06-03 21:03:27 +04:00
return 0 ;
}
2008-07-16 21:30:07 +04:00
static const struct i2c_device_id max6875_id [ ] = {
{ " max6875 " , 0 } ,
{ }
} ;
2015-08-07 15:04:19 +03:00
MODULE_DEVICE_TABLE ( i2c , max6875_id ) ;
2008-07-16 21:30:07 +04:00
static struct i2c_driver max6875_driver = {
. driver = {
. name = " max6875 " ,
} ,
. probe = max6875_probe ,
. remove = max6875_remove ,
. id_table = max6875_id ,
} ;
2012-01-22 11:36:45 +04:00
module_i2c_driver ( max6875_driver ) ;
2005-06-03 21:03:27 +04:00
MODULE_AUTHOR ( " Ben Gardner <bgardner@wabtec.com> " ) ;
MODULE_DESCRIPTION ( " MAX6875 driver " ) ;
MODULE_LICENSE ( " GPL " ) ;