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 >
*
2017-12-25 22:26:46 +01:00
* This module supports the PCA954x and PCA954x series of I2C multiplexer / switch
* chips made by NXP Semiconductors .
2010-08-11 18:21:03 +02:00
* This includes the :
2017-12-25 22:26:46 +01:00
* PCA9540 , PCA9542 , PCA9543 , PCA9544 , PCA9545 , PCA9546 , PCA9547 ,
* PCA9548 , PCA9846 , PCA9847 , PCA9848 and PCA9849 .
2010-08-11 18:21:03 +02:00
*
* 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>
2018-05-01 13:42:12 +02:00
# include <linux/delay.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>
2017-01-25 09:31:08 +08:00
# include <linux/interrupt.h>
# include <linux/irq.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>
2017-01-25 09:31:08 +08:00
# include <linux/of_irq.h>
2017-08-14 10:23:25 +02:00
# include <linux/platform_data/pca954x.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>
2017-01-25 09:31:08 +08:00
# include <linux/spinlock.h>
2010-08-11 18:21:03 +02:00
# define PCA954X_MAX_NCHANS 8
2017-01-25 09:31:08 +08:00
# define PCA954X_IRQ_OFFSET 4
2010-08-11 18:21:03 +02:00
enum pca_type {
pca_9540 ,
pca_9542 ,
pca_9543 ,
pca_9544 ,
pca_9545 ,
pca_9546 ,
pca_9547 ,
pca_9548 ,
2017-12-25 22:26:46 +01:00
pca_9846 ,
pca_9847 ,
pca_9848 ,
pca_9849 ,
2010-08-11 18:21:03 +02:00
} ;
struct chip_desc {
u8 nchans ;
u8 enable ; /* used for muxes only */
2017-01-25 09:31:08 +08:00
u8 has_irq ;
2010-08-11 18:21:03 +02:00
enum muxtype {
pca954x_ismux = 0 ,
pca954x_isswi
} muxtype ;
2018-01-22 08:40:02 +01:00
struct i2c_device_identity id ;
2010-08-11 18:21:03 +02:00
} ;
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 ;
2017-01-25 09:31:08 +08:00
struct irq_domain * irq ;
unsigned int irq_mask ;
2017-03-09 10:21:59 -06:00
raw_spinlock_t lock ;
2016-07-09 21:21:15 +02:00
} ;
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 ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
2017-01-25 09:31:06 +08:00
[ pca_9542 ] = {
. nchans = 2 ,
. enable = 0x4 ,
2017-01-25 09:31:08 +08:00
. has_irq = 1 ,
2017-01-25 09:31:06 +08:00
. muxtype = pca954x_ismux ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2017-01-25 09:31:06 +08:00
} ,
2010-08-11 18:21:03 +02:00
[ pca_9543 ] = {
. nchans = 2 ,
2017-01-25 09:31:08 +08:00
. has_irq = 1 ,
2010-08-11 18:21:03 +02:00
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
[ pca_9544 ] = {
. nchans = 4 ,
. enable = 0x4 ,
2017-01-25 09:31:08 +08:00
. has_irq = 1 ,
2010-08-11 18:21:03 +02:00
. muxtype = pca954x_ismux ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
[ pca_9545 ] = {
. nchans = 4 ,
2017-01-25 09:31:08 +08:00
. has_irq = 1 ,
2010-08-11 18:21:03 +02:00
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
2017-03-23 10:00:36 +01:00
[ pca_9546 ] = {
. nchans = 4 ,
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2017-03-23 10:00:36 +01:00
} ,
2010-08-11 18:21:03 +02:00
[ pca_9547 ] = {
. nchans = 8 ,
. enable = 0x8 ,
. muxtype = pca954x_ismux ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
[ pca_9548 ] = {
. nchans = 8 ,
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = { . manufacturer_id = I2C_DEVICE_ID_NONE } ,
2010-08-11 18:21:03 +02:00
} ,
2017-12-25 22:26:46 +01:00
[ pca_9846 ] = {
. nchans = 4 ,
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = {
. manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS ,
. part_id = 0x10b ,
} ,
2017-12-25 22:26:46 +01:00
} ,
[ pca_9847 ] = {
. nchans = 8 ,
. enable = 0x8 ,
. muxtype = pca954x_ismux ,
2018-01-22 08:40:02 +01:00
. id = {
. manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS ,
. part_id = 0x108 ,
} ,
2017-12-25 22:26:46 +01:00
} ,
[ pca_9848 ] = {
. nchans = 8 ,
. muxtype = pca954x_isswi ,
2018-01-22 08:40:02 +01:00
. id = {
. manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS ,
. part_id = 0x10a ,
} ,
2017-12-25 22:26:46 +01:00
} ,
[ pca_9849 ] = {
. nchans = 4 ,
. enable = 0x4 ,
. muxtype = pca954x_ismux ,
2018-01-22 08:40:02 +01:00
. id = {
. manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS ,
. part_id = 0x109 ,
} ,
2017-12-25 22:26:46 +01:00
} ,
2010-08-11 18:21:03 +02:00
} ;
static const struct i2c_device_id pca954x_id [ ] = {
{ " pca9540 " , pca_9540 } ,
2017-01-25 09:31:06 +08:00
{ " pca9542 " , pca_9542 } ,
2010-08-11 18:21:03 +02:00
{ " pca9543 " , pca_9543 } ,
{ " pca9544 " , pca_9544 } ,
{ " pca9545 " , pca_9545 } ,
2017-03-23 10:00:36 +01:00
{ " pca9546 " , pca_9546 } ,
2010-08-11 18:21:03 +02:00
{ " pca9547 " , pca_9547 } ,
{ " pca9548 " , pca_9548 } ,
2017-12-25 22:26:46 +01:00
{ " pca9846 " , pca_9846 } ,
{ " pca9847 " , pca_9847 } ,
{ " pca9848 " , pca_9848 } ,
{ " pca9849 " , pca_9849 } ,
2010-08-11 18:21:03 +02:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , pca954x_id ) ;
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 ] } ,
2017-12-25 22:26:46 +01:00
{ . compatible = " nxp,pca9846 " , . data = & chips [ pca_9846 ] } ,
{ . compatible = " nxp,pca9847 " , . data = & chips [ pca_9847 ] } ,
{ . compatible = " nxp,pca9848 " , . data = & chips [ pca_9848 ] } ,
{ . compatible = " nxp,pca9849 " , . data = & chips [ pca_9849 ] } ,
2016-07-09 21:21:15 +02:00
{ }
} ;
2017-01-16 10:54:54 -03:00
MODULE_DEVICE_TABLE ( of , pca954x_of_match ) ;
2016-07-09 21:21:15 +02:00
# 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 )
{
2018-06-20 10:51:56 +02:00
union i2c_smbus_data dummy ;
2010-08-11 18:21:03 +02:00
2018-06-20 10:51:56 +02:00
return __i2c_smbus_xfer ( adap , client - > addr , client - > flags ,
I2C_SMBUS_WRITE , val ,
I2C_SMBUS_BYTE , & dummy ) ;
2010-08-11 18:21:03 +02:00
}
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
}
2017-01-25 09:31:08 +08:00
static irqreturn_t pca954x_irq_handler ( int irq , void * dev_id )
{
struct pca954x * data = dev_id ;
unsigned int child_irq ;
int ret , i , handled = 0 ;
ret = i2c_smbus_read_byte ( data - > client ) ;
if ( ret < 0 )
return IRQ_NONE ;
for ( i = 0 ; i < data - > chip - > nchans ; i + + ) {
if ( ret & BIT ( PCA954X_IRQ_OFFSET + i ) ) {
child_irq = irq_linear_revmap ( data - > irq , i ) ;
handle_nested_irq ( child_irq ) ;
handled + + ;
}
}
return handled ? IRQ_HANDLED : IRQ_NONE ;
}
static int pca954x_irq_set_type ( struct irq_data * idata , unsigned int type )
{
if ( ( type & IRQ_TYPE_SENSE_MASK ) ! = IRQ_TYPE_LEVEL_LOW )
return - EINVAL ;
return 0 ;
}
static struct irq_chip pca954x_irq_chip = {
. name = " i2c-mux-pca954x " ,
. irq_set_type = pca954x_irq_set_type ,
} ;
static int pca954x_irq_setup ( struct i2c_mux_core * muxc )
{
struct pca954x * data = i2c_mux_priv ( muxc ) ;
struct i2c_client * client = data - > client ;
2017-08-24 17:31:05 +08:00
int c , irq ;
2017-01-25 09:31:08 +08:00
if ( ! data - > chip - > has_irq | | client - > irq < = 0 )
return 0 ;
2017-03-09 10:21:59 -06:00
raw_spin_lock_init ( & data - > lock ) ;
2017-01-25 09:31:08 +08:00
data - > irq = irq_domain_add_linear ( client - > dev . of_node ,
data - > chip - > nchans ,
& irq_domain_simple_ops , data ) ;
if ( ! data - > irq )
return - ENODEV ;
for ( c = 0 ; c < data - > chip - > nchans ; c + + ) {
irq = irq_create_mapping ( data - > irq , c ) ;
2017-08-24 17:31:06 +08:00
if ( ! irq ) {
dev_err ( & client - > dev , " failed irq create map \n " ) ;
return - EINVAL ;
}
2017-01-25 09:31:08 +08:00
irq_set_chip_data ( irq , data ) ;
irq_set_chip_and_handler ( irq , & pca954x_irq_chip ,
handle_simple_irq ) ;
}
2017-08-24 17:31:05 +08:00
return 0 ;
}
2017-01-25 09:31:08 +08:00
2017-08-24 17:31:05 +08:00
static void pca954x_cleanup ( struct i2c_mux_core * muxc )
{
struct pca954x * data = i2c_mux_priv ( muxc ) ;
int c , irq ;
2017-01-25 09:31:08 +08:00
2017-08-24 17:31:05 +08:00
if ( data - > irq ) {
for ( c = 0 ; c < data - > chip - > nchans ; c + + ) {
irq = irq_find_mapping ( data - > irq , c ) ;
irq_dispose_mapping ( irq ) ;
}
irq_domain_remove ( data - > irq ) ;
2017-01-25 09:31:08 +08:00
}
2017-08-24 17:31:05 +08:00
i2c_mux_del_adapters ( muxc ) ;
2017-01-25 09:31:08 +08:00
}
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
{
2018-10-03 17:50:22 +02:00
struct i2c_adapter * adap = client - > adapter ;
2013-07-30 16:59:33 +09:00
struct pca954x_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2018-06-05 15:42:36 +02:00
struct device * dev = & client - > dev ;
struct device_node * np = dev - > of_node ;
2015-01-23 16:41:29 +01:00
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 ;
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
2018-06-05 15:42:36 +02:00
muxc = i2c_mux_alloc ( adap , dev , PCA954X_MAX_NCHANS , sizeof ( * data ) , 0 ,
2016-04-20 08:40:14 +02:00
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
2018-05-01 13:42:12 +02:00
/* Reset the mux if a reset GPIO is specified. */
2018-06-05 15:42:36 +02:00
gpio = devm_gpiod_get_optional ( dev , " reset " , GPIOD_OUT_HIGH ) ;
2015-02-17 10:12:08 +01:00
if ( IS_ERR ( gpio ) )
return PTR_ERR ( gpio ) ;
2018-05-01 13:42:12 +02:00
if ( gpio ) {
udelay ( 1 ) ;
gpiod_set_value_cansleep ( gpio , 0 ) ;
/* Give the chip some time to recover. */
udelay ( 1 ) ;
}
2013-11-29 01:51:25 +01:00
2018-06-05 15:42:36 +02:00
data - > chip = of_device_get_match_data ( dev ) ;
2018-05-21 11:49:08 +02:00
if ( ! data - > chip )
2018-01-22 08:40:02 +01:00
data - > chip = & chips [ id - > driver_data ] ;
if ( data - > chip - > id . manufacturer_id ! = I2C_DEVICE_ID_NONE ) {
struct i2c_device_identity id ;
ret = i2c_get_device_id ( client , & id ) ;
if ( ret & & ret ! = - EOPNOTSUPP )
return ret ;
if ( ! ret & &
( id . manufacturer_id ! = data - > chip - > id . manufacturer_id | |
id . part_id ! = data - > chip - > id . part_id ) ) {
2018-06-05 15:42:36 +02:00
dev_warn ( dev , " unexpected device id %03x-%03x-%x \n " ,
2018-01-22 08:40:02 +01:00
id . manufacturer_id , id . part_id ,
id . die_revision ) ;
return - ENODEV ;
}
}
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 ) {
2018-06-05 15:42:36 +02:00
dev_warn ( dev , " probe failed \n " ) ;
2013-11-29 01:51:23 +01:00
return - ENODEV ;
2010-08-11 18:21:03 +02:00
}
data - > last_chan = 0 ; /* force the first selection */
2018-06-05 15:42:36 +02:00
idle_disconnect_dt = np & &
of_property_read_bool ( np , " i2c-mux-idle-disconnect " ) ;
2015-01-23 16:41:29 +01:00
2017-01-25 09:31:08 +08:00
ret = pca954x_irq_setup ( muxc ) ;
if ( ret )
2017-08-24 17:31:05 +08:00
goto fail_cleanup ;
2017-01-25 09:31:08 +08:00
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 ) ;
2017-04-03 10:14:22 +02:00
if ( ret )
2017-08-24 17:31:05 +08:00
goto fail_cleanup ;
}
if ( data - > irq ) {
2018-06-05 15:42:36 +02:00
ret = devm_request_threaded_irq ( dev , data - > client - > irq ,
2017-08-24 17:31:05 +08:00
NULL , pca954x_irq_handler ,
IRQF_ONESHOT | IRQF_SHARED ,
" pca954x " , data ) ;
if ( ret )
goto fail_cleanup ;
2010-08-11 18:21:03 +02:00
}
2018-06-05 15:42:36 +02:00
dev_info ( 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 ;
2017-08-24 17:31:05 +08:00
fail_cleanup :
pca954x_cleanup ( 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 ) ;
2017-01-25 09:31:08 +08:00
2017-08-24 17:31:05 +08:00
pca954x_cleanup ( 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 ) ,
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 " ) ;