2018-11-22 16:59:01 +03:00
// SPDX-License-Identifier: GPL-2.0+
2008-04-11 17:06:45 +04:00
/*
* OF helpers for the GPIO API
*
* Copyright ( c ) 2007 - 2008 MontaVista Software , Inc .
*
* Author : Anton Vorontsov < avorontsov @ ru . mvista . com >
*/
2010-07-06 02:11:55 +04:00
# include <linux/device.h>
2014-01-27 10:45:08 +04:00
# include <linux/err.h>
2008-04-11 17:06:45 +04:00
# include <linux/errno.h>
# include <linux/io.h>
2023-02-08 20:07:28 +03:00
# include <linux/module.h>
2008-04-11 17:06:45 +04:00
# include <linux/of.h>
2010-07-06 02:11:55 +04:00
# include <linux/of_address.h>
2008-04-11 17:06:45 +04:00
# include <linux/of_gpio.h>
2012-10-27 13:51:36 +04:00
# include <linux/pinctrl/pinctrl.h>
2010-07-06 02:11:55 +04:00
# include <linux/slab.h>
2023-02-08 20:07:28 +03:00
# include <linux/string.h>
# include <linux/gpio/consumer.h>
2015-02-02 20:44:44 +03:00
# include <linux/gpio/machine.h>
2008-04-11 17:06:45 +04:00
2014-07-22 11:17:41 +04:00
# include "gpiolib.h"
2019-07-17 10:10:01 +03:00
# include "gpiolib-of.h"
2023-01-12 17:51:40 +03:00
/*
* This is Linux - specific flags . By default controllers ' and Linux ' mapping
* match , but GPIO controllers are free to translate their own flags to
* Linux - specific in their . xlate callback . Though , 1 : 1 mapping is recommended .
*/
enum of_gpio_flags {
OF_GPIO_ACTIVE_LOW = 0x1 ,
OF_GPIO_SINGLE_ENDED = 0x2 ,
OF_GPIO_OPEN_DRAIN = 0x4 ,
OF_GPIO_TRANSITORY = 0x8 ,
OF_GPIO_PULL_UP = 0x10 ,
OF_GPIO_PULL_DOWN = 0x20 ,
OF_GPIO_PULL_DISABLE = 0x40 ,
} ;
2022-12-19 22:20:13 +03:00
/**
* of_gpio_named_count ( ) - Count GPIOs for a device
* @ np : device node to count GPIOs for
* @ propname : property name containing gpio specifier ( s )
*
* The function returns the count of GPIOs specified for a node .
* Note that the empty GPIO specifiers count too . Returns either
* Number of gpios defined in property ,
* - EINVAL for an incorrectly formed gpios property , or
* - ENOENT for a missing gpios property
*
* Example :
* gpios = < 0
* & gpio1 1 2
* 0
* & gpio2 3 4 > ;
*
* The above example defines four GPIOs , two of which are not specified .
* This function will return ' 4 '
*/
static int of_gpio_named_count ( const struct device_node * np ,
const char * propname )
{
return of_count_phandle_with_args ( np , propname , " #gpio-cells " ) ;
}
2019-11-28 11:37:17 +03:00
/**
* of_gpio_spi_cs_get_count ( ) - special GPIO counting for SPI
2020-06-30 16:33:36 +03:00
* @ dev : Consuming device
* @ con_id : Function within the GPIO consumer
*
2019-11-28 11:37:17 +03:00
* Some elder GPIO controllers need special quirks . Currently we handle
2020-07-14 10:22:26 +03:00
* the Freescale and PPC GPIO controller with bindings that doesn ' t use the
2019-11-28 11:37:17 +03:00
* established " cs-gpios " for chip selects but instead rely on
* " gpios " for the chip select lines . If we detect this , we redirect
* the counting of " cs-gpios " to count " gpios " transparent to the
* driver .
*/
2019-11-30 04:28:28 +03:00
static int of_gpio_spi_cs_get_count ( struct device * dev , const char * con_id )
2019-11-28 11:37:17 +03:00
{
struct device_node * np = dev - > of_node ;
if ( ! IS_ENABLED ( CONFIG_SPI_MASTER ) )
return 0 ;
if ( ! con_id | | strcmp ( con_id , " cs " ) )
return 0 ;
if ( ! of_device_is_compatible ( np , " fsl,spi " ) & &
2020-07-14 10:22:26 +03:00
! of_device_is_compatible ( np , " aeroflexgaisler,spictrl " ) & &
! of_device_is_compatible ( np , " ibm,ppc4xx-spi " ) )
2019-11-28 11:37:17 +03:00
return 0 ;
return of_gpio_named_count ( np , " gpios " ) ;
}
2019-07-17 10:10:01 +03:00
int of_gpio_get_count ( struct device * dev , const char * con_id )
{
int ret ;
char propname [ 32 ] ;
unsigned int i ;
2019-11-28 11:37:17 +03:00
ret = of_gpio_spi_cs_get_count ( dev , con_id ) ;
if ( ret > 0 )
return ret ;
2019-07-17 10:10:01 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( gpio_suffixes ) ; i + + ) {
if ( con_id )
snprintf ( propname , sizeof ( propname ) , " %s-%s " ,
con_id , gpio_suffixes [ i ] ) ;
else
snprintf ( propname , sizeof ( propname ) , " %s " ,
gpio_suffixes [ i ] ) ;
ret = of_gpio_named_count ( dev - > of_node , propname ) ;
if ( ret > 0 )
break ;
}
return ret ? ret : - ENOENT ;
}
2013-10-17 21:21:37 +04:00
2016-10-25 04:47:44 +03:00
static int of_gpiochip_match_node_and_xlate ( struct gpio_chip * chip , void * data )
2012-05-17 23:54:40 +04:00
{
2016-10-25 04:47:44 +03:00
struct of_phandle_args * gpiospec = data ;
2022-11-03 23:30:05 +03:00
return device_match_of_node ( & chip - > gpiodev - > dev , gpiospec - > np ) & &
2018-08-31 10:04:18 +03:00
chip - > of_xlate & &
2016-10-25 04:47:44 +03:00
chip - > of_xlate ( chip , gpiospec , NULL ) > = 0 ;
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
}
2012-05-17 23:54:40 +04:00
2016-10-25 04:47:44 +03:00
static struct gpio_chip * of_find_gpiochip_by_xlate (
struct of_phandle_args * gpiospec )
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
{
2016-10-25 04:47:44 +03:00
return gpiochip_find ( gpiospec , of_gpiochip_match_node_and_xlate ) ;
2012-05-17 23:54:40 +04:00
}
2016-06-14 13:07:07 +03:00
static struct gpio_desc * of_xlate_and_get_gpiod_flags ( struct gpio_chip * chip ,
struct of_phandle_args * gpiospec ,
enum of_gpio_flags * flags )
2012-05-17 23:54:40 +04:00
{
int ret ;
2016-06-14 13:07:07 +03:00
if ( chip - > of_gpio_n_cells ! = gpiospec - > args_count )
return ERR_PTR ( - EINVAL ) ;
ret = chip - > of_xlate ( chip , gpiospec , flags ) ;
if ( ret < 0 )
return ERR_PTR ( ret ) ;
return gpiochip_get_desc ( chip , ret ) ;
2012-05-17 23:54:40 +04:00
}
2022-10-18 08:41:09 +03:00
/*
* Overrides stated polarity of a gpio line and warns when there is a
* discrepancy .
*/
static void of_gpio_quirk_polarity ( const struct device_node * np ,
bool active_high ,
enum of_gpio_flags * flags )
{
if ( active_high ) {
if ( * flags & OF_GPIO_ACTIVE_LOW ) {
pr_warn ( " %s GPIO handle specifies active low - ignored \n " ,
of_node_full_name ( np ) ) ;
* flags & = ~ OF_GPIO_ACTIVE_LOW ;
}
} else {
if ( ! ( * flags & OF_GPIO_ACTIVE_LOW ) )
pr_info ( " %s enforce active low on GPIO handle \n " ,
of_node_full_name ( np ) ) ;
* flags | = OF_GPIO_ACTIVE_LOW ;
}
}
2022-10-18 08:41:11 +03:00
/*
* This quirk does static polarity overrides in cases where existing
* DTS specified incorrect polarity .
*/
static void of_gpio_try_fixup_polarity ( const struct device_node * np ,
const char * propname ,
enum of_gpio_flags * flags )
{
static const struct {
const char * compatible ;
const char * propname ;
bool active_high ;
} gpios [ ] = {
# if !IS_ENABLED(CONFIG_LCD_HX8357)
/*
* Himax LCD controllers used incorrectly named
* " gpios-reset " property and also specified wrong
* polarity .
*/
{ " himax,hx8357 " , " gpios-reset " , false } ,
{ " himax,hx8369 " , " gpios-reset " , false } ,
2023-09-26 12:06:23 +03:00
/*
* The rb - gpios semantics was undocumented and qi , lb60 ( along with
* the ingenic driver ) got it wrong . The active state encodes the
* NAND ready state , which is high level . Since there ' s no signal
* inverter on this board , it should be active - high . Let ' s fix that
* here for older DTs so we can re - use the generic nand_gpio_waitrdy ( )
* helper , and be consistent with what other drivers do .
*/
{ " qi,lb60 " , " rb-gpios " , true } ,
2022-10-18 08:41:11 +03:00
# endif
} ;
unsigned int i ;
for ( i = 0 ; i < ARRAY_SIZE ( gpios ) ; i + + ) {
if ( of_device_is_compatible ( np , gpios [ i ] . compatible ) & &
! strcmp ( propname , gpios [ i ] . propname ) ) {
of_gpio_quirk_polarity ( np , gpios [ i ] . active_high , flags ) ;
break ;
}
}
}
2022-10-30 07:40:46 +03:00
static void of_gpio_set_polarity_by_property ( const struct device_node * np ,
const char * propname ,
enum of_gpio_flags * flags )
2017-12-30 18:26:36 +03:00
{
2023-08-25 12:51:57 +03:00
const struct device_node * np_compat = np ;
const struct device_node * np_propname = np ;
2022-10-30 07:40:46 +03:00
static const struct {
const char * compatible ;
const char * gpio_propname ;
const char * polarity_propname ;
} gpios [ ] = {
# if IS_ENABLED(CONFIG_FEC)
/* Freescale Fast Ethernet Controller */
{ " fsl,imx25-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx27-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx28-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx6q-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,mvf600-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx6sx-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx6ul-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx8mq-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,imx8qm-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
{ " fsl,s32v234-fec " , " phy-reset-gpios " , " phy-reset-active-high " } ,
# endif
2022-10-30 07:40:47 +03:00
# if IS_ENABLED(CONFIG_PCI_IMX6)
{ " fsl,imx6q-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx6sx-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx6qp-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx7d-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx8mq-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx8mm-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
{ " fsl,imx8mp-pcie " , " reset-gpio " , " reset-gpio-active-high " } ,
# endif
2022-10-18 08:41:11 +03:00
2017-12-30 18:26:36 +03:00
/*
* The regulator GPIO handles are specified such that the
* presence or absence of " enable-active-high " solely controls
* the polarity of the GPIO line . Any phandle flags must
* be actively ignored .
*/
2022-10-30 07:40:46 +03:00
# if IS_ENABLED(CONFIG_REGULATOR_FIXED_VOLTAGE)
{ " regulator-fixed " , " gpios " , " enable-active-high " } ,
{ " regulator-fixed " , " gpio " , " enable-active-high " } ,
{ " reg-fixed-voltage " , " gpios " , " enable-active-high " } ,
{ " reg-fixed-voltage " , " gpio " , " enable-active-high " } ,
# endif
# if IS_ENABLED(CONFIG_REGULATOR_GPIO)
{ " regulator-gpio " , " enable-gpio " , " enable-active-high " } ,
{ " regulator-gpio " , " enable-gpios " , " enable-active-high " } ,
2023-08-25 12:51:57 +03:00
# endif
# if IS_ENABLED(CONFIG_MMC_ATMELMCI)
{ " atmel,hsmci " , " cd-gpios " , " cd-inverted " } ,
2022-10-30 07:40:46 +03:00
# endif
} ;
unsigned int i ;
bool active_high ;
2023-08-25 12:51:57 +03:00
# if IS_ENABLED(CONFIG_MMC_ATMELMCI)
/*
* The Atmel HSMCI has compatible property in the parent node and
* gpio property in a child node
*/
if ( of_device_is_compatible ( np - > parent , " atmel,hsmci " ) ) {
np_compat = np - > parent ;
np_propname = np ;
}
# endif
2022-10-30 07:40:46 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( gpios ) ; i + + ) {
2023-08-25 12:51:57 +03:00
if ( of_device_is_compatible ( np_compat , gpios [ i ] . compatible ) & &
2022-10-30 07:40:46 +03:00
! strcmp ( propname , gpios [ i ] . gpio_propname ) ) {
2023-08-25 12:51:57 +03:00
active_high = of_property_read_bool ( np_propname ,
2022-10-30 07:40:46 +03:00
gpios [ i ] . polarity_propname ) ;
of_gpio_quirk_polarity ( np , active_high , flags ) ;
break ;
}
2017-12-30 18:26:36 +03:00
}
2022-10-30 07:40:46 +03:00
}
static void of_gpio_flags_quirks ( const struct device_node * np ,
const char * propname ,
enum of_gpio_flags * flags ,
int index )
{
of_gpio_try_fixup_polarity ( np , propname , flags ) ;
of_gpio_set_polarity_by_property ( np , propname , flags ) ;
2017-12-30 18:26:36 +03:00
/*
* Legacy open drain handling for fixed voltage regulators .
*/
if ( IS_ENABLED ( CONFIG_REGULATOR ) & &
of_device_is_compatible ( np , " reg-fixed-voltage " ) & &
of_property_read_bool ( np , " gpio-open-drain " ) ) {
* flags | = ( OF_GPIO_SINGLE_ENDED | OF_GPIO_OPEN_DRAIN ) ;
pr_info ( " %s uses legacy open drain flag - update the DTS if you can \n " ,
of_node_full_name ( np ) ) ;
}
2018-09-04 12:01:58 +03:00
/*
* Legacy handling of SPI active high chip select . If we have a
* property named " cs-gpios " we need to inspect the child node
* to determine if the flags should have inverted semantics .
*/
2019-07-15 23:45:29 +03:00
if ( IS_ENABLED ( CONFIG_SPI_MASTER ) & & ! strcmp ( propname , " cs-gpios " ) & &
2019-03-29 11:42:29 +03:00
of_property_read_bool ( np , " cs-gpios " ) ) {
2018-09-04 12:01:58 +03:00
struct device_node * child ;
u32 cs ;
int ret ;
for_each_child_of_node ( np , child ) {
ret = of_property_read_u32 ( child , " reg " , & cs ) ;
2019-01-16 11:21:10 +03:00
if ( ret )
2018-09-04 12:01:58 +03:00
continue ;
if ( cs = = index ) {
/*
* SPI children have active low chip selects
* by default . This can be specified negatively
* by just omitting " spi-cs-high " in the
* device node , or actively by tagging on
* GPIO_ACTIVE_LOW as flag in the device
* tree . If the line is simultaneously
* tagged as active low in the device tree
* and has the " spi-cs-high " set , we get a
* conflict and the " spi-cs-high " flag will
* take precedence .
*/
2022-10-18 08:41:09 +03:00
bool active_high = of_property_read_bool ( child ,
" spi-cs-high " ) ;
of_gpio_quirk_polarity ( child , active_high ,
flags ) ;
2019-07-06 16:34:22 +03:00
of_node_put ( child ) ;
2018-09-04 12:01:58 +03:00
break ;
}
}
}
2019-06-10 20:05:23 +03:00
/* Legacy handling of stmmac's active-low PHY reset line */
if ( IS_ENABLED ( CONFIG_STMMAC_ETH ) & &
! strcmp ( propname , " snps,reset-gpio " ) & &
of_property_read_bool ( np , " snps,reset-active-low " ) )
* flags | = OF_GPIO_ACTIVE_LOW ;
2017-12-30 18:26:36 +03:00
}
2008-04-11 17:06:45 +04:00
/**
2013-10-17 21:21:37 +04:00
* of_get_named_gpiod_flags ( ) - Get a GPIO descriptor and flags for GPIO API
2008-04-11 17:06:45 +04:00
* @ np : device node to get GPIO from
2011-06-28 03:49:57 +04:00
* @ propname : property name containing gpio specifier ( s )
2008-04-11 17:06:45 +04:00
* @ index : index of the GPIO
2008-12-01 09:30:04 +03:00
* @ flags : a flags pointer to fill in
2008-04-11 17:06:45 +04:00
*
2013-10-17 21:21:37 +04:00
* Returns GPIO descriptor to use with Linux GPIO API , or one of the errno
2008-12-01 09:30:04 +03:00
* value on the error condition . If @ flags is not NULL the function also fills
* in flags for the GPIO .
2008-04-11 17:06:45 +04:00
*/
2021-07-28 17:42:28 +03:00
static struct gpio_desc * of_get_named_gpiod_flags ( const struct device_node * np ,
2013-10-17 21:21:37 +04:00
const char * propname , int index , enum of_gpio_flags * flags )
2008-04-11 17:06:45 +04:00
{
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
struct of_phandle_args gpiospec ;
struct gpio_chip * chip ;
struct gpio_desc * desc ;
2008-10-10 08:43:17 +04:00
int ret ;
2012-05-17 23:54:40 +04:00
2018-01-31 05:36:18 +03:00
ret = of_parse_phandle_with_args_map ( np , propname , " gpio " , index ,
& gpiospec ) ;
2008-10-10 08:43:17 +04:00
if ( ret ) {
2017-07-19 00:43:03 +03:00
pr_debug ( " %s: can't parse '%s' property of node '%pOF[%d]' \n " ,
__func__ , propname , np , index ) ;
2013-10-17 21:21:37 +04:00
return ERR_PTR ( ret ) ;
2008-04-11 17:06:45 +04:00
}
2016-10-25 04:47:44 +03:00
chip = of_find_gpiochip_by_xlate ( & gpiospec ) ;
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
if ( ! chip ) {
desc = ERR_PTR ( - EPROBE_DEFER ) ;
goto out ;
}
2016-06-14 13:07:07 +03:00
desc = of_xlate_and_get_gpiod_flags ( chip , & gpiospec , flags ) ;
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
if ( IS_ERR ( desc ) )
goto out ;
2008-04-11 17:06:45 +04:00
2018-01-17 01:44:46 +03:00
if ( flags )
2018-12-18 00:36:25 +03:00
of_gpio_flags_quirks ( np , propname , flags , index ) ;
2017-12-30 18:26:36 +03:00
2017-07-19 00:43:03 +03:00
pr_debug ( " %s: parsed '%s' property of node '%pOF[%d]' - status (%d) \n " ,
__func__ , propname , np , index ,
gpio: of: remove of_gpiochip_and_xlate() and struct gg_data
The usage of gpiochip_find(&gg_data, of_gpiochip_and_xlate) is odd.
Usually gpiochip_find() is used to find a gpio_chip. Here, however,
the return value from gpiochip_find() is just discarded. Instead,
gpiochip_find(&gg_data, of_gpiochip_and_xlate) is called for the
side-effect of the match function.
The match function, of_gpiochip_find_and_xlate(), fills the given
struct gg_data, but a match function should be simply called to
judge the matching.
This commit fixes this distortion and makes the code more readable.
Remove of_gpiochip_find_and_xlate() and struct gg_data. Instead,
this adds a very simple helper function of_find_gpiochip_by_node().
Now, of_get_named_gpiod_flags() is implemented more straight-forward.
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2016-06-14 13:07:06 +03:00
PTR_ERR_OR_ZERO ( desc ) ) ;
out :
of_node_put ( gpiospec . np ) ;
return desc ;
2008-04-11 17:06:45 +04:00
}
2022-12-19 22:20:15 +03:00
/**
* of_get_named_gpio ( ) - Get a GPIO number to use with GPIO API
* @ np : device node to get GPIO from
* @ propname : Name of property containing gpio specifier ( s )
* @ index : index of the GPIO
*
* Returns GPIO number to use with Linux generic GPIO API , or one of the errno
* value on the error condition .
*/
int of_get_named_gpio ( const struct device_node * np , const char * propname ,
int index )
2014-05-17 09:54:50 +04:00
{
struct gpio_desc * desc ;
2022-12-19 22:20:15 +03:00
desc = of_get_named_gpiod_flags ( np , propname , index , NULL ) ;
2014-05-17 09:54:50 +04:00
if ( IS_ERR ( desc ) )
return PTR_ERR ( desc ) ;
else
return desc_to_gpio ( desc ) ;
}
2022-12-19 22:20:15 +03:00
EXPORT_SYMBOL_GPL ( of_get_named_gpio ) ;
2014-05-17 09:54:50 +04:00
2022-09-08 08:39:49 +03:00
/* Converts gpio_lookup_flags into bitmask of GPIO_* values */
static unsigned long of_convert_gpio_flags ( enum of_gpio_flags flags )
{
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT ;
if ( flags & OF_GPIO_ACTIVE_LOW )
lflags | = GPIO_ACTIVE_LOW ;
if ( flags & OF_GPIO_SINGLE_ENDED ) {
if ( flags & OF_GPIO_OPEN_DRAIN )
lflags | = GPIO_OPEN_DRAIN ;
else
lflags | = GPIO_OPEN_SOURCE ;
}
if ( flags & OF_GPIO_TRANSITORY )
lflags | = GPIO_TRANSITORY ;
if ( flags & OF_GPIO_PULL_UP )
lflags | = GPIO_PULL_UP ;
if ( flags & OF_GPIO_PULL_DOWN )
lflags | = GPIO_PULL_DOWN ;
if ( flags & OF_GPIO_PULL_DISABLE )
lflags | = GPIO_PULL_DISABLE ;
return lflags ;
}
2022-10-18 08:41:03 +03:00
static struct gpio_desc * of_find_gpio_rename ( struct device_node * np ,
2018-12-13 17:22:47 +03:00
const char * con_id ,
unsigned int idx ,
2022-09-08 08:39:47 +03:00
enum of_gpio_flags * of_flags )
2018-12-13 17:22:47 +03:00
{
2022-10-18 08:41:03 +03:00
static const struct of_rename_gpio {
const char * con_id ;
const char * legacy_id ; /* NULL - same as con_id */
/*
* Compatible string can be set to NULL in case where
* matching to a particular compatible is not practical ,
* but it should only be done for gpio names that have
* vendor prefix to reduce risk of false positives .
* Addition of such entries is strongly discouraged .
*/
const char * compatible ;
} gpios [ ] = {
2022-10-18 08:41:05 +03:00
# if !IS_ENABLED(CONFIG_LCD_HX8357)
/* Himax LCD controllers used "gpios-reset" */
{ " reset " , " gpios-reset " , " himax,hx8357 " } ,
{ " reset " , " gpios-reset " , " himax,hx8369 " } ,
# endif
2022-10-18 08:41:03 +03:00
# if IS_ENABLED(CONFIG_MFD_ARIZONA)
{ " wlf,reset " , NULL , NULL } ,
# endif
2022-10-18 08:41:08 +03:00
# if IS_ENABLED(CONFIG_RTC_DRV_MOXART)
{ " rtc-data " , " gpio-rtc-data " , " moxa,moxart-rtc " } ,
{ " rtc-sclk " , " gpio-rtc-sclk " , " moxa,moxart-rtc " } ,
{ " rtc-reset " , " gpio-rtc-reset " , " moxa,moxart-rtc " } ,
# endif
2022-10-18 08:41:06 +03:00
# if IS_ENABLED(CONFIG_NFC_MRVL_I2C)
{ " reset " , " reset-n-io " , " marvell,nfc-i2c " } ,
# endif
# if IS_ENABLED(CONFIG_NFC_MRVL_SPI)
{ " reset " , " reset-n-io " , " marvell,nfc-spi " } ,
# endif
# if IS_ENABLED(CONFIG_NFC_MRVL_UART)
{ " reset " , " reset-n-io " , " marvell,nfc-uart " } ,
{ " reset " , " reset-n-io " , " mrvl,nfc-uart " } ,
# endif
2022-10-18 08:41:05 +03:00
# if !IS_ENABLED(CONFIG_PCI_LANTIQ)
/* MIPS Lantiq PCI */
{ " reset " , " gpios-reset " , " lantiq,pci-xway " } ,
# endif
2022-10-18 08:41:04 +03:00
2022-10-18 08:41:03 +03:00
/*
* Some regulator bindings happened before we managed to
* establish that GPIO properties should be named
* " foo-gpios " so we have this special kludge for them .
*/
2022-10-18 08:41:04 +03:00
# if IS_ENABLED(CONFIG_REGULATOR_ARIZONA_LDO1)
2022-10-18 08:41:03 +03:00
{ " wlf,ldoena " , NULL , NULL } , /* Arizona */
2022-10-18 08:41:04 +03:00
# endif
# if IS_ENABLED(CONFIG_REGULATOR_WM8994)
2022-10-18 08:41:03 +03:00
{ " wlf,ldo1ena " , NULL , NULL } , /* WM8994 */
{ " wlf,ldo2ena " , NULL , NULL } , /* WM8994 */
# endif
2018-12-13 17:22:47 +03:00
2022-10-18 08:41:07 +03:00
# if IS_ENABLED(CONFIG_SND_SOC_CS42L56)
{ " reset " , " cirrus,gpio-nreset " , " cirrus,cs42l56 " } ,
# endif
2022-10-18 08:41:05 +03:00
# if IS_ENABLED(CONFIG_SND_SOC_TLV320AIC3X)
{ " reset " , " gpio-reset " , " ti,tlv320aic3x " } ,
{ " reset " , " gpio-reset " , " ti,tlv320aic33 " } ,
{ " reset " , " gpio-reset " , " ti,tlv320aic3007 " } ,
{ " reset " , " gpio-reset " , " ti,tlv320aic3104 " } ,
{ " reset " , " gpio-reset " , " ti,tlv320aic3106 " } ,
# endif
2022-10-18 08:41:04 +03:00
# if IS_ENABLED(CONFIG_SPI_GPIO)
2022-10-18 08:41:03 +03:00
/*
* The SPI GPIO bindings happened before we managed to
* establish that GPIO properties should be named
* " foo-gpios " so we have this special kludge for them .
*/
{ " miso " , " gpio-miso " , " spi-gpio " } ,
{ " mosi " , " gpio-mosi " , " spi-gpio " } ,
{ " sck " , " gpio-sck " , " spi-gpio " } ,
2022-10-18 08:41:04 +03:00
# endif
2018-12-13 17:22:47 +03:00
2022-10-18 08:41:03 +03:00
/*
* The old Freescale bindings use simply " gpios " as name
* for the chip select lines rather than " cs-gpios " like
* all other SPI hardware . Allow this specifically for
* Freescale and PPC devices .
*/
2022-10-18 08:41:04 +03:00
# if IS_ENABLED(CONFIG_SPI_FSL_SPI)
2022-10-18 08:41:03 +03:00
{ " cs " , " gpios " , " fsl,spi " } ,
{ " cs " , " gpios " , " aeroflexgaisler,spictrl " } ,
2022-10-18 08:41:04 +03:00
# endif
# if IS_ENABLED(CONFIG_SPI_PPC4xx)
2022-10-18 08:41:03 +03:00
{ " cs " , " gpios " , " ibm,ppc4xx-spi " } ,
# endif
2022-10-18 08:41:04 +03:00
2022-10-18 08:41:03 +03:00
# if IS_ENABLED(CONFIG_TYPEC_FUSB302)
/*
* Fairchild FUSB302 host is using undocumented " fcs,int_n "
* property without the compulsory " -gpios " suffix .
*/
{ " fcs,int_n " , NULL , " fcs,fusb302 " } ,
# endif
2017-12-27 18:37:44 +03:00
} ;
2022-10-18 08:41:03 +03:00
struct gpio_desc * desc ;
const char * legacy_id ;
unsigned int i ;
2017-12-27 18:37:44 +03:00
if ( ! con_id )
return ERR_PTR ( - ENOENT ) ;
2022-10-18 08:41:03 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( gpios ) ; i + + ) {
if ( strcmp ( con_id , gpios [ i ] . con_id ) )
continue ;
2017-12-27 18:37:44 +03:00
2022-10-18 08:41:03 +03:00
if ( gpios [ i ] . compatible & &
! of_device_is_compatible ( np , gpios [ i ] . compatible ) )
continue ;
2019-09-11 10:52:05 +03:00
2022-10-18 08:41:03 +03:00
legacy_id = gpios [ i ] . legacy_id ? : gpios [ i ] . con_id ;
desc = of_get_named_gpiod_flags ( np , legacy_id , idx , of_flags ) ;
if ( ! gpiod_not_found ( desc ) ) {
pr_info ( " %s uses legacy gpio name '%s' instead of '%s-gpios' \n " ,
of_node_full_name ( np ) , legacy_id , con_id ) ;
return desc ;
}
}
2020-04-15 22:24:48 +03:00
2022-10-18 08:41:03 +03:00
return ERR_PTR ( - ENOENT ) ;
2020-04-15 22:24:48 +03:00
}
2022-10-18 08:41:02 +03:00
static struct gpio_desc * of_find_mt2701_gpio ( struct device_node * np ,
const char * con_id ,
unsigned int idx ,
enum of_gpio_flags * of_flags )
{
struct gpio_desc * desc ;
const char * legacy_id ;
if ( ! IS_ENABLED ( CONFIG_SND_SOC_MT2701_CS42448 ) )
return ERR_PTR ( - ENOENT ) ;
if ( ! of_device_is_compatible ( np , " mediatek,mt2701-cs42448-machine " ) )
return ERR_PTR ( - ENOENT ) ;
if ( ! con_id | | strcmp ( con_id , " i2s1-in-sel " ) )
return ERR_PTR ( - ENOENT ) ;
if ( idx = = 0 )
legacy_id = " i2s1-in-sel-gpio1 " ;
else if ( idx = = 1 )
legacy_id = " i2s1-in-sel-gpio2 " ;
else
return ERR_PTR ( - ENOENT ) ;
desc = of_get_named_gpiod_flags ( np , legacy_id , 0 , of_flags ) ;
if ( ! gpiod_not_found ( desc ) )
pr_info ( " %s is using legacy gpio name '%s' instead of '%s-gpios' \n " ,
of_node_full_name ( np ) , legacy_id , con_id ) ;
return desc ;
}
2022-09-08 08:39:48 +03:00
typedef struct gpio_desc * ( * of_find_gpio_quirk ) ( struct device_node * np ,
const char * con_id ,
unsigned int idx ,
enum of_gpio_flags * of_flags ) ;
static const of_find_gpio_quirk of_find_gpio_quirks [ ] = {
2022-10-18 08:41:03 +03:00
of_find_gpio_rename ,
2022-10-18 08:41:02 +03:00
of_find_mt2701_gpio ,
2022-09-16 14:01:18 +03:00
NULL
2022-09-08 08:39:48 +03:00
} ;
2022-11-15 13:16:24 +03:00
struct gpio_desc * of_find_gpio ( struct device_node * np , const char * con_id ,
2019-04-10 18:39:16 +03:00
unsigned int idx , unsigned long * flags )
2016-10-03 11:09:40 +03:00
{
char prop_name [ 32 ] ; /* 32 is max size of property name */
enum of_gpio_flags of_flags ;
2022-09-08 08:39:48 +03:00
const of_find_gpio_quirk * q ;
2016-10-03 11:09:40 +03:00
struct gpio_desc * desc ;
unsigned int i ;
2017-12-27 18:37:44 +03:00
/* Try GPIO property "foo-gpios" and "foo-gpio" */
2016-10-03 11:09:40 +03:00
for ( i = 0 ; i < ARRAY_SIZE ( gpio_suffixes ) ; i + + ) {
if ( con_id )
snprintf ( prop_name , sizeof ( prop_name ) , " %s-%s " , con_id ,
gpio_suffixes [ i ] ) ;
else
snprintf ( prop_name , sizeof ( prop_name ) , " %s " ,
gpio_suffixes [ i ] ) ;
2022-11-15 13:16:24 +03:00
desc = of_get_named_gpiod_flags ( np , prop_name , idx , & of_flags ) ;
2018-02-21 11:11:00 +03:00
2020-10-21 17:25:28 +03:00
if ( ! gpiod_not_found ( desc ) )
2016-10-03 11:09:40 +03:00
break ;
}
2022-09-08 08:39:48 +03:00
/* Properly named GPIO was not found, try workarounds */
for ( q = of_find_gpio_quirks ; gpiod_not_found ( desc ) & & * q ; q + + )
2022-11-15 13:16:24 +03:00
desc = ( * q ) ( np , con_id , idx , & of_flags ) ;
2020-04-15 22:24:48 +03:00
2016-10-03 11:09:40 +03:00
if ( IS_ERR ( desc ) )
return desc ;
2022-09-08 08:39:49 +03:00
* flags = of_convert_gpio_flags ( of_flags ) ;
2019-02-07 19:28:58 +03:00
2016-10-03 11:09:40 +03:00
return desc ;
}
2015-02-02 20:44:44 +03:00
/**
2015-08-14 17:10:58 +03:00
* of_parse_own_gpio ( ) - Get a GPIO hog descriptor , names and flags for GPIO API
2015-02-02 20:44:44 +03:00
* @ np : device node to get GPIO from
2016-06-14 13:07:04 +03:00
* @ chip : GPIO chip whose hog is parsed
2016-12-19 21:21:34 +03:00
* @ idx : Index of the GPIO to parse
2015-02-02 20:44:44 +03:00
* @ name : GPIO line name
2019-04-10 18:39:16 +03:00
* @ lflags : bitmask of gpio_lookup_flags GPIO_ * values - returned from
* of_find_gpio ( ) or of_parse_own_gpio ( )
2015-02-02 20:44:44 +03:00
* @ dflags : gpiod_flags - optional GPIO initialization flags
*
* Returns GPIO descriptor to use with Linux GPIO API , or one of the errno
* value on the error condition .
*/
2015-08-14 17:10:58 +03:00
static struct gpio_desc * of_parse_own_gpio ( struct device_node * np ,
2016-06-14 13:07:04 +03:00
struct gpio_chip * chip ,
2016-12-19 21:21:34 +03:00
unsigned int idx , const char * * name ,
2019-04-10 18:39:16 +03:00
unsigned long * lflags ,
2015-08-14 17:10:58 +03:00
enum gpiod_flags * dflags )
2015-02-02 20:44:44 +03:00
{
struct device_node * chip_np ;
enum of_gpio_flags xlate_flags ;
2016-06-14 13:07:04 +03:00
struct of_phandle_args gpiospec ;
struct gpio_desc * desc ;
2016-12-19 21:21:34 +03:00
unsigned int i ;
2015-02-02 20:44:44 +03:00
u32 tmp ;
2016-06-14 13:07:03 +03:00
int ret ;
2015-02-02 20:44:44 +03:00
2022-12-28 12:20:44 +03:00
chip_np = dev_of_node ( & chip - > gpiodev - > dev ) ;
2015-02-02 20:44:44 +03:00
if ( ! chip_np )
return ERR_PTR ( - EINVAL ) ;
xlate_flags = 0 ;
2019-04-10 18:39:17 +03:00
* lflags = GPIO_LOOKUP_FLAGS_DEFAULT ;
2020-10-22 19:58:47 +03:00
* dflags = GPIOD_ASIS ;
2015-02-02 20:44:44 +03:00
ret = of_property_read_u32 ( chip_np , " #gpio-cells " , & tmp ) ;
if ( ret )
return ERR_PTR ( ret ) ;
2016-06-14 13:07:04 +03:00
gpiospec . np = chip_np ;
gpiospec . args_count = tmp ;
2015-02-02 20:44:44 +03:00
2016-12-19 21:21:34 +03:00
for ( i = 0 ; i < tmp ; i + + ) {
ret = of_property_read_u32_index ( np , " gpios " , idx * tmp + i ,
& gpiospec . args [ i ] ) ;
if ( ret )
return ERR_PTR ( ret ) ;
}
2015-02-02 20:44:44 +03:00
2016-06-14 13:07:07 +03:00
desc = of_xlate_and_get_gpiod_flags ( chip , & gpiospec , & xlate_flags ) ;
2016-06-14 13:07:04 +03:00
if ( IS_ERR ( desc ) )
return desc ;
2015-02-02 20:44:44 +03:00
2022-09-08 08:39:49 +03:00
* lflags = of_convert_gpio_flags ( xlate_flags ) ;
2015-02-02 20:44:44 +03:00
if ( of_property_read_bool ( np , " input " ) )
* dflags | = GPIOD_IN ;
else if ( of_property_read_bool ( np , " output-low " ) )
* dflags | = GPIOD_OUT_LOW ;
else if ( of_property_read_bool ( np , " output-high " ) )
* dflags | = GPIOD_OUT_HIGH ;
else {
2018-08-28 04:52:19 +03:00
pr_warn ( " GPIO line %d (%pOFn): no hogging state specified, bailing out \n " ,
desc_to_gpio ( desc ) , np ) ;
2015-02-02 20:44:44 +03:00
return ERR_PTR ( - EINVAL ) ;
}
if ( name & & of_property_read_string ( np , " line-name " , name ) )
* name = np - > name ;
2016-06-14 13:07:04 +03:00
return desc ;
2015-02-02 20:44:44 +03:00
}
2020-02-20 16:01:48 +03:00
/**
* of_gpiochip_add_hog - Add all hogs in a hog device node
* @ chip : gpio chip to act on
* @ hog : device node describing the hogs
*
* Returns error if it fails otherwise 0 on success .
*/
static int of_gpiochip_add_hog ( struct gpio_chip * chip , struct device_node * hog )
{
enum gpiod_flags dflags ;
struct gpio_desc * desc ;
unsigned long lflags ;
const char * name ;
unsigned int i ;
int ret ;
for ( i = 0 ; ; i + + ) {
desc = of_parse_own_gpio ( hog , chip , i , & name , & lflags , & dflags ) ;
if ( IS_ERR ( desc ) )
break ;
ret = gpiod_hog ( desc , name , lflags , dflags ) ;
if ( ret < 0 )
return ret ;
2020-02-20 16:01:49 +03:00
# ifdef CONFIG_OF_DYNAMIC
desc - > hog = hog ;
# endif
2020-02-20 16:01:48 +03:00
}
return 0 ;
}
2015-02-02 20:44:44 +03:00
/**
2015-08-14 17:10:58 +03:00
* of_gpiochip_scan_gpios - Scan gpio - controller for gpio definitions
2015-02-02 20:44:44 +03:00
* @ chip : gpio chip to act on
*
* This is only used by of_gpiochip_add to request / set GPIO initial
* configuration .
2017-06-01 13:30:01 +03:00
* It returns error if it fails otherwise 0 on success .
2015-02-02 20:44:44 +03:00
*/
2016-03-11 16:43:22 +03:00
static int of_gpiochip_scan_gpios ( struct gpio_chip * chip )
2015-02-02 20:44:44 +03:00
{
struct device_node * np ;
2016-03-11 16:43:22 +03:00
int ret ;
2015-02-02 20:44:44 +03:00
2022-12-28 12:20:44 +03:00
for_each_available_child_of_node ( dev_of_node ( & chip - > gpiodev - > dev ) , np ) {
2015-02-02 20:44:44 +03:00
if ( ! of_property_read_bool ( np , " gpio-hog " ) )
continue ;
2020-02-20 16:01:48 +03:00
ret = of_gpiochip_add_hog ( chip , np ) ;
if ( ret < 0 ) {
of_node_put ( np ) ;
return ret ;
2016-10-29 19:13:52 +03:00
}
2020-02-20 16:01:49 +03:00
of_node_set_flag ( np , OF_POPULATED ) ;
2015-02-02 20:44:44 +03:00
}
2016-03-11 16:43:22 +03:00
return 0 ;
2015-02-02 20:44:44 +03:00
}
2020-02-20 16:01:49 +03:00
# ifdef CONFIG_OF_DYNAMIC
/**
* of_gpiochip_remove_hog - Remove all hogs in a hog device node
* @ chip : gpio chip to act on
* @ hog : device node describing the hogs
*/
static void of_gpiochip_remove_hog ( struct gpio_chip * chip ,
struct device_node * hog )
{
2022-02-01 18:27:56 +03:00
struct gpio_desc * desc ;
2020-02-20 16:01:49 +03:00
2022-04-08 21:18:50 +03:00
for_each_gpio_desc_with_flag ( chip , desc , FLAG_IS_HOGGED )
2022-02-01 18:27:56 +03:00
if ( desc - > hog = = hog )
gpiochip_free_own_desc ( desc ) ;
2020-02-20 16:01:49 +03:00
}
static int of_gpiochip_match_node ( struct gpio_chip * chip , void * data )
{
2022-06-29 14:30:58 +03:00
return device_match_of_node ( & chip - > gpiodev - > dev , data ) ;
2020-02-20 16:01:49 +03:00
}
static struct gpio_chip * of_find_gpiochip_by_node ( struct device_node * np )
{
return gpiochip_find ( np , of_gpiochip_match_node ) ;
}
static int of_gpio_notify ( struct notifier_block * nb , unsigned long action ,
void * arg )
{
struct of_reconfig_data * rd = arg ;
struct gpio_chip * chip ;
int ret ;
/*
* This only supports adding and removing complete gpio - hog nodes .
* Modifying an existing gpio - hog node is not supported ( except for
* changing its " status " property , which is treated the same as
* addition / removal ) .
*/
switch ( of_reconfig_get_state_change ( action , arg ) ) {
case OF_RECONFIG_CHANGE_ADD :
if ( ! of_property_read_bool ( rd - > dn , " gpio-hog " ) )
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ; /* not for us */
2020-02-20 16:01:49 +03:00
if ( of_node_test_and_set_flag ( rd - > dn , OF_POPULATED ) )
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ;
2020-02-20 16:01:49 +03:00
chip = of_find_gpiochip_by_node ( rd - > dn - > parent ) ;
if ( chip = = NULL )
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ; /* not for us */
2020-02-20 16:01:49 +03:00
ret = of_gpiochip_add_hog ( chip , rd - > dn ) ;
if ( ret < 0 ) {
pr_err ( " %s: failed to add hogs for %pOF \n " , __func__ ,
rd - > dn ) ;
of_node_clear_flag ( rd - > dn , OF_POPULATED ) ;
return notifier_from_errno ( ret ) ;
}
2023-09-05 21:53:04 +03:00
return NOTIFY_OK ;
2020-02-20 16:01:49 +03:00
case OF_RECONFIG_CHANGE_REMOVE :
if ( ! of_node_check_flag ( rd - > dn , OF_POPULATED ) )
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ; /* already depopulated */
2020-02-20 16:01:49 +03:00
chip = of_find_gpiochip_by_node ( rd - > dn - > parent ) ;
if ( chip = = NULL )
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ; /* not for us */
2020-02-20 16:01:49 +03:00
of_gpiochip_remove_hog ( chip , rd - > dn ) ;
of_node_clear_flag ( rd - > dn , OF_POPULATED ) ;
2023-09-05 21:53:04 +03:00
return NOTIFY_OK ;
2020-02-20 16:01:49 +03:00
}
2023-09-05 21:53:04 +03:00
return NOTIFY_DONE ;
2020-02-20 16:01:49 +03:00
}
struct notifier_block gpio_of_notifier = {
. notifier_call = of_gpio_notify ,
} ;
# endif /* CONFIG_OF_DYNAMIC */
2008-04-11 17:06:45 +04:00
/**
2017-07-24 17:57:23 +03:00
* of_gpio_simple_xlate - translate gpiospec to the GPIO number and flags
2010-06-08 17:48:16 +04:00
* @ gc : pointer to the gpio_chip structure
2017-07-24 17:57:23 +03:00
* @ gpiospec : GPIO specifier as found in the device tree
2008-12-01 09:30:04 +03:00
* @ flags : a flags pointer to fill in
2008-04-11 17:06:45 +04:00
*
* This is simple translation function , suitable for the most 1 : 1 mapped
2017-07-24 17:57:23 +03:00
* GPIO chips . This function performs only one sanity check : whether GPIO
2008-04-11 17:06:45 +04:00
* is less than ngpios ( that is specified in the gpio_chip ) .
*/
2019-09-06 11:45:37 +03:00
static int of_gpio_simple_xlate ( struct gpio_chip * gc ,
const struct of_phandle_args * gpiospec ,
u32 * flags )
2008-04-11 17:06:45 +04:00
{
2008-12-01 09:30:04 +03:00
/*
* We ' re discouraging gpio_cells < 2 , since that way you ' ll have to
2015-05-18 21:41:43 +03:00
* write your own xlate function ( that will have to retrieve the GPIO
2008-12-01 09:30:04 +03:00
* number and the flags from a single gpio cell - - this is possible ,
* but not recommended ) .
*/
2010-06-08 17:48:16 +04:00
if ( gc - > of_gpio_n_cells < 2 ) {
2008-12-01 09:30:04 +03:00
WARN_ON ( 1 ) ;
return - EINVAL ;
}
2011-12-12 20:25:57 +04:00
if ( WARN_ON ( gpiospec - > args_count < gc - > of_gpio_n_cells ) )
return - EINVAL ;
2012-04-04 04:02:58 +04:00
if ( gpiospec - > args [ 0 ] > = gc - > ngpio )
2008-04-11 17:06:45 +04:00
return - EINVAL ;
2008-12-01 09:30:04 +03:00
if ( flags )
2011-12-12 20:25:57 +04:00
* flags = gpiospec - > args [ 1 ] ;
2008-12-01 09:30:04 +03:00
2011-12-12 20:25:57 +04:00
return gpiospec - > args [ 0 ] ;
2008-04-11 17:06:45 +04:00
}
2023-02-07 17:29:47 +03:00
# if IS_ENABLED(CONFIG_OF_GPIO_MM_GPIOCHIP)
# include <linux/gpio/legacy-of-mm-gpiochip.h>
2008-04-11 17:06:45 +04:00
/**
2015-12-04 17:13:53 +03:00
* of_mm_gpiochip_add_data - Add memory mapped GPIO chip ( bank )
2008-04-11 17:06:45 +04:00
* @ np : device node of the GPIO chip
* @ mm_gc : pointer to the of_mm_gpio_chip allocated structure
2015-12-04 17:13:53 +03:00
* @ data : driver data to store in the struct gpio_chip
2008-04-11 17:06:45 +04:00
*
* To use this function you should allocate and fill mm_gc with :
*
* 1 ) In the gpio_chip structure :
* - all the callbacks
2010-06-08 17:48:16 +04:00
* - of_gpio_n_cells
* - of_xlate callback ( optional )
2008-04-11 17:06:45 +04:00
*
* 3 ) In the of_mm_gpio_chip structure :
* - save_regs callback ( optional )
*
* If succeeded , this function will map bank ' s memory and will
* do all necessary work for you . Then you ' ll able to use . regs
* to manage GPIOs from the callbacks .
*/
2015-12-04 17:13:53 +03:00
int of_mm_gpiochip_add_data ( struct device_node * np ,
struct of_mm_gpio_chip * mm_gc ,
void * data )
2008-04-11 17:06:45 +04:00
{
int ret = - ENOMEM ;
2010-06-08 17:48:16 +04:00
struct gpio_chip * gc = & mm_gc - > gc ;
2008-04-11 17:06:45 +04:00
2017-07-19 00:43:03 +03:00
gc - > label = kasprintf ( GFP_KERNEL , " %pOF " , np ) ;
2008-04-11 17:06:45 +04:00
if ( ! gc - > label )
goto err0 ;
mm_gc - > regs = of_iomap ( np , 0 ) ;
if ( ! mm_gc - > regs )
goto err1 ;
2008-04-29 18:05:24 +04:00
gc - > base = - 1 ;
2008-04-11 17:06:45 +04:00
if ( mm_gc - > save_regs )
mm_gc - > save_regs ( mm_gc ) ;
2022-11-14 21:46:25 +03:00
fwnode_handle_put ( mm_gc - > gc . fwnode ) ;
mm_gc - > gc . fwnode = fwnode_handle_get ( of_fwnode_handle ( np ) ) ;
2008-04-11 17:06:45 +04:00
2015-12-04 17:13:53 +03:00
ret = gpiochip_add_data ( gc , data ) ;
2008-04-11 17:06:45 +04:00
if ( ret )
goto err2 ;
return 0 ;
err2 :
2022-07-11 15:52:38 +03:00
of_node_put ( np ) ;
2008-04-11 17:06:45 +04:00
iounmap ( mm_gc - > regs ) ;
err1 :
kfree ( gc - > label ) ;
err0 :
2017-07-19 00:43:03 +03:00
pr_err ( " %pOF: GPIO chip registration failed with status %d \n " , np , ret ) ;
2008-04-11 17:06:45 +04:00
return ret ;
}
2019-09-06 11:45:38 +03:00
EXPORT_SYMBOL_GPL ( of_mm_gpiochip_add_data ) ;
2010-06-08 17:48:16 +04:00
2014-12-17 18:51:13 +03:00
/**
* of_mm_gpiochip_remove - Remove memory mapped GPIO chip ( bank )
* @ mm_gc : pointer to the of_mm_gpio_chip allocated structure
*/
void of_mm_gpiochip_remove ( struct of_mm_gpio_chip * mm_gc )
{
struct gpio_chip * gc = & mm_gc - > gc ;
gpiochip_remove ( gc ) ;
iounmap ( mm_gc - > regs ) ;
kfree ( gc - > label ) ;
}
2019-09-06 11:45:38 +03:00
EXPORT_SYMBOL_GPL ( of_mm_gpiochip_remove ) ;
2023-02-07 17:29:47 +03:00
# endif
2014-12-17 18:51:13 +03:00
2012-10-27 13:51:36 +04:00
# ifdef CONFIG_PINCTRL
2015-07-14 11:29:54 +03:00
static int of_gpiochip_add_pin_range ( struct gpio_chip * chip )
2012-10-27 13:51:36 +04:00
{
struct of_phandle_args pinspec ;
2012-11-06 19:03:35 +04:00
struct pinctrl_dev * pctldev ;
2022-12-28 12:20:44 +03:00
struct device_node * np ;
2012-10-27 13:51:36 +04:00
int index = 0 , ret ;
2013-10-15 17:37:54 +04:00
const char * name ;
static const char group_names_propname [ ] = " gpio-ranges-group-names " ;
struct property * group_names ;
2012-10-27 13:51:36 +04:00
2022-12-28 12:20:44 +03:00
np = dev_of_node ( & chip - > gpiodev - > dev ) ;
2012-10-27 13:51:36 +04:00
if ( ! np )
2015-07-14 11:29:54 +03:00
return 0 ;
2012-10-27 13:51:36 +04:00
2013-10-15 17:37:54 +04:00
group_names = of_find_property ( np , group_names_propname , NULL ) ;
2013-02-17 15:42:48 +04:00
for ( ; ; index + + ) {
2013-08-15 01:27:12 +04:00
ret = of_parse_phandle_with_fixed_args ( np , " gpio-ranges " , 3 ,
index , & pinspec ) ;
2012-10-27 13:51:36 +04:00
if ( ret )
break ;
2012-11-06 19:03:35 +04:00
pctldev = of_pinctrl_get ( pinspec . np ) ;
2016-05-23 04:52:09 +03:00
of_node_put ( pinspec . np ) ;
2012-11-06 19:03:35 +04:00
if ( ! pctldev )
2015-07-14 11:29:54 +03:00
return - EPROBE_DEFER ;
2012-10-27 13:51:36 +04:00
2013-10-15 17:37:54 +04:00
if ( pinspec . args [ 2 ] ) {
if ( group_names ) {
2015-07-07 23:22:15 +03:00
of_property_read_string_index ( np ,
2013-10-15 17:37:54 +04:00
group_names_propname ,
index , & name ) ;
if ( strlen ( name ) ) {
2017-07-19 00:43:03 +03:00
pr_err ( " %pOF: Group name of numeric GPIO ranges must be the empty string. \n " ,
np ) ;
2013-10-15 17:37:54 +04:00
break ;
}
}
/* npins != 0: linear range */
ret = gpiochip_add_pin_range ( chip ,
pinctrl_dev_get_devname ( pctldev ) ,
pinspec . args [ 0 ] ,
pinspec . args [ 1 ] ,
pinspec . args [ 2 ] ) ;
if ( ret )
2015-07-14 11:29:54 +03:00
return ret ;
2013-10-15 17:37:54 +04:00
} else {
/* npins == 0: special range */
if ( pinspec . args [ 1 ] ) {
2017-07-19 00:43:03 +03:00
pr_err ( " %pOF: Illegal gpio-range format. \n " ,
np ) ;
2013-10-15 17:37:54 +04:00
break ;
}
if ( ! group_names ) {
2017-07-19 00:43:03 +03:00
pr_err ( " %pOF: GPIO group range requested but no %s property. \n " ,
np , group_names_propname ) ;
2013-10-15 17:37:54 +04:00
break ;
}
ret = of_property_read_string_index ( np ,
group_names_propname ,
index , & name ) ;
if ( ret )
break ;
if ( ! strlen ( name ) ) {
2017-07-19 00:43:03 +03:00
pr_err ( " %pOF: Group name of GPIO group range cannot be the empty string. \n " ,
np ) ;
2013-10-15 17:37:54 +04:00
break ;
}
ret = gpiochip_add_pingroup_range ( chip , pctldev ,
pinspec . args [ 0 ] , name ) ;
if ( ret )
2015-07-14 11:29:54 +03:00
return ret ;
2013-10-15 17:37:54 +04:00
}
2013-02-17 15:42:48 +04:00
}
2015-07-14 11:29:54 +03:00
return 0 ;
2012-10-27 13:51:36 +04:00
}
# else
2015-07-14 11:29:54 +03:00
static int of_gpiochip_add_pin_range ( struct gpio_chip * chip ) { return 0 ; }
2012-10-27 13:51:36 +04:00
# endif
2015-07-14 11:29:54 +03:00
int of_gpiochip_add ( struct gpio_chip * chip )
2010-06-08 17:48:17 +04:00
{
2022-11-08 16:38:52 +03:00
struct device_node * np ;
2019-07-16 14:58:54 +03:00
int ret ;
2015-07-14 11:29:54 +03:00
2022-12-28 12:20:44 +03:00
np = dev_of_node ( & chip - > gpiodev - > dev ) ;
2022-11-08 16:38:52 +03:00
if ( ! np )
2015-07-14 11:29:54 +03:00
return 0 ;
2010-06-08 17:48:17 +04:00
if ( ! chip - > of_xlate ) {
chip - > of_gpio_n_cells = 2 ;
chip - > of_xlate = of_gpio_simple_xlate ;
}
2016-06-14 13:07:05 +03:00
if ( chip - > of_gpio_n_cells > MAX_PHANDLE_ARGS )
return - EINVAL ;
2019-07-16 14:58:54 +03:00
ret = of_gpiochip_add_pin_range ( chip ) ;
if ( ret )
return ret ;
2015-07-14 11:29:54 +03:00
2023-07-03 17:23:06 +03:00
of_node_get ( np ) ;
2015-02-02 20:44:44 +03:00
2019-07-16 14:58:54 +03:00
ret = of_gpiochip_scan_gpios ( chip ) ;
2019-11-05 21:06:54 +03:00
if ( ret )
2023-07-03 17:23:06 +03:00
of_node_put ( np ) ;
2019-03-28 16:13:47 +03:00
2019-07-16 14:58:54 +03:00
return ret ;
2010-06-08 17:48:17 +04:00
}
void of_gpiochip_remove ( struct gpio_chip * chip )
{
2023-07-03 17:23:06 +03:00
of_node_put ( dev_of_node ( & chip - > gpiodev - > dev ) ) ;
2010-06-08 17:48:17 +04:00
}