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 .
*/
2016-11-29 17:12:43 +07:00
# include <linux/acpi.h>
2010-08-11 18:21:03 +02:00
# include <linux/device.h>
2014-06-04 18:56:32 +02:00
# include <linux/gpio/consumer.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>
2015-01-23 16:41:29 +01:00
# include <linux/of.h>
2016-07-09 21:21:15 +02:00
# include <linux/of_device.h>
2014-07-25 19:57:46 +08:00
# include <linux/pm.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 chip_desc {
u8 nchans ;
u8 enable ; /* used for muxes only */
enum muxtype {
pca954x_ismux = 0 ,
pca954x_isswi
} muxtype ;
} ;
2016-07-09 21:21:15 +02:00
struct pca954x {
const struct chip_desc * chip ;
u8 last_chan ; /* last register value */
u8 deselect ;
struct i2c_client * client ;
} ;
2010-08-11 18:21:03 +02:00
/* 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 ) ;
2016-11-29 17:12:43 +07:00
# ifdef CONFIG_ACPI
static const struct acpi_device_id pca954x_acpi_ids [ ] = {
{ . id = " PCA9540 " , . driver_data = pca_9540 } ,
{ . id = " PCA9542 " , . driver_data = pca_9540 } ,
{ . id = " PCA9543 " , . driver_data = pca_9543 } ,
{ . id = " PCA9544 " , . driver_data = pca_9544 } ,
{ . id = " PCA9545 " , . driver_data = pca_9545 } ,
{ . id = " PCA9546 " , . driver_data = pca_9545 } ,
{ . id = " PCA9547 " , . driver_data = pca_9547 } ,
{ . id = " PCA9548 " , . driver_data = pca_9548 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( acpi , pca954x_acpi_ids ) ;
# endif
2016-07-09 21:21:15 +02:00
# ifdef CONFIG_OF
static const struct of_device_id pca954x_of_match [ ] = {
{ . compatible = " nxp,pca9540 " , . data = & chips [ pca_9540 ] } ,
{ . compatible = " nxp,pca9542 " , . data = & chips [ pca_9542 ] } ,
{ . compatible = " nxp,pca9543 " , . data = & chips [ pca_9543 ] } ,
{ . compatible = " nxp,pca9544 " , . data = & chips [ pca_9544 ] } ,
{ . compatible = " nxp,pca9545 " , . data = & chips [ pca_9545 ] } ,
{ . compatible = " nxp,pca9546 " , . data = & chips [ pca_9546 ] } ,
{ . compatible = " nxp,pca9547 " , . data = & chips [ pca_9547 ] } ,
{ . compatible = " nxp,pca9548 " , . data = & chips [ pca_9548 ] } ,
{ }
} ;
# endif
2010-08-11 18:21:03 +02:00
/* 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 ;
2015-06-12 14:41:00 +02:00
ret = __i2c_transfer ( adap , & msg , 1 ) ;
2016-12-17 12:10:56 +00:00
if ( ret > = 0 & & ret ! = 1 )
ret = - EREMOTEIO ;
2010-08-11 18:21:03 +02:00
} 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 ;
}
2016-04-20 08:40:14 +02:00
static int pca954x_select_chan ( struct i2c_mux_core * muxc , u32 chan )
2010-08-11 18:21:03 +02:00
{
2016-04-20 08:40:14 +02:00
struct pca954x * data = i2c_mux_priv ( muxc ) ;
struct i2c_client * client = data - > client ;
2016-07-09 21:21:15 +02:00
const struct chip_desc * chip = data - > chip ;
2010-08-11 18:21:03 +02:00
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 ) {
2016-04-20 08:40:14 +02:00
ret = pca954x_reg_write ( muxc - > parent , client , regval ) ;
2016-12-17 12:10:56 +00:00
data - > last_chan = ret < 0 ? 0 : regval ;
2010-08-11 18:21:03 +02:00
}
return ret ;
}
2016-04-20 08:40:14 +02:00
static int pca954x_deselect_mux ( struct i2c_mux_core * muxc , u32 chan )
2010-08-11 18:21:03 +02:00
{
2016-04-20 08:40:14 +02:00
struct pca954x * data = i2c_mux_priv ( muxc ) ;
struct i2c_client * client = data - > client ;
if ( ! ( data - > deselect & ( 1 < < chan ) ) )
return 0 ;
2010-08-11 18:21:03 +02:00
/* Deselect active channel */
data - > last_chan = 0 ;
2016-04-20 08:40:14 +02:00
return pca954x_reg_write ( muxc - > parent , client , data - > last_chan ) ;
2010-08-11 18:21:03 +02:00
}
/*
* 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 ) ;
2015-01-23 16:41:29 +01:00
struct device_node * of_node = client - > dev . of_node ;
bool idle_disconnect_dt ;
2014-06-03 13:15:26 +02:00
struct gpio_desc * gpio ;
2012-10-05 22:23:51 +02:00
int num , force , class ;
2016-04-20 08:40:14 +02:00
struct i2c_mux_core * muxc ;
2010-08-11 18:21:03 +02:00
struct pca954x * data ;
2016-07-09 21:21:15 +02:00
const struct of_device_id * match ;
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
2016-04-20 08:40:14 +02:00
muxc = i2c_mux_alloc ( adap , & client - > dev ,
PCA954X_MAX_NCHANS , sizeof ( * data ) , 0 ,
pca954x_select_chan , pca954x_deselect_mux ) ;
if ( ! muxc )
2013-11-29 01:51:23 +01:00
return - ENOMEM ;
2016-04-20 08:40:14 +02:00
data = i2c_mux_priv ( muxc ) ;
2010-08-11 18:21:03 +02:00
2016-04-20 08:40:14 +02:00
i2c_set_clientdata ( client , muxc ) ;
data - > client = client ;
2010-08-11 18:21:03 +02:00
2014-06-03 13:15:26 +02:00
/* Get the mux out of reset if a reset GPIO is specified. */
2015-02-17 10:12:08 +01:00
gpio = devm_gpiod_get_optional ( & client - > dev , " reset " , GPIOD_OUT_LOW ) ;
if ( IS_ERR ( gpio ) )
return PTR_ERR ( gpio ) ;
2013-11-29 01:51:25 +01:00
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
}
2016-07-09 21:21:15 +02:00
match = of_match_device ( of_match_ptr ( pca954x_of_match ) , & client - > dev ) ;
if ( match )
data - > chip = of_device_get_match_data ( & client - > dev ) ;
2016-11-29 17:12:43 +07:00
else if ( id )
2016-07-09 21:21:15 +02:00
data - > chip = & chips [ id - > driver_data ] ;
2016-11-29 17:12:43 +07:00
else {
const struct acpi_device_id * acpi_id ;
acpi_id = acpi_match_device ( ACPI_PTR ( pca954x_acpi_ids ) ,
& client - > dev ) ;
if ( ! acpi_id )
return - ENODEV ;
data - > chip = & chips [ acpi_id - > driver_data ] ;
}
2016-07-09 21:21:15 +02:00
2010-08-11 18:21:03 +02:00
data - > last_chan = 0 ; /* force the first selection */
2015-01-23 16:41:29 +01:00
idle_disconnect_dt = of_node & &
of_property_read_bool ( of_node , " i2c-mux-idle-disconnect " ) ;
2010-08-11 18:21:03 +02:00
/* Now create an adapter for each channel */
2016-07-09 21:21:15 +02:00
for ( num = 0 ; num < data - > chip - > nchans ; num + + ) {
2015-01-23 16:41:29 +01:00
bool idle_disconnect_pd = false ;
2010-08-11 18:21:03 +02:00
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 ;
2015-01-23 16:41:29 +01:00
idle_disconnect_pd = pdata - > modes [ num ] . deselect_on_exit ;
2010-08-11 18:21:03 +02:00
}
2016-11-19 10:48:38 +01:00
data - > deselect | = ( idle_disconnect_pd | |
idle_disconnect_dt ) < < num ;
2010-08-11 18:21:03 +02:00
2016-04-20 08:40:14 +02:00
ret = i2c_mux_add_adapter ( muxc , force , num , class ) ;
2010-08-11 18:21:03 +02:00
2016-04-20 08:40:14 +02:00
if ( ret ) {
2010-08-11 18:21:03 +02:00
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 " ,
2016-07-09 21:21:15 +02:00
num , data - > chip - > muxtype = = pca954x_ismux
2010-08-11 18:21:03 +02:00
? " mux " : " switch " , client - > name ) ;
return 0 ;
virt_reg_failed :
2016-04-20 08:40:14 +02:00
i2c_mux_del_adapters ( muxc ) ;
2010-08-11 18:21:03 +02:00
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
{
2016-04-20 08:40:14 +02:00
struct i2c_mux_core * muxc = i2c_get_clientdata ( client ) ;
2010-08-11 18:21:03 +02:00
2016-04-20 08:40:14 +02:00
i2c_mux_del_adapters ( muxc ) ;
2010-08-11 18:21:03 +02:00
return 0 ;
}
2014-07-25 19:57:46 +08:00
# ifdef CONFIG_PM_SLEEP
static int pca954x_resume ( struct device * dev )
{
struct i2c_client * client = to_i2c_client ( dev ) ;
2016-04-20 08:40:14 +02:00
struct i2c_mux_core * muxc = i2c_get_clientdata ( client ) ;
struct pca954x * data = i2c_mux_priv ( muxc ) ;
2014-07-25 19:57:46 +08:00
data - > last_chan = 0 ;
return i2c_smbus_write_byte ( client , 0 ) ;
}
# endif
static SIMPLE_DEV_PM_OPS ( pca954x_pm , NULL , pca954x_resume ) ;
2010-08-11 18:21:03 +02:00
static struct i2c_driver pca954x_driver = {
. driver = {
. name = " pca954x " ,
2014-07-25 19:57:46 +08:00
. pm = & pca954x_pm ,
2016-07-09 21:21:15 +02:00
. of_match_table = of_match_ptr ( pca954x_of_match ) ,
2016-11-29 17:12:43 +07:00
. acpi_match_table = ACPI_PTR ( pca954x_acpi_ids ) ,
2010-08-11 18:21:03 +02:00
} ,
. 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 " ) ;