2010-08-11 18:21:03 +02:00
/*
* I2C multiplexer
*
* Copyright ( c ) 2008 - 2009 Rodolfo Giometti < giometti @ linux . it >
* Copyright ( c ) 2008 - 2009 Eurotech S . p . A . < info @ eurotech . it >
*
* This module supports the PCA954x series of I2C multiplexer / switch chips
* made by Philips Semiconductors .
* This includes the :
* PCA9540 , PCA9542 , PCA9543 , PCA9544 , PCA9545 , PCA9546 , PCA9547
* and PCA9548 .
*
* These chips are all controlled via the I2C bus itself , and all have a
* single 8 - bit register . The upstream " parent " bus fans out to two ,
* four , or eight downstream busses or channels ; which of these
* are selected is determined by the chip type and register contents . A
* mux can select only one sub - bus at a time ; a switch can select any
* combination simultaneously .
*
* Based on :
* pca954x . c from Kumar Gala < galak @ kernel . crashing . org >
* Copyright ( C ) 2006
*
* Based on :
* pca954x . c from Ken Harrenstien
* Copyright ( C ) 2004 Google , Inc . ( Ken Harrenstien )
*
* Based on :
* i2c - virtual_cb . c from Brian Kuschak < bkuschak @ yahoo . com >
* and
2014-01-29 20:40:08 +01:00
* pca9540 . c from Jean Delvare < jdelvare @ suse . de > .
2010-08-11 18:21:03 +02:00
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# include <linux/device.h>
2013-11-29 01:51:25 +01:00
# include <linux/gpio.h>
2010-08-11 18:21:03 +02:00
# include <linux/i2c.h>
# include <linux/i2c-mux.h>
# include <linux/i2c/pca954x.h>
2013-11-29 01:51:22 +01:00
# include <linux/module.h>
2013-11-29 01:51:25 +01:00
# include <linux/of_gpio.h>
2013-11-29 01:51:22 +01:00
# include <linux/slab.h>
2010-08-11 18:21:03 +02:00
# define PCA954X_MAX_NCHANS 8
enum pca_type {
pca_9540 ,
pca_9542 ,
pca_9543 ,
pca_9544 ,
pca_9545 ,
pca_9546 ,
pca_9547 ,
pca_9548 ,
} ;
struct pca954x {
enum pca_type type ;
struct i2c_adapter * virt_adaps [ PCA954X_MAX_NCHANS ] ;
u8 last_chan ; /* last register value */
} ;
struct chip_desc {
u8 nchans ;
u8 enable ; /* used for muxes only */
enum muxtype {
pca954x_ismux = 0 ,
pca954x_isswi
} muxtype ;
} ;
/* Provide specs for the PCA954x types we know about */
static const struct chip_desc chips [ ] = {
[ pca_9540 ] = {
. nchans = 2 ,
. enable = 0x4 ,
. muxtype = pca954x_ismux ,
} ,
[ pca_9543 ] = {
. nchans = 2 ,
. muxtype = pca954x_isswi ,
} ,
[ pca_9544 ] = {
. nchans = 4 ,
. enable = 0x4 ,
. muxtype = pca954x_ismux ,
} ,
[ pca_9545 ] = {
. nchans = 4 ,
. muxtype = pca954x_isswi ,
} ,
[ pca_9547 ] = {
. nchans = 8 ,
. enable = 0x8 ,
. muxtype = pca954x_ismux ,
} ,
[ pca_9548 ] = {
. nchans = 8 ,
. muxtype = pca954x_isswi ,
} ,
} ;
static const struct i2c_device_id pca954x_id [ ] = {
{ " pca9540 " , pca_9540 } ,
{ " pca9542 " , pca_9540 } ,
{ " pca9543 " , pca_9543 } ,
{ " pca9544 " , pca_9544 } ,
{ " pca9545 " , pca_9545 } ,
{ " pca9546 " , pca_9545 } ,
{ " pca9547 " , pca_9547 } ,
{ " pca9548 " , pca_9548 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , pca954x_id ) ;
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
for this as they will try to lock adapter a second time */
static int pca954x_reg_write ( struct i2c_adapter * adap ,
struct i2c_client * client , u8 val )
{
int ret = - ENODEV ;
if ( adap - > algo - > master_xfer ) {
struct i2c_msg msg ;
char buf [ 1 ] ;
msg . addr = client - > addr ;
msg . flags = 0 ;
msg . len = 1 ;
buf [ 0 ] = val ;
msg . buf = buf ;
ret = adap - > algo - > master_xfer ( adap , & msg , 1 ) ;
} else {
union i2c_smbus_data data ;
ret = adap - > algo - > smbus_xfer ( adap , client - > addr ,
client - > flags ,
I2C_SMBUS_WRITE ,
val , I2C_SMBUS_BYTE , & data ) ;
}
return ret ;
}
static int pca954x_select_chan ( struct i2c_adapter * adap ,
void * client , u32 chan )
{
struct pca954x * data = i2c_get_clientdata ( client ) ;
const struct chip_desc * chip = & chips [ data - > type ] ;
u8 regval ;
int ret = 0 ;
/* we make switches look like muxes, not sure how to be smarter */
if ( chip - > muxtype = = pca954x_ismux )
regval = chan | chip - > enable ;
else
regval = 1 < < chan ;
/* Only select the channel if its different from the last channel */
if ( data - > last_chan ! = regval ) {
ret = pca954x_reg_write ( adap , client , regval ) ;
data - > last_chan = regval ;
}
return ret ;
}
static int pca954x_deselect_mux ( struct i2c_adapter * adap ,
void * client , u32 chan )
{
struct pca954x * data = i2c_get_clientdata ( client ) ;
/* Deselect active channel */
data - > last_chan = 0 ;
return pca954x_reg_write ( adap , client , data - > last_chan ) ;
}
/*
* I2C init / probing / exit functions
*/
2010-10-24 18:16:59 +02:00
static int pca954x_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2010-08-11 18:21:03 +02:00
{
struct i2c_adapter * adap = to_i2c_adapter ( client - > dev . parent ) ;
2013-07-30 16:59:33 +09:00
struct pca954x_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2013-11-29 01:51:25 +01:00
struct device_node * np = client - > dev . of_node ;
2012-10-05 22:23:51 +02:00
int num , force , class ;
2010-08-11 18:21:03 +02:00
struct pca954x * data ;
2013-11-29 01:51:23 +01:00
int ret ;
2010-08-11 18:21:03 +02:00
if ( ! i2c_check_functionality ( adap , I2C_FUNC_SMBUS_BYTE ) )
2013-11-29 01:51:23 +01:00
return - ENODEV ;
2010-08-11 18:21:03 +02:00
2013-11-29 01:51:23 +01:00
data = devm_kzalloc ( & client - > dev , sizeof ( struct pca954x ) , GFP_KERNEL ) ;
if ( ! data )
return - ENOMEM ;
2010-08-11 18:21:03 +02:00
i2c_set_clientdata ( client , data ) ;
2013-11-29 01:51:25 +01:00
if ( IS_ENABLED ( CONFIG_OF ) & & np ) {
enum of_gpio_flags flags ;
int gpio ;
/* Get the mux out of reset if a reset GPIO is specified. */
gpio = of_get_named_gpio_flags ( np , " reset-gpio " , 0 , & flags ) ;
if ( gpio_is_valid ( gpio ) ) {
ret = devm_gpio_request_one ( & client - > dev , gpio ,
flags & OF_GPIO_ACTIVE_LOW ?
GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW ,
" pca954x reset " ) ;
if ( ret < 0 )
return ret ;
}
}
2011-06-29 11:36:11 +02:00
/* Write the mux register at addr to verify
* that the mux is in fact present . This also
* initializes the mux to disconnected state .
2010-08-11 18:21:03 +02:00
*/
2011-06-29 11:36:11 +02:00
if ( i2c_smbus_write_byte ( client , 0 ) < 0 ) {
2010-08-11 18:21:03 +02:00
dev_warn ( & client - > dev , " probe failed \n " ) ;
2013-11-29 01:51:23 +01:00
return - ENODEV ;
2010-08-11 18:21:03 +02:00
}
data - > type = id - > driver_data ;
data - > last_chan = 0 ; /* force the first selection */
/* Now create an adapter for each channel */
for ( num = 0 ; num < chips [ data - > type ] . nchans ; num + + ) {
force = 0 ; /* dynamic adap number */
2012-10-05 22:23:51 +02:00
class = 0 ; /* no class by default */
2010-08-11 18:21:03 +02:00
if ( pdata ) {
2012-10-05 22:23:51 +02:00
if ( num < pdata - > num_modes ) {
2010-08-11 18:21:03 +02:00
/* force static number */
force = pdata - > modes [ num ] . adap_id ;
2012-10-05 22:23:51 +02:00
class = pdata - > modes [ num ] . class ;
} else
2010-08-11 18:21:03 +02:00
/* discard unconfigured channels */
break ;
}
data - > virt_adaps [ num ] =
2012-04-12 14:14:22 -07:00
i2c_add_mux_adapter ( adap , & client - > dev , client ,
2012-10-05 22:23:51 +02:00
force , num , class , pca954x_select_chan ,
2010-08-11 18:21:03 +02:00
( pdata & & pdata - > modes [ num ] . deselect_on_exit )
? pca954x_deselect_mux : NULL ) ;
if ( data - > virt_adaps [ num ] = = NULL ) {
ret = - ENODEV ;
dev_err ( & client - > dev ,
" failed to register multiplexed adapter "
" %d as bus %d \n " , num , force ) ;
goto virt_reg_failed ;
}
}
dev_info ( & client - > dev ,
" registered %d multiplexed busses for I2C %s %s \n " ,
num , chips [ data - > type ] . muxtype = = pca954x_ismux
? " mux " : " switch " , client - > name ) ;
return 0 ;
virt_reg_failed :
for ( num - - ; num > = 0 ; num - - )
i2c_del_mux_adapter ( data - > virt_adaps [ num ] ) ;
return ret ;
}
2010-10-24 18:16:59 +02:00
static int pca954x_remove ( struct i2c_client * client )
2010-08-11 18:21:03 +02:00
{
struct pca954x * data = i2c_get_clientdata ( client ) ;
const struct chip_desc * chip = & chips [ data - > type ] ;
2013-03-09 08:16:48 +00:00
int i ;
2010-08-11 18:21:03 +02:00
for ( i = 0 ; i < chip - > nchans ; + + i )
if ( data - > virt_adaps [ i ] ) {
2013-03-09 08:16:48 +00:00
i2c_del_mux_adapter ( data - > virt_adaps [ i ] ) ;
2010-08-11 18:21:03 +02:00
data - > virt_adaps [ i ] = NULL ;
}
return 0 ;
}
static struct i2c_driver pca954x_driver = {
. driver = {
. name = " pca954x " ,
. owner = THIS_MODULE ,
} ,
. probe = pca954x_probe ,
2010-10-24 18:16:59 +02:00
. remove = pca954x_remove ,
2010-08-11 18:21:03 +02:00
. id_table = pca954x_id ,
} ;
2012-03-26 21:47:19 +02:00
module_i2c_driver ( pca954x_driver ) ;
2010-08-11 18:21:03 +02:00
MODULE_AUTHOR ( " Rodolfo Giometti <giometti@linux.it> " ) ;
MODULE_DESCRIPTION ( " PCA954x I2C mux/switch driver " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;