2019-05-24 12:04:09 +02:00
// SPDX-License-Identifier: GPL-2.0-or-later
2010-01-08 14:43:08 -08:00
/*
* GPIO Chip driver for Analog Devices
2010-10-27 15:33:19 -07:00
* ADP5588 / ADP5587 I / O Expander and QWERTY Keypad Controller
2010-01-08 14:43:08 -08:00
*
2010-10-27 15:33:19 -07:00
* Copyright 2009 - 2010 Analog Devices Inc .
2010-01-08 14:43:08 -08:00
*/
2018-01-13 22:14:56 +01:00
# include <linux/gpio/driver.h>
2022-06-28 22:39:05 +03:00
# include <linux/i2c.h>
# include <linux/init.h>
2010-10-27 15:33:19 -07:00
# include <linux/interrupt.h>
# include <linux/irq.h>
2022-06-28 22:39:05 +03:00
# include <linux/kernel.h>
2022-06-28 22:39:03 +03:00
# include <linux/mod_devicetable.h>
# include <linux/module.h>
2022-06-28 22:39:05 +03:00
# include <linux/slab.h>
2010-01-08 14:43:08 -08:00
2017-05-21 23:57:27 +02:00
# include <linux/platform_data/adp5588.h>
2010-01-08 14:43:08 -08:00
2010-10-27 15:33:19 -07:00
/*
* Early pre 4.0 Silicon required to delay readout by at least 25 ms ,
* since the Event Counter Register updated 25 ms after the interrupt
* asserted .
*/
# define WA_DELAYED_READOUT_REVID(rev) ((rev) < 4)
2010-01-08 14:43:08 -08:00
struct adp5588_gpio {
struct i2c_client * client ;
struct gpio_chip gpio_chip ;
struct mutex lock ; /* protect cached dir, dat_out */
2010-10-27 15:33:19 -07:00
/* protect serialized access to the interrupt controller bus */
struct mutex irq_lock ;
2010-01-08 14:43:08 -08:00
uint8_t dat_out [ 3 ] ;
uint8_t dir [ 3 ] ;
2019-02-05 14:31:11 +01:00
uint8_t int_lvl_low [ 3 ] ;
uint8_t int_lvl_high [ 3 ] ;
2010-10-27 15:33:19 -07:00
uint8_t int_en [ 3 ] ;
uint8_t irq_mask [ 3 ] ;
2018-08-13 15:57:44 +02:00
uint8_t int_input_en [ 3 ] ;
2010-01-08 14:43:08 -08:00
} ;
static int adp5588_gpio_read ( struct i2c_client * client , u8 reg )
{
int ret = i2c_smbus_read_byte_data ( client , reg ) ;
if ( ret < 0 )
dev_err ( & client - > dev , " Read Error \n " ) ;
return ret ;
}
static int adp5588_gpio_write ( struct i2c_client * client , u8 reg , u8 val )
{
int ret = i2c_smbus_write_byte_data ( client , reg , val ) ;
if ( ret < 0 )
dev_err ( & client - > dev , " Write Error \n " ) ;
return ret ;
}
static int adp5588_gpio_get_value ( struct gpio_chip * chip , unsigned off )
{
2015-12-04 15:05:34 +01:00
struct adp5588_gpio * dev = gpiochip_get_data ( chip ) ;
2014-02-10 12:05:28 -05:00
unsigned bank = ADP5588_BANK ( off ) ;
unsigned bit = ADP5588_BIT ( off ) ;
int val ;
2010-01-08 14:43:08 -08:00
2014-02-10 12:05:28 -05:00
mutex_lock ( & dev - > lock ) ;
if ( dev - > dir [ bank ] & bit )
val = dev - > dat_out [ bank ] ;
else
val = adp5588_gpio_read ( dev - > client , GPIO_DAT_STAT1 + bank ) ;
mutex_unlock ( & dev - > lock ) ;
return ! ! ( val & bit ) ;
2010-01-08 14:43:08 -08:00
}
static void adp5588_gpio_set_value ( struct gpio_chip * chip ,
unsigned off , int val )
{
unsigned bank , bit ;
2015-12-04 15:05:34 +01:00
struct adp5588_gpio * dev = gpiochip_get_data ( chip ) ;
2010-01-08 14:43:08 -08:00
2010-10-27 15:33:19 -07:00
bank = ADP5588_BANK ( off ) ;
bit = ADP5588_BIT ( off ) ;
2010-01-08 14:43:08 -08:00
mutex_lock ( & dev - > lock ) ;
if ( val )
dev - > dat_out [ bank ] | = bit ;
else
dev - > dat_out [ bank ] & = ~ bit ;
adp5588_gpio_write ( dev - > client , GPIO_DAT_OUT1 + bank ,
dev - > dat_out [ bank ] ) ;
mutex_unlock ( & dev - > lock ) ;
}
static int adp5588_gpio_direction_input ( struct gpio_chip * chip , unsigned off )
{
int ret ;
unsigned bank ;
2015-12-04 15:05:34 +01:00
struct adp5588_gpio * dev = gpiochip_get_data ( chip ) ;
2010-01-08 14:43:08 -08:00
2010-10-27 15:33:19 -07:00
bank = ADP5588_BANK ( off ) ;
2010-01-08 14:43:08 -08:00
mutex_lock ( & dev - > lock ) ;
2010-10-27 15:33:19 -07:00
dev - > dir [ bank ] & = ~ ADP5588_BIT ( off ) ;
2010-01-08 14:43:08 -08:00
ret = adp5588_gpio_write ( dev - > client , GPIO_DIR1 + bank , dev - > dir [ bank ] ) ;
mutex_unlock ( & dev - > lock ) ;
return ret ;
}
static int adp5588_gpio_direction_output ( struct gpio_chip * chip ,
unsigned off , int val )
{
int ret ;
unsigned bank , bit ;
2015-12-04 15:05:34 +01:00
struct adp5588_gpio * dev = gpiochip_get_data ( chip ) ;
2010-01-08 14:43:08 -08:00
2010-10-27 15:33:19 -07:00
bank = ADP5588_BANK ( off ) ;
bit = ADP5588_BIT ( off ) ;
2010-01-08 14:43:08 -08:00
mutex_lock ( & dev - > lock ) ;
dev - > dir [ bank ] | = bit ;
if ( val )
dev - > dat_out [ bank ] | = bit ;
else
dev - > dat_out [ bank ] & = ~ bit ;
ret = adp5588_gpio_write ( dev - > client , GPIO_DAT_OUT1 + bank ,
dev - > dat_out [ bank ] ) ;
ret | = adp5588_gpio_write ( dev - > client , GPIO_DIR1 + bank ,
dev - > dir [ bank ] ) ;
mutex_unlock ( & dev - > lock ) ;
return ret ;
}
2010-10-27 15:33:19 -07:00
# ifdef CONFIG_GPIO_ADP5588_IRQ
2011-01-12 17:00:12 -08:00
static void adp5588_irq_bus_lock ( struct irq_data * d )
2010-10-27 15:33:19 -07:00
{
2018-07-25 10:43:57 +02:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
2011-01-12 17:00:12 -08:00
2010-10-27 15:33:19 -07:00
mutex_lock ( & dev - > irq_lock ) ;
}
/*
* genirq core code can issue chip - > mask / unmask from atomic context .
* This doesn ' t work for slow busses where an access needs to sleep .
* bus_sync_unlock ( ) is therefore called outside the atomic context ,
* syncs the current irq mask state with the slow external controller
* and unlocks the bus .
*/
2011-01-12 17:00:12 -08:00
static void adp5588_irq_bus_sync_unlock ( struct irq_data * d )
2010-10-27 15:33:19 -07:00
{
2018-07-25 10:43:57 +02:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
2010-10-27 15:33:19 -07:00
int i ;
2018-08-13 15:57:44 +02:00
for ( i = 0 ; i < = ADP5588_BANK ( ADP5588_MAXGPIO ) ; i + + ) {
if ( dev - > int_input_en [ i ] ) {
mutex_lock ( & dev - > lock ) ;
dev - > dir [ i ] & = ~ dev - > int_input_en [ i ] ;
dev - > int_input_en [ i ] = 0 ;
adp5588_gpio_write ( dev - > client , GPIO_DIR1 + i ,
dev - > dir [ i ] ) ;
mutex_unlock ( & dev - > lock ) ;
}
2010-10-27 15:33:19 -07:00
if ( dev - > int_en [ i ] ^ dev - > irq_mask [ i ] ) {
dev - > int_en [ i ] = dev - > irq_mask [ i ] ;
2019-02-05 14:31:11 +01:00
adp5588_gpio_write ( dev - > client , GPI_EM1 + i ,
2010-10-27 15:33:19 -07:00
dev - > int_en [ i ] ) ;
}
2018-08-13 15:57:44 +02:00
}
2010-10-27 15:33:19 -07:00
mutex_unlock ( & dev - > irq_lock ) ;
}
2011-01-12 17:00:12 -08:00
static void adp5588_irq_mask ( struct irq_data * d )
2010-10-27 15:33:19 -07:00
{
2018-07-25 10:43:57 +02:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
2010-10-27 15:33:19 -07:00
2018-07-25 10:43:57 +02:00
dev - > irq_mask [ ADP5588_BANK ( d - > hwirq ) ] & = ~ ADP5588_BIT ( d - > hwirq ) ;
2010-10-27 15:33:19 -07:00
}
2011-01-12 17:00:12 -08:00
static void adp5588_irq_unmask ( struct irq_data * d )
2010-10-27 15:33:19 -07:00
{
2018-07-25 10:43:57 +02:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
2010-10-27 15:33:19 -07:00
2018-07-25 10:43:57 +02:00
dev - > irq_mask [ ADP5588_BANK ( d - > hwirq ) ] | = ADP5588_BIT ( d - > hwirq ) ;
2010-10-27 15:33:19 -07:00
}
2011-01-12 17:00:12 -08:00
static int adp5588_irq_set_type ( struct irq_data * d , unsigned int type )
2010-10-27 15:33:19 -07:00
{
2018-07-25 10:43:57 +02:00
struct gpio_chip * gc = irq_data_get_irq_chip_data ( d ) ;
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
uint16_t gpio = d - > hwirq ;
2010-10-27 15:33:19 -07:00
unsigned bank , bit ;
bank = ADP5588_BANK ( gpio ) ;
bit = ADP5588_BIT ( gpio ) ;
2019-02-05 14:31:11 +01:00
dev - > int_lvl_low [ bank ] & = ~ bit ;
dev - > int_lvl_high [ bank ] & = ~ bit ;
if ( type & IRQ_TYPE_EDGE_BOTH | | type & IRQ_TYPE_LEVEL_HIGH )
dev - > int_lvl_high [ bank ] | = bit ;
if ( type & IRQ_TYPE_EDGE_BOTH | | type & IRQ_TYPE_LEVEL_LOW )
dev - > int_lvl_low [ bank ] | = bit ;
2010-10-27 15:33:19 -07:00
2018-08-13 15:57:44 +02:00
dev - > int_input_en [ bank ] | = bit ;
2010-10-27 15:33:19 -07:00
return 0 ;
}
static struct irq_chip adp5588_irq_chip = {
. name = " adp5588 " ,
2011-01-12 17:00:12 -08:00
. irq_mask = adp5588_irq_mask ,
. irq_unmask = adp5588_irq_unmask ,
. irq_bus_lock = adp5588_irq_bus_lock ,
. irq_bus_sync_unlock = adp5588_irq_bus_sync_unlock ,
. irq_set_type = adp5588_irq_set_type ,
2010-10-27 15:33:19 -07:00
} ;
static irqreturn_t adp5588_irq_handler ( int irq , void * devid )
{
struct adp5588_gpio * dev = devid ;
2019-02-05 14:31:11 +01:00
int status = adp5588_gpio_read ( dev - > client , INT_STAT ) ;
if ( status & ADP5588_KE_INT ) {
int ev_cnt = adp5588_gpio_read ( dev - > client , KEY_LCK_EC_STAT ) ;
if ( ev_cnt > 0 ) {
int i ;
for ( i = 0 ; i < ( ev_cnt & ADP5588_KEC ) ; i + + ) {
int key = adp5588_gpio_read ( dev - > client ,
Key_EVENTA + i ) ;
/* GPIN events begin at 97,
* bit 7 indicates logic level
*/
int gpio = ( key & 0x7f ) - 97 ;
int lvl = key & ( 1 < < 7 ) ;
int bank = ADP5588_BANK ( gpio ) ;
int bit = ADP5588_BIT ( gpio ) ;
if ( ( lvl & & dev - > int_lvl_high [ bank ] & bit ) | |
( ! lvl & & dev - > int_lvl_low [ bank ] & bit ) )
handle_nested_irq ( irq_find_mapping (
dev - > gpio_chip . irq . domain , gpio ) ) ;
2010-10-27 15:33:19 -07:00
}
}
}
adp5588_gpio_write ( dev - > client , INT_STAT , status ) ; /* Status is W1C */
return IRQ_HANDLED ;
}
2020-07-16 17:05:02 +02:00
static int adp5588_irq_init_hw ( struct gpio_chip * gc )
{
struct adp5588_gpio * dev = gpiochip_get_data ( gc ) ;
/* Enable IRQs after registering chip */
adp5588_gpio_write ( dev - > client , CFG ,
ADP5588_AUTO_INC | ADP5588_INT_CFG | ADP5588_KE_IEN ) ;
return 0 ;
}
2010-10-27 15:33:19 -07:00
static int adp5588_irq_setup ( struct adp5588_gpio * dev )
{
struct i2c_client * client = dev - > client ;
2018-07-25 10:43:57 +02:00
int ret ;
2013-07-30 17:08:05 +09:00
struct adp5588_gpio_platform_data * pdata =
dev_get_platdata ( & client - > dev ) ;
2020-07-16 17:05:02 +02:00
struct gpio_irq_chip * girq ;
2010-10-27 15:33:19 -07:00
adp5588_gpio_write ( client , CFG , ADP5588_AUTO_INC ) ;
adp5588_gpio_write ( client , INT_STAT , - 1 ) ; /* status is W1C */
mutex_init ( & dev - > irq_lock ) ;
2018-07-25 10:43:57 +02:00
ret = devm_request_threaded_irq ( & client - > dev , client - > irq ,
NULL , adp5588_irq_handler , IRQF_ONESHOT
| IRQF_TRIGGER_FALLING | IRQF_SHARED ,
dev_name ( & client - > dev ) , dev ) ;
2010-10-27 15:33:19 -07:00
if ( ret ) {
dev_err ( & client - > dev , " failed to request irq %d \n " ,
client - > irq ) ;
2018-07-25 10:43:57 +02:00
return ret ;
}
2010-10-27 15:33:19 -07:00
2020-07-16 17:05:02 +02:00
/* This will be registered in the call to devm_gpiochip_add_data() */
girq = & dev - > gpio_chip . irq ;
girq - > chip = & adp5588_irq_chip ;
/* This will let us handle the parent IRQ in the driver */
girq - > parent_handler = NULL ;
girq - > num_parents = 0 ;
girq - > parents = NULL ;
girq - > first = pdata ? pdata - > irq_base : 0 ;
girq - > default_type = IRQ_TYPE_NONE ;
girq - > handler = handle_simple_irq ;
girq - > init_hw = adp5588_irq_init_hw ;
girq - > threaded = true ;
2010-10-27 15:33:19 -07:00
return 0 ;
}
# else
static int adp5588_irq_setup ( struct adp5588_gpio * dev )
{
struct i2c_client * client = dev - > client ;
dev_warn ( & client - > dev , " interrupt support not compiled in \n " ) ;
return 0 ;
}
# endif /* CONFIG_GPIO_ADP5588_IRQ */
2018-07-25 10:43:57 +02:00
static int adp5588_gpio_probe ( struct i2c_client * client )
2010-01-08 14:43:08 -08:00
{
2013-07-30 17:08:05 +09:00
struct adp5588_gpio_platform_data * pdata =
dev_get_platdata ( & client - > dev ) ;
2010-01-08 14:43:08 -08:00
struct adp5588_gpio * dev ;
struct gpio_chip * gc ;
int ret , i , revid ;
2018-07-25 10:43:57 +02:00
unsigned int pullup_dis_mask = 0 ;
2010-01-08 14:43:08 -08:00
if ( ! i2c_check_functionality ( client - > adapter ,
I2C_FUNC_SMBUS_BYTE_DATA ) ) {
dev_err ( & client - > dev , " SMBUS Byte Data not Supported \n " ) ;
return - EIO ;
}
2015-03-31 09:49:08 +05:30
dev = devm_kzalloc ( & client - > dev , sizeof ( * dev ) , GFP_KERNEL ) ;
2015-03-31 09:49:11 +05:30
if ( ! dev )
2010-01-08 14:43:08 -08:00
return - ENOMEM ;
dev - > client = client ;
gc = & dev - > gpio_chip ;
gc - > direction_input = adp5588_gpio_direction_input ;
gc - > direction_output = adp5588_gpio_direction_output ;
gc - > get = adp5588_gpio_get_value ;
gc - > set = adp5588_gpio_set_value ;
2013-12-04 14:42:46 +01:00
gc - > can_sleep = true ;
2018-07-25 10:43:57 +02:00
gc - > base = - 1 ;
gc - > parent = & client - > dev ;
if ( pdata ) {
gc - > base = pdata - > gpio_start ;
gc - > names = pdata - > names ;
pullup_dis_mask = pdata - > pullup_dis_mask ;
}
2010-01-08 14:43:08 -08:00
2010-10-27 15:33:19 -07:00
gc - > ngpio = ADP5588_MAXGPIO ;
2010-01-08 14:43:08 -08:00
gc - > label = client - > name ;
gc - > owner = THIS_MODULE ;
mutex_init ( & dev - > lock ) ;
ret = adp5588_gpio_read ( dev - > client , DEV_ID ) ;
if ( ret < 0 )
2018-07-25 10:43:57 +02:00
return ret ;
2010-01-08 14:43:08 -08:00
revid = ret & ADP5588_DEVICE_ID_MASK ;
2010-10-27 15:33:19 -07:00
for ( i = 0 , ret = 0 ; i < = ADP5588_BANK ( ADP5588_MAXGPIO ) ; i + + ) {
2010-01-08 14:43:08 -08:00
dev - > dat_out [ i ] = adp5588_gpio_read ( client , GPIO_DAT_OUT1 + i ) ;
dev - > dir [ i ] = adp5588_gpio_read ( client , GPIO_DIR1 + i ) ;
ret | = adp5588_gpio_write ( client , KP_GPIO1 + i , 0 ) ;
ret | = adp5588_gpio_write ( client , GPIO_PULL1 + i ,
2018-07-25 10:43:57 +02:00
( pullup_dis_mask > > ( 8 * i ) ) & 0xFF ) ;
2010-10-27 15:33:19 -07:00
ret | = adp5588_gpio_write ( client , GPIO_INT_EN1 + i , 0 ) ;
2010-01-08 14:43:08 -08:00
if ( ret )
2018-07-25 10:43:57 +02:00
return ret ;
2010-01-08 14:43:08 -08:00
}
2018-07-25 10:43:57 +02:00
if ( client - > irq ) {
2010-10-27 15:33:19 -07:00
if ( WA_DELAYED_READOUT_REVID ( revid ) ) {
dev_warn ( & client - > dev , " GPIO int not supported \n " ) ;
} else {
ret = adp5588_irq_setup ( dev ) ;
if ( ret )
2018-07-25 10:43:57 +02:00
return ret ;
2010-10-27 15:33:19 -07:00
}
}
2016-02-22 17:43:28 +05:30
ret = devm_gpiochip_add_data ( & client - > dev , & dev - > gpio_chip , dev ) ;
2010-01-08 14:43:08 -08:00
if ( ret )
2018-07-25 10:43:57 +02:00
return ret ;
2010-01-08 14:43:08 -08:00
i2c_set_clientdata ( client , dev ) ;
2010-10-27 15:33:19 -07:00
2010-01-08 14:43:08 -08:00
return 0 ;
}
2012-11-19 13:25:50 -05:00
static int adp5588_gpio_remove ( struct i2c_client * client )
2010-01-08 14:43:08 -08:00
{
struct adp5588_gpio * dev = i2c_get_clientdata ( client ) ;
2018-07-25 10:43:57 +02:00
if ( dev - > client - > irq )
2010-10-27 15:33:19 -07:00
free_irq ( dev - > client - > irq , dev ) ;
2010-01-08 14:43:08 -08:00
return 0 ;
}
static const struct i2c_device_id adp5588_gpio_id [ ] = {
2022-06-28 22:39:04 +03:00
{ " adp5588-gpio " } ,
2010-01-08 14:43:08 -08:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , adp5588_gpio_id ) ;
2018-07-25 10:43:57 +02:00
static const struct of_device_id adp5588_gpio_of_id [ ] = {
2022-06-28 22:39:04 +03:00
{ . compatible = " adi,adp5588-gpio " } ,
{ }
2018-07-25 10:43:57 +02:00
} ;
MODULE_DEVICE_TABLE ( of , adp5588_gpio_of_id ) ;
2010-01-08 14:43:08 -08:00
static struct i2c_driver adp5588_gpio_driver = {
. driver = {
2022-06-28 22:39:04 +03:00
. name = " adp5588-gpio " ,
2022-06-28 22:39:03 +03:00
. of_match_table = adp5588_gpio_of_id ,
2018-07-25 10:43:57 +02:00
} ,
. probe_new = adp5588_gpio_probe ,
2012-11-19 13:20:08 -05:00
. remove = adp5588_gpio_remove ,
2010-01-08 14:43:08 -08:00
. id_table = adp5588_gpio_id ,
} ;
2012-09-02 08:08:01 +08:00
module_i2c_driver ( adp5588_gpio_driver ) ;
2010-01-08 14:43:08 -08:00
2018-08-14 13:29:18 +02:00
MODULE_AUTHOR ( " Michael Hennerich <michael.hennerich@analog.com> " ) ;
2010-01-08 14:43:08 -08:00
MODULE_DESCRIPTION ( " GPIO ADP5588 Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;