2019-05-20 10:19:02 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2008-02-05 09:28:24 +03:00
/*
2011-06-05 04:38:28 +04:00
* Driver for pcf857x , pca857x , and pca967x I2C GPIO expanders
2008-02-05 09:28:24 +03:00
*
* Copyright ( C ) 2007 David Brownell
*/
2018-05-24 15:27:28 +03:00
# include <linux/gpio/driver.h>
2008-02-05 09:28:24 +03:00
# include <linux/i2c.h>
2017-05-22 00:57:26 +03:00
# include <linux/platform_data/pcf857x.h>
2012-06-15 06:40:41 +04:00
# include <linux/interrupt.h>
# include <linux/irq.h>
# include <linux/irqdomain.h>
2013-08-20 03:04:52 +04:00
# include <linux/kernel.h>
2011-07-03 21:38:09 +04:00
# include <linux/module.h>
2013-09-21 22:39:49 +04:00
# include <linux/of.h>
# include <linux/of_device.h>
2013-08-20 03:04:52 +04:00
# include <linux/slab.h>
2012-06-15 06:40:41 +04:00
# include <linux/spinlock.h>
2008-02-05 09:28:24 +03:00
2008-04-30 01:11:40 +04:00
static const struct i2c_device_id pcf857x_id [ ] = {
{ " pcf8574 " , 8 } ,
2009-09-19 00:45:47 +04:00
{ " pcf8574a " , 8 } ,
2008-04-30 01:11:40 +04:00
{ " pca8574 " , 8 } ,
{ " pca9670 " , 8 } ,
{ " pca9672 " , 8 } ,
{ " pca9674 " , 8 } ,
{ " pcf8575 " , 16 } ,
{ " pca8575 " , 16 } ,
{ " pca9671 " , 16 } ,
{ " pca9673 " , 16 } ,
{ " pca9675 " , 16 } ,
2008-07-22 01:21:34 +04:00
{ " max7328 " , 8 } ,
{ " max7329 " , 8 } ,
2008-04-30 01:11:40 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , pcf857x_id ) ;
2013-09-21 22:39:49 +04:00
# ifdef CONFIG_OF
static const struct of_device_id pcf857x_of_table [ ] = {
{ . compatible = " nxp,pcf8574 " } ,
{ . compatible = " nxp,pcf8574a " } ,
{ . compatible = " nxp,pca8574 " } ,
{ . compatible = " nxp,pca9670 " } ,
{ . compatible = " nxp,pca9672 " } ,
{ . compatible = " nxp,pca9674 " } ,
{ . compatible = " nxp,pcf8575 " } ,
{ . compatible = " nxp,pca8575 " } ,
{ . compatible = " nxp,pca9671 " } ,
{ . compatible = " nxp,pca9673 " } ,
{ . compatible = " nxp,pca9675 " } ,
{ . compatible = " maxim,max7328 " } ,
{ . compatible = " maxim,max7329 " } ,
{ }
} ;
MODULE_DEVICE_TABLE ( of , pcf857x_of_table ) ;
# endif
2008-02-05 09:28:24 +03:00
/*
* The pcf857x , pca857x , and pca967x chips only expose one read and one
* write register . Writing a " one " bit ( to match the reset state ) lets
* that pin be used as an input ; it ' s not an open - drain model , but acts
* a bit like one . This is described as " quasi-bidirectional " ; read the
* chip documentation for details .
*
* Many other I2C GPIO expander chips ( like the pca953x models ) have
* more complex register models and more conventional circuitry using
* push / pull drivers . They often use the same 0x20 . .0 x27 addresses as
* pcf857x parts , making the " legacy " I2C driver model problematic .
*/
struct pcf857x {
struct gpio_chip chip ;
struct i2c_client * client ;
2008-07-22 01:21:34 +04:00
struct mutex lock ; /* protect 'out' */
2008-02-05 09:28:24 +03:00
unsigned out ; /* software latch */
2012-06-15 06:40:41 +04:00
unsigned status ; /* current status */
2015-06-11 00:01:09 +03:00
unsigned irq_enabled ; /* enabled irqs */
2012-06-14 08:58:08 +04:00
int ( * write ) ( struct i2c_client * client , unsigned data ) ;
int ( * read ) ( struct i2c_client * client ) ;
2008-02-05 09:28:24 +03:00
} ;
/*-------------------------------------------------------------------------*/
/* Talk to 8-bit I/O expander */
2012-06-14 08:58:08 +04:00
static int i2c_write_le8 ( struct i2c_client * client , unsigned data )
2008-02-05 09:28:24 +03:00
{
2012-06-14 08:58:08 +04:00
return i2c_smbus_write_byte ( client , data ) ;
2008-02-05 09:28:24 +03:00
}
2012-06-14 08:58:08 +04:00
static int i2c_read_le8 ( struct i2c_client * client )
2008-02-05 09:28:24 +03:00
{
2012-06-14 08:58:08 +04:00
return ( int ) i2c_smbus_read_byte ( client ) ;
2008-02-05 09:28:24 +03:00
}
/* Talk to 16-bit I/O expander */
2012-06-14 08:58:08 +04:00
static int i2c_write_le16 ( struct i2c_client * client , unsigned word )
2008-02-05 09:28:24 +03:00
{
u8 buf [ 2 ] = { word & 0xff , word > > 8 , } ;
int status ;
status = i2c_master_send ( client , buf , 2 ) ;
return ( status < 0 ) ? status : 0 ;
}
static int i2c_read_le16 ( struct i2c_client * client )
{
u8 buf [ 2 ] ;
int status ;
status = i2c_master_recv ( client , buf , 2 ) ;
if ( status < 0 )
return status ;
return ( buf [ 1 ] < < 8 ) | buf [ 0 ] ;
}
2012-06-14 08:58:08 +04:00
/*-------------------------------------------------------------------------*/
static int pcf857x_input ( struct gpio_chip * chip , unsigned offset )
2008-02-05 09:28:24 +03:00
{
2015-12-07 13:24:05 +03:00
struct pcf857x * gpio = gpiochip_get_data ( chip ) ;
2008-07-22 01:21:34 +04:00
int status ;
2008-02-05 09:28:24 +03:00
2008-07-22 01:21:34 +04:00
mutex_lock ( & gpio - > lock ) ;
2008-02-05 09:28:24 +03:00
gpio - > out | = ( 1 < < offset ) ;
2012-06-14 08:58:08 +04:00
status = gpio - > write ( gpio - > client , gpio - > out ) ;
2008-07-22 01:21:34 +04:00
mutex_unlock ( & gpio - > lock ) ;
return status ;
2008-02-05 09:28:24 +03:00
}
2012-06-14 08:58:08 +04:00
static int pcf857x_get ( struct gpio_chip * chip , unsigned offset )
2008-02-05 09:28:24 +03:00
{
2015-12-07 13:24:05 +03:00
struct pcf857x * gpio = gpiochip_get_data ( chip ) ;
2008-02-05 09:28:24 +03:00
int value ;
2012-06-14 08:58:08 +04:00
value = gpio - > read ( gpio - > client ) ;
2015-12-21 13:32:53 +03:00
return ( value < 0 ) ? value : ! ! ( value & ( 1 < < offset ) ) ;
2008-02-05 09:28:24 +03:00
}
2012-06-14 08:58:08 +04:00
static int pcf857x_output ( struct gpio_chip * chip , unsigned offset , int value )
2008-02-05 09:28:24 +03:00
{
2015-12-07 13:24:05 +03:00
struct pcf857x * gpio = gpiochip_get_data ( chip ) ;
2008-02-05 09:28:24 +03:00
unsigned bit = 1 < < offset ;
2008-07-22 01:21:34 +04:00
int status ;
2008-02-05 09:28:24 +03:00
2008-07-22 01:21:34 +04:00
mutex_lock ( & gpio - > lock ) ;
2008-02-05 09:28:24 +03:00
if ( value )
gpio - > out | = bit ;
else
gpio - > out & = ~ bit ;
2012-06-14 08:58:08 +04:00
status = gpio - > write ( gpio - > client , gpio - > out ) ;
2008-07-22 01:21:34 +04:00
mutex_unlock ( & gpio - > lock ) ;
return status ;
2008-02-05 09:28:24 +03:00
}
2012-06-14 08:58:08 +04:00
static void pcf857x_set ( struct gpio_chip * chip , unsigned offset , int value )
2008-02-05 09:28:24 +03:00
{
2012-06-14 08:58:08 +04:00
pcf857x_output ( chip , offset , value ) ;
2008-02-05 09:28:24 +03:00
}
/*-------------------------------------------------------------------------*/
2013-09-04 11:03:01 +04:00
static irqreturn_t pcf857x_irq ( int irq , void * data )
{
struct pcf857x * gpio = data ;
2015-06-25 18:18:11 +03:00
unsigned long change , i , status ;
2013-09-04 11:03:01 +04:00
status = gpio - > read ( gpio - > client ) ;
2013-09-04 11:03:03 +04:00
/*
* call the interrupt handler iff gpio is used as
* interrupt source , just to avoid bad irqs
*/
2015-06-25 18:18:11 +03:00
mutex_lock ( & gpio - > lock ) ;
2015-06-11 00:01:09 +03:00
change = ( gpio - > status ^ status ) & gpio - > irq_enabled ;
2013-09-04 11:03:01 +04:00
gpio - > status = status ;
2015-06-25 18:18:11 +03:00
mutex_unlock ( & gpio - > lock ) ;
2013-09-04 11:03:01 +04:00
2015-06-25 18:18:11 +03:00
for_each_set_bit ( i , & change , gpio - > chip . ngpio )
2017-11-07 21:15:47 +03:00
handle_nested_irq ( irq_find_mapping ( gpio - > chip . irq . domain , i ) ) ;
2013-09-04 11:03:01 +04:00
return IRQ_HANDLED ;
}
2015-02-05 18:49:09 +03:00
/*
* NOP functions
*/
static void noop ( struct irq_data * data ) { }
static int pcf857x_irq_set_wake ( struct irq_data * data , unsigned int on )
{
struct pcf857x * gpio = irq_data_get_irq_chip_data ( data ) ;
2015-06-11 00:01:09 +03:00
2019-02-13 16:14:09 +03:00
return irq_set_irq_wake ( gpio - > client - > irq , on ) ;
2015-02-05 18:49:09 +03:00
}
2015-06-11 00:01:09 +03:00
static void pcf857x_irq_enable ( struct irq_data * data )
{
struct pcf857x * gpio = irq_data_get_irq_chip_data ( data ) ;
2022-05-20 13:20:57 +03:00
irq_hw_number_t hwirq = irqd_to_hwirq ( data ) ;
2015-06-11 00:01:09 +03:00
2022-05-20 13:20:57 +03:00
gpiochip_enable_irq ( & gpio - > chip , hwirq ) ;
gpio - > irq_enabled | = ( 1 < < hwirq ) ;
2015-06-11 00:01:09 +03:00
}
static void pcf857x_irq_disable ( struct irq_data * data )
{
struct pcf857x * gpio = irq_data_get_irq_chip_data ( data ) ;
2022-05-20 13:20:57 +03:00
irq_hw_number_t hwirq = irqd_to_hwirq ( data ) ;
2015-06-11 00:01:09 +03:00
2022-05-20 13:20:57 +03:00
gpio - > irq_enabled & = ~ ( 1 < < hwirq ) ;
gpiochip_disable_irq ( & gpio - > chip , hwirq ) ;
2015-06-11 00:01:09 +03:00
}
static void pcf857x_irq_bus_lock ( struct irq_data * data )
{
struct pcf857x * gpio = irq_data_get_irq_chip_data ( data ) ;
mutex_lock ( & gpio - > lock ) ;
}
static void pcf857x_irq_bus_sync_unlock ( struct irq_data * data )
{
struct pcf857x * gpio = irq_data_get_irq_chip_data ( data ) ;
mutex_unlock ( & gpio - > lock ) ;
}
2022-05-20 13:20:57 +03:00
static const struct irq_chip pcf857x_irq_chip = {
. name = " pcf857x " ,
. irq_enable = pcf857x_irq_enable ,
. irq_disable = pcf857x_irq_disable ,
. irq_ack = noop ,
. irq_mask = noop ,
. irq_unmask = noop ,
. irq_set_wake = pcf857x_irq_set_wake ,
. irq_bus_lock = pcf857x_irq_bus_lock ,
. irq_bus_sync_unlock = pcf857x_irq_bus_sync_unlock ,
. flags = IRQCHIP_IMMUTABLE ,
GPIOCHIP_IRQ_RESOURCE_HELPERS ,
} ;
2012-06-15 06:40:41 +04:00
/*-------------------------------------------------------------------------*/
2008-04-30 01:11:39 +04:00
static int pcf857x_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
2008-02-05 09:28:24 +03:00
{
2013-09-21 22:39:49 +04:00
struct pcf857x_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
struct device_node * np = client - > dev . of_node ;
2008-02-05 09:28:24 +03:00
struct pcf857x * gpio ;
2013-09-21 22:39:49 +04:00
unsigned int n_latch = 0 ;
2008-02-05 09:28:24 +03:00
int status ;
2013-09-21 22:39:49 +04:00
if ( IS_ENABLED ( CONFIG_OF ) & & np )
of_property_read_u32 ( np , " lines-initial-states " , & n_latch ) ;
else if ( pdata )
n_latch = pdata - > n_latch ;
else
2009-01-16 00:50:45 +03:00
dev_dbg ( & client - > dev , " no platform data \n " ) ;
2008-02-05 09:28:24 +03:00
/* Allocate, initialize, and register this gpio_chip. */
2013-03-15 13:16:11 +04:00
gpio = devm_kzalloc ( & client - > dev , sizeof ( * gpio ) , GFP_KERNEL ) ;
2008-02-05 09:28:24 +03:00
if ( ! gpio )
return - ENOMEM ;
2008-07-22 01:21:34 +04:00
mutex_init ( & gpio - > lock ) ;
2012-06-14 08:58:08 +04:00
gpio - > chip . base = pdata ? pdata - > gpio_base : - 1 ;
2013-12-04 17:42:46 +04:00
gpio - > chip . can_sleep = true ;
2015-12-04 17:28:16 +03:00
gpio - > chip . parent = & client - > dev ;
2012-06-14 08:58:08 +04:00
gpio - > chip . owner = THIS_MODULE ;
gpio - > chip . get = pcf857x_get ;
gpio - > chip . set = pcf857x_set ;
gpio - > chip . direction_input = pcf857x_input ;
gpio - > chip . direction_output = pcf857x_output ;
gpio - > chip . ngpio = id - > driver_data ;
2008-02-05 09:28:24 +03:00
/* NOTE: the OnSemi jlc1562b is also largely compatible with
* these parts , notably for output . It has a low - resolution
* DAC instead of pin change IRQs ; and its inputs can be the
* result of comparators .
*/
/* 8574 addresses are 0x20..0x27; 8574a uses 0x38..0x3f;
* 9670 , 9672 , 9764 , and 9764 a use quite a variety .
*
* NOTE : we don ' t distinguish here between * 4 and * 4 a parts .
*/
2008-04-30 01:11:40 +04:00
if ( gpio - > chip . ngpio = = 8 ) {
2012-06-14 08:58:08 +04:00
gpio - > write = i2c_write_le8 ;
gpio - > read = i2c_read_le8 ;
2008-02-05 09:28:24 +03:00
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_BYTE ) )
status = - EIO ;
/* fail if there's no chip present */
else
status = i2c_smbus_read_byte ( client ) ;
/* '75/'75c addresses are 0x20..0x27, just like the '74;
* the ' 75 c doesn ' t have a current source pulling high .
* 9671 , 9673 , and 9765 use quite a variety of addresses .
*
* NOTE : we don ' t distinguish here between ' 75 and ' 75 c parts .
*/
2008-04-30 01:11:40 +04:00
} else if ( gpio - > chip . ngpio = = 16 ) {
2012-06-14 08:58:08 +04:00
gpio - > write = i2c_write_le16 ;
gpio - > read = i2c_read_le16 ;
2008-02-05 09:28:24 +03:00
if ( ! i2c_check_functionality ( client - > adapter , I2C_FUNC_I2C ) )
status = - EIO ;
/* fail if there's no chip present */
else
status = i2c_read_le16 ( client ) ;
2009-01-16 00:50:45 +03:00
} else {
dev_dbg ( & client - > dev , " unsupported number of gpios \n " ) ;
status = - EINVAL ;
}
2008-02-05 09:28:24 +03:00
if ( status < 0 )
goto fail ;
gpio - > chip . label = client - > name ;
gpio - > client = client ;
i2c_set_clientdata ( client , gpio ) ;
/* NOTE: these chips have strange "quasi-bidirectional" I/O pins.
* We can ' t actually know whether a pin is configured ( a ) as output
* and driving the signal low , or ( b ) as input and reporting a low
* value . . . without knowing the last value written since the chip
* came out of reset ( if any ) . We can ' t read the latched output .
*
* In short , the only reliable solution for setting up pin direction
* is to do it explicitly . The setup ( ) method can do that , but it
* may cause transient glitching since it can ' t know the last value
* written ( some pins may need to be driven low ) .
*
2013-09-21 22:39:49 +04:00
* Using n_latch avoids that trouble . When left initialized to zero ,
* our software copy of the " latch " then matches the chip ' s all - ones
* reset state . Otherwise it flags pins to be driven low .
2008-02-05 09:28:24 +03:00
*/
2013-09-21 22:39:49 +04:00
gpio - > out = ~ n_latch ;
2021-02-17 16:10:00 +03:00
gpio - > status = gpio - > read ( gpio - > client ) ;
2008-02-05 09:28:24 +03:00
2015-02-05 18:49:08 +03:00
/* Enable irqchip if we have an interrupt */
if ( client - > irq ) {
2020-07-17 17:48:35 +03:00
struct gpio_irq_chip * girq ;
2015-02-05 18:49:08 +03:00
status = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , pcf857x_irq , IRQF_ONESHOT |
IRQF_TRIGGER_FALLING | IRQF_SHARED ,
dev_name ( & client - > dev ) , gpio ) ;
if ( status )
2016-02-22 15:13:28 +03:00
goto fail ;
2015-02-05 18:49:08 +03:00
2020-07-17 17:48:35 +03:00
girq = & gpio - > chip . irq ;
2022-05-20 13:20:57 +03:00
gpio_irq_chip_set_chip ( girq , & pcf857x_irq_chip ) ;
2020-07-17 17:48:35 +03:00
/* This will let us handle the parent IRQ in the driver */
girq - > parent_handler = NULL ;
girq - > num_parents = 0 ;
girq - > parents = NULL ;
girq - > default_type = IRQ_TYPE_NONE ;
girq - > handler = handle_level_irq ;
girq - > threaded = true ;
2015-02-05 18:49:08 +03:00
}
2020-07-17 17:48:35 +03:00
status = devm_gpiochip_add_data ( & client - > dev , & gpio - > chip , gpio ) ;
if ( status < 0 )
goto fail ;
2008-02-05 09:28:24 +03:00
/* Let platform code set up the GPIOs and their users.
* Now is the first time anyone could use them .
*/
2010-08-11 05:02:24 +04:00
if ( pdata & & pdata - > setup ) {
2008-02-05 09:28:24 +03:00
status = pdata - > setup ( client ,
gpio - > chip . base , gpio - > chip . ngpio ,
pdata - > context ) ;
if ( status < 0 )
dev_warn ( & client - > dev , " setup --> %d \n " , status ) ;
}
2012-12-06 13:10:28 +04:00
dev_info ( & client - > dev , " probed \n " ) ;
2008-02-05 09:28:24 +03:00
return 0 ;
2015-02-05 18:49:08 +03:00
fail :
dev_dbg ( & client - > dev , " probe error %d for '%s' \n " , status ,
client - > name ) ;
2014-05-23 09:57:26 +04:00
2008-02-05 09:28:24 +03:00
return status ;
}
static int pcf857x_remove ( struct i2c_client * client )
{
2013-07-30 12:08:05 +04:00
struct pcf857x_platform_data * pdata = dev_get_platdata ( & client - > dev ) ;
2008-02-05 09:28:24 +03:00
struct pcf857x * gpio = i2c_get_clientdata ( client ) ;
2022-04-25 20:32:55 +03:00
if ( pdata & & pdata - > teardown )
pdata - > teardown ( client , gpio - > chip . base , gpio - > chip . ngpio ,
2008-02-05 09:28:24 +03:00
pdata - > context ) ;
2022-04-25 20:32:55 +03:00
return 0 ;
2008-02-05 09:28:24 +03:00
}
2016-05-27 09:35:29 +03:00
static void pcf857x_shutdown ( struct i2c_client * client )
{
struct pcf857x * gpio = i2c_get_clientdata ( client ) ;
/* Drive all the I/O lines high */
gpio - > write ( gpio - > client , BIT ( gpio - > chip . ngpio ) - 1 ) ;
}
2008-02-05 09:28:24 +03:00
static struct i2c_driver pcf857x_driver = {
. driver = {
. name = " pcf857x " ,
2013-09-21 22:39:49 +04:00
. of_match_table = of_match_ptr ( pcf857x_of_table ) ,
2008-02-05 09:28:24 +03:00
} ,
. probe = pcf857x_probe ,
. remove = pcf857x_remove ,
2016-05-27 09:35:29 +03:00
. shutdown = pcf857x_shutdown ,
2008-04-30 01:11:40 +04:00
. id_table = pcf857x_id ,
2008-02-05 09:28:24 +03:00
} ;
static int __init pcf857x_init ( void )
{
return i2c_add_driver ( & pcf857x_driver ) ;
}
2008-10-16 09:03:13 +04:00
/* register after i2c postcore initcall and before
* subsys initcalls that may rely on these GPIOs
*/
subsys_initcall ( pcf857x_init ) ;
2008-02-05 09:28:24 +03:00
static void __exit pcf857x_exit ( void )
{
i2c_del_driver ( & pcf857x_driver ) ;
}
module_exit ( pcf857x_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_AUTHOR ( " David Brownell " ) ;