2019-03-25 16:47:48 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2010-10-28 02:33:18 +04:00
/*
* 74 Hx164 - Generic serial - in / parallel - out 8 - bits shift register GPIO driver
*
* Copyright ( C ) 2010 Gabor Juhos < juhosg @ openwrt . org >
* Copyright ( C ) 2010 Miguel Gaio < miguel . gaio @ efixo . com >
*/
2019-12-05 03:51:29 +03:00
# include <linux/bitops.h>
2018-01-14 00:07:09 +03:00
# include <linux/gpio/consumer.h>
2019-03-25 16:47:47 +03:00
# include <linux/gpio/driver.h>
# include <linux/module.h>
# include <linux/mutex.h>
2019-03-25 16:47:46 +03:00
# include <linux/property.h>
2010-10-28 02:33:18 +04:00
# include <linux/slab.h>
2019-03-25 16:47:47 +03:00
# include <linux/spi/spi.h>
2010-10-28 02:33:18 +04:00
2012-09-11 00:35:39 +04:00
# define GEN_74X164_NUMBER_GPIOS 8
2010-10-28 02:33:18 +04:00
struct gen_74x164_chip {
struct gpio_chip gpio_chip ;
struct mutex lock ;
2017-11-21 17:18:10 +03:00
struct gpio_desc * gpiod_oe ;
2012-09-11 00:35:39 +04:00
u32 registers ;
2015-11-30 17:35:26 +03:00
/*
* Since the registers are chained , every byte sent will make
* the previous byte shift to the next register in the
* chain . Thus , the first byte sent will end up in the last
* register at the end of the transfer . So , to have a logical
* numbering , store the bytes in reverse order .
*/
2017-11-21 17:18:10 +03:00
u8 buffer [ ] ;
2010-10-28 02:33:18 +04:00
} ;
static int __gen_74x164_write_config ( struct gen_74x164_chip * chip )
{
2016-06-17 19:39:28 +03:00
return spi_write ( to_spi_device ( chip - > gpio_chip . parent ) , chip - > buffer ,
chip - > registers ) ;
2010-10-28 02:33:18 +04:00
}
static int gen_74x164_get_value ( struct gpio_chip * gc , unsigned offset )
{
2015-12-03 20:20:29 +03:00
struct gen_74x164_chip * chip = gpiochip_get_data ( gc ) ;
2015-11-30 17:35:26 +03:00
u8 bank = chip - > registers - 1 - offset / 8 ;
2012-09-11 00:35:39 +04:00
u8 pin = offset % 8 ;
2010-10-28 02:33:18 +04:00
int ret ;
mutex_lock ( & chip - > lock ) ;
2012-09-11 00:35:39 +04:00
ret = ( chip - > buffer [ bank ] > > pin ) & 0x1 ;
2010-10-28 02:33:18 +04:00
mutex_unlock ( & chip - > lock ) ;
return ret ;
}
static void gen_74x164_set_value ( struct gpio_chip * gc ,
unsigned offset , int val )
{
2015-12-03 20:20:29 +03:00
struct gen_74x164_chip * chip = gpiochip_get_data ( gc ) ;
2015-11-30 17:35:26 +03:00
u8 bank = chip - > registers - 1 - offset / 8 ;
2012-09-11 00:35:39 +04:00
u8 pin = offset % 8 ;
2010-10-28 02:33:18 +04:00
mutex_lock ( & chip - > lock ) ;
if ( val )
2012-09-11 00:35:39 +04:00
chip - > buffer [ bank ] | = ( 1 < < pin ) ;
2010-10-28 02:33:18 +04:00
else
2012-09-11 00:35:39 +04:00
chip - > buffer [ bank ] & = ~ ( 1 < < pin ) ;
2010-10-28 02:33:18 +04:00
__gen_74x164_write_config ( chip ) ;
mutex_unlock ( & chip - > lock ) ;
}
2016-03-14 18:19:18 +03:00
static void gen_74x164_set_multiple ( struct gpio_chip * gc , unsigned long * mask ,
unsigned long * bits )
{
struct gen_74x164_chip * chip = gpiochip_get_data ( gc ) ;
2019-12-05 03:51:29 +03:00
unsigned long offset ;
unsigned long bankmask ;
size_t bank ;
unsigned long bitmask ;
2016-03-14 18:19:18 +03:00
mutex_lock ( & chip - > lock ) ;
2019-12-05 03:51:29 +03:00
for_each_set_clump8 ( offset , bankmask , mask , chip - > registers * 8 ) {
bank = chip - > registers - 1 - offset / 8 ;
bitmask = bitmap_get_value8 ( bits , offset ) & bankmask ;
2016-03-14 18:19:18 +03:00
chip - > buffer [ bank ] & = ~ bankmask ;
2019-12-05 03:51:29 +03:00
chip - > buffer [ bank ] | = bitmask ;
2016-03-14 18:19:18 +03:00
}
__gen_74x164_write_config ( chip ) ;
mutex_unlock ( & chip - > lock ) ;
}
2011-05-28 03:35:59 +04:00
static int gen_74x164_direction_output ( struct gpio_chip * gc ,
unsigned offset , int val )
{
gen_74x164_set_value ( gc , offset , val ) ;
return 0 ;
}
2012-11-19 22:22:34 +04:00
static int gen_74x164_probe ( struct spi_device * spi )
2010-10-28 02:33:18 +04:00
{
struct gen_74x164_chip * chip ;
2015-11-30 17:35:25 +03:00
u32 nregs ;
2010-10-28 02:33:18 +04:00
int ret ;
/*
* bits_per_word cannot be configured in platform data
*/
spi - > bits_per_word = 8 ;
ret = spi_setup ( spi ) ;
if ( ret < 0 )
return ret ;
2019-03-25 16:47:46 +03:00
ret = device_property_read_u32 ( & spi - > dev , " registers-number " , & nregs ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Missing 'registers-number' property. \n " ) ;
2015-11-30 17:35:25 +03:00
return - EINVAL ;
}
chip = devm_kzalloc ( & spi - > dev , sizeof ( * chip ) + nregs , GFP_KERNEL ) ;
2010-10-28 02:33:18 +04:00
if ( ! chip )
return - ENOMEM ;
2017-08-07 15:41:50 +03:00
chip - > gpiod_oe = devm_gpiod_get_optional ( & spi - > dev , " enable " ,
GPIOD_OUT_LOW ) ;
if ( IS_ERR ( chip - > gpiod_oe ) )
return PTR_ERR ( chip - > gpiod_oe ) ;
gpiod_set_value_cansleep ( chip - > gpiod_oe , 1 ) ;
2013-03-15 13:17:18 +04:00
spi_set_drvdata ( spi , chip ) ;
2010-10-28 02:33:18 +04:00
2011-05-28 03:35:59 +04:00
chip - > gpio_chip . label = spi - > modalias ;
chip - > gpio_chip . direction_output = gen_74x164_direction_output ;
2010-10-28 02:33:18 +04:00
chip - > gpio_chip . get = gen_74x164_get_value ;
chip - > gpio_chip . set = gen_74x164_set_value ;
2016-03-14 18:19:18 +03:00
chip - > gpio_chip . set_multiple = gen_74x164_set_multiple ;
2013-12-07 14:08:22 +04:00
chip - > gpio_chip . base = - 1 ;
2012-09-11 00:35:39 +04:00
2015-11-30 17:35:25 +03:00
chip - > registers = nregs ;
2012-09-11 00:35:39 +04:00
chip - > gpio_chip . ngpio = GEN_74X164_NUMBER_GPIOS * chip - > registers ;
2013-12-04 17:42:46 +04:00
chip - > gpio_chip . can_sleep = true ;
2015-11-04 11:56:26 +03:00
chip - > gpio_chip . parent = & spi - > dev ;
2010-10-28 02:33:18 +04:00
chip - > gpio_chip . owner = THIS_MODULE ;
2013-12-07 14:08:23 +04:00
mutex_init ( & chip - > lock ) ;
2010-10-28 02:33:18 +04:00
ret = __gen_74x164_write_config ( chip ) ;
if ( ret ) {
dev_err ( & spi - > dev , " Failed writing: %d \n " , ret ) ;
goto exit_destroy ;
}
2015-12-03 20:20:29 +03:00
ret = gpiochip_add_data ( & chip - > gpio_chip , chip ) ;
2013-12-07 14:08:23 +04:00
if ( ! ret )
return 0 ;
2010-10-28 02:33:18 +04:00
exit_destroy :
mutex_destroy ( & chip - > lock ) ;
2013-12-07 14:08:23 +04:00
2010-10-28 02:33:18 +04:00
return ret ;
}
2022-01-23 20:52:01 +03:00
static void gen_74x164_remove ( struct spi_device * spi )
2010-10-28 02:33:18 +04:00
{
2013-12-07 14:08:23 +04:00
struct gen_74x164_chip * chip = spi_get_drvdata ( spi ) ;
2010-10-28 02:33:18 +04:00
2017-08-07 15:41:50 +03:00
gpiod_set_value_cansleep ( chip - > gpiod_oe , 0 ) ;
2014-07-13 00:30:12 +04:00
gpiochip_remove ( & chip - > gpio_chip ) ;
mutex_destroy ( & chip - > lock ) ;
2010-10-28 02:33:18 +04:00
}
2021-09-22 19:17:36 +03:00
static const struct spi_device_id gen_74x164_spi_ids [ ] = {
{ . name = " 74hc595 " } ,
{ . name = " 74lvc594 " } ,
{ } ,
} ;
MODULE_DEVICE_TABLE ( spi , gen_74x164_spi_ids ) ;
2012-09-07 16:18:13 +04:00
static const struct of_device_id gen_74x164_dt_ids [ ] = {
{ . compatible = " fairchild,74hc595 " } ,
2016-03-15 02:32:10 +03:00
{ . compatible = " nxp,74lvc594 " } ,
2012-09-07 16:18:13 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( of , gen_74x164_dt_ids ) ;
2010-10-28 02:33:18 +04:00
static struct spi_driver gen_74x164_driver = {
. driver = {
2011-05-28 03:35:59 +04:00
. name = " 74x164 " ,
2013-09-19 15:58:08 +04:00
. of_match_table = gen_74x164_dt_ids ,
2010-10-28 02:33:18 +04:00
} ,
. probe = gen_74x164_probe ,
2012-11-19 22:20:08 +04:00
. remove = gen_74x164_remove ,
2021-09-22 19:17:36 +03:00
. id_table = gen_74x164_spi_ids ,
2010-10-28 02:33:18 +04:00
} ;
2012-09-05 12:40:50 +04:00
module_spi_driver ( gen_74x164_driver ) ;
2010-10-28 02:33:18 +04:00
MODULE_AUTHOR ( " Gabor Juhos <juhosg@openwrt.org> " ) ;
MODULE_AUTHOR ( " Miguel Gaio <miguel.gaio@efixo.com> " ) ;
MODULE_DESCRIPTION ( " GPIO expander driver for 74X164 8-bits shift register " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;