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>
2010-07-06 02:11:55 +04:00
# include <linux/module.h>
2008-04-11 17:06:45 +04:00
# include <linux/io.h>
2013-10-17 21:21:37 +04:00
# include <linux/gpio/consumer.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>
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"
2019-11-28 11:37:17 +03:00
/**
* of_gpio_spi_cs_get_count ( ) - special GPIO counting for SPI
* Some elder GPIO controllers need special quirks . Currently we handle
* the Freescale GPIO controller with bindings that doesn ' t use the
* 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 " ) & &
! of_device_is_compatible ( np , " aeroflexgaisler,spictrl " ) )
return 0 ;
return of_gpio_named_count ( np , " gpios " ) ;
}
2019-07-17 10:10:01 +03:00
/*
* This is used by external users of of_gpio_count ( ) from < linux / of_gpio . h >
*
* FIXME : get rid of those external users by converting them to GPIO
2019-11-20 18:45:21 +03:00
* descriptors and let them all use gpiod_count ( )
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 ;
return chip - > gpiodev - > dev . of_node = = 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
}
2019-07-17 10:10:01 +03:00
/**
* of_gpio_need_valid_mask ( ) - figure out if the OF GPIO driver needs
* to set the . valid_mask
2019-10-08 23:40:21 +03:00
* @ gc : the target gpio_chip
*
* Return : true if the valid mask needs to be set
2019-07-17 10:10:01 +03:00
*/
2019-08-01 01:28:26 +03:00
bool of_gpio_need_valid_mask ( const struct gpio_chip * gc )
2019-07-17 10:10:01 +03:00
{
int size ;
struct device_node * np = gc - > of_node ;
size = of_property_count_u32_elems ( np , " gpio-reserved-ranges " ) ;
if ( size > 0 & & size % 2 = = 0 )
return true ;
return false ;
}
2017-12-30 18:26:36 +03:00
static void of_gpio_flags_quirks ( struct device_node * np ,
2018-12-18 00:36:25 +03:00
const char * propname ,
2018-09-04 12:01:58 +03:00
enum of_gpio_flags * flags ,
int index )
2017-12-30 18:26:36 +03:00
{
/*
* Some GPIO fixed regulator quirks .
* Note that active low is the default .
*/
if ( IS_ENABLED ( CONFIG_REGULATOR ) & &
2018-06-11 16:11:41 +03:00
( of_device_is_compatible ( np , " regulator-fixed " ) | |
of_device_is_compatible ( np , " reg-fixed-voltage " ) | |
2019-03-29 11:42:29 +03:00
( ! ( strcmp ( propname , " enable-gpio " ) & &
strcmp ( propname , " enable-gpios " ) ) & &
of_device_is_compatible ( np , " regulator-gpio " ) ) ) ) {
2019-10-18 13:05:38 +03:00
bool active_low = ! of_property_read_bool ( np ,
" enable-active-high " ) ;
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 .
*/
2019-10-18 13:05:38 +03:00
if ( ( * flags & OF_GPIO_ACTIVE_LOW ) & & ! active_low ) {
2017-12-30 18:26:36 +03:00
pr_warn ( " %s GPIO handle specifies active low - ignored \n " ,
of_node_full_name ( np ) ) ;
* flags & = ~ OF_GPIO_ACTIVE_LOW ;
}
2019-10-18 13:05:38 +03:00
if ( active_low )
2017-12-30 18:26:36 +03:00
* flags | = OF_GPIO_ACTIVE_LOW ;
}
/*
* 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 .
*/
2019-03-26 09:32:09 +03:00
if ( of_property_read_bool ( child , " spi-cs-high " ) ) {
2018-09-04 12:01:58 +03:00
if ( * flags & OF_GPIO_ACTIVE_LOW ) {
pr_warn ( " %s GPIO handle specifies active low - ignored \n " ,
2019-03-26 09:32:09 +03:00
of_node_full_name ( child ) ) ;
2018-09-04 12:01:58 +03:00
* flags & = ~ OF_GPIO_ACTIVE_LOW ;
}
} else {
if ( ! ( * flags & OF_GPIO_ACTIVE_LOW ) )
pr_info ( " %s enforce active low on chipselect handle \n " ,
2019-03-26 09:32:09 +03:00
of_node_full_name ( child ) ) ;
2018-09-04 12:01:58 +03:00
* flags | = OF_GPIO_ACTIVE_LOW ;
}
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
*/
2019-09-06 11:45:36 +03:00
static struct gpio_desc * of_get_named_gpiod_flags ( 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
}
2014-05-17 09:54:50 +04:00
int of_get_named_gpio_flags ( struct device_node * np , const char * list_name ,
int index , enum of_gpio_flags * flags )
{
struct gpio_desc * desc ;
desc = of_get_named_gpiod_flags ( np , list_name , index , flags ) ;
if ( IS_ERR ( desc ) )
return PTR_ERR ( desc ) ;
else
return desc_to_gpio ( desc ) ;
}
2019-09-06 11:45:38 +03:00
EXPORT_SYMBOL_GPL ( of_get_named_gpio_flags ) ;
2014-05-17 09:54:50 +04:00
2019-07-17 10:10:01 +03:00
/**
* gpiod_get_from_of_node ( ) - obtain a GPIO from an OF node
* @ node : handle of the OF node
* @ propname : name of the DT property representing the GPIO
* @ index : index of the GPIO to obtain for the consumer
* @ dflags : GPIO initialization flags
* @ label : label to attach to the requested GPIO
*
* Returns :
* On successful request the GPIO pin is configured in accordance with
* provided @ dflags .
*
* In case of error an ERR_PTR ( ) is returned .
*/
struct gpio_desc * gpiod_get_from_of_node ( struct device_node * node ,
const char * propname , int index ,
enum gpiod_flags dflags ,
const char * label )
{
unsigned long lflags = GPIO_LOOKUP_FLAGS_DEFAULT ;
struct gpio_desc * desc ;
enum of_gpio_flags flags ;
bool active_low = false ;
bool single_ended = false ;
bool open_drain = false ;
bool transitory = false ;
int ret ;
desc = of_get_named_gpiod_flags ( node , propname ,
index , & flags ) ;
if ( ! desc | | IS_ERR ( desc ) ) {
return desc ;
}
active_low = flags & OF_GPIO_ACTIVE_LOW ;
single_ended = flags & OF_GPIO_SINGLE_ENDED ;
open_drain = flags & OF_GPIO_OPEN_DRAIN ;
transitory = flags & OF_GPIO_TRANSITORY ;
ret = gpiod_request ( desc , label ) ;
2019-10-01 12:49:21 +03:00
if ( ret = = - EBUSY & & ( dflags & GPIOD_FLAGS_BIT_NONEXCLUSIVE ) )
2019-07-17 10:10:01 +03:00
return desc ;
if ( ret )
return ERR_PTR ( ret ) ;
if ( active_low )
lflags | = GPIO_ACTIVE_LOW ;
if ( single_ended ) {
if ( open_drain )
lflags | = GPIO_OPEN_DRAIN ;
else
lflags | = GPIO_OPEN_SOURCE ;
}
if ( transitory )
lflags | = GPIO_TRANSITORY ;
ret = gpiod_configure_flags ( desc , propname , lflags , dflags ) ;
if ( ret < 0 ) {
gpiod_put ( desc ) ;
return ERR_PTR ( ret ) ;
}
return desc ;
}
2019-09-06 11:45:38 +03:00
EXPORT_SYMBOL_GPL ( gpiod_get_from_of_node ) ;
2014-05-17 09:54:50 +04:00
2017-12-27 18:37:44 +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 .
*/
static struct gpio_desc * of_find_spi_gpio ( struct device * dev , const char * con_id ,
enum of_gpio_flags * of_flags )
{
char prop_name [ 32 ] ; /* 32 is max size of property name */
struct device_node * np = dev - > of_node ;
struct gpio_desc * desc ;
/*
* Hopefully the compiler stubs the rest of the function if this
* is false .
*/
if ( ! IS_ENABLED ( CONFIG_SPI_MASTER ) )
return ERR_PTR ( - ENOENT ) ;
/* Allow this specifically for "spi-gpio" devices */
if ( ! of_device_is_compatible ( np , " spi-gpio " ) | | ! con_id )
return ERR_PTR ( - ENOENT ) ;
/* Will be "gpio-sck", "gpio-mosi" or "gpio-miso" */
snprintf ( prop_name , sizeof ( prop_name ) , " %s-%s " , " gpio " , con_id ) ;
desc = of_get_named_gpiod_flags ( np , prop_name , 0 , of_flags ) ;
return desc ;
}
2018-12-13 17:22:47 +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 . Account for this
* with a special quirk .
*/
static struct gpio_desc * of_find_spi_cs_gpio ( struct device * dev ,
const char * con_id ,
unsigned int idx ,
unsigned long * flags )
{
struct device_node * np = dev - > of_node ;
if ( ! IS_ENABLED ( CONFIG_SPI_MASTER ) )
return ERR_PTR ( - ENOENT ) ;
/* Allow this specifically for Freescale devices */
if ( ! of_device_is_compatible ( np , " fsl,spi " ) & &
! of_device_is_compatible ( np , " aeroflexgaisler,spictrl " ) )
return ERR_PTR ( - ENOENT ) ;
/* Allow only if asking for "cs-gpios" */
if ( ! con_id | | strcmp ( con_id , " cs " ) )
return ERR_PTR ( - ENOENT ) ;
/*
* While all other SPI controllers use " cs-gpios " the Freescale
* uses just " gpios " so translate to that when " cs-gpios " is
* requested .
*/
return of_find_gpio ( dev , NULL , idx , flags ) ;
}
2017-12-27 18:37:44 +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 .
*/
static struct gpio_desc * of_find_regulator_gpio ( struct device * dev , const char * con_id ,
enum of_gpio_flags * of_flags )
{
/* These are the connection IDs we accept as legacy GPIO phandles */
const char * whitelist [ ] = {
" wlf,ldoena " , /* Arizona */
" wlf,ldo1ena " , /* WM8994 */
" wlf,ldo2ena " , /* WM8994 */
} ;
struct device_node * np = dev - > of_node ;
struct gpio_desc * desc ;
int i ;
if ( ! IS_ENABLED ( CONFIG_REGULATOR ) )
return ERR_PTR ( - ENOENT ) ;
if ( ! con_id )
return ERR_PTR ( - ENOENT ) ;
2018-05-03 20:14:46 +03:00
i = match_string ( whitelist , ARRAY_SIZE ( whitelist ) , con_id ) ;
if ( i < 0 )
2017-12-27 18:37:44 +03:00
return ERR_PTR ( - ENOENT ) ;
desc = of_get_named_gpiod_flags ( np , con_id , 0 , of_flags ) ;
return desc ;
}
2019-09-11 10:52:05 +03:00
static struct gpio_desc * of_find_arizona_gpio ( struct device * dev ,
const char * con_id ,
enum of_gpio_flags * of_flags )
{
if ( ! IS_ENABLED ( CONFIG_MFD_ARIZONA ) )
return ERR_PTR ( - ENOENT ) ;
if ( ! con_id | | strcmp ( con_id , " wlf,reset " ) )
return ERR_PTR ( - ENOENT ) ;
return of_get_named_gpiod_flags ( dev - > of_node , con_id , 0 , of_flags ) ;
}
2016-10-03 11:09:40 +03:00
struct gpio_desc * of_find_gpio ( struct device * dev , 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 ;
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 ] ) ;
desc = of_get_named_gpiod_flags ( dev - > of_node , prop_name , idx ,
& of_flags ) ;
2018-02-21 11:11:00 +03:00
2019-09-04 02:18:56 +03:00
if ( ! IS_ERR ( desc ) | | PTR_ERR ( desc ) ! = - ENOENT )
2016-10-03 11:09:40 +03:00
break ;
}
2019-09-04 02:18:56 +03:00
if ( IS_ERR ( desc ) & & PTR_ERR ( desc ) = = - ENOENT ) {
/* Special handling for SPI GPIOs if used */
2017-12-27 18:37:44 +03:00
desc = of_find_spi_gpio ( dev , con_id , & of_flags ) ;
2019-09-04 02:18:56 +03:00
}
if ( IS_ERR ( desc ) & & PTR_ERR ( desc ) = = - ENOENT ) {
2018-12-13 17:22:47 +03:00
/* This quirk looks up flags and all */
desc = of_find_spi_cs_gpio ( dev , con_id , idx , flags ) ;
if ( ! IS_ERR ( desc ) )
return desc ;
}
2017-12-27 18:37:44 +03:00
2019-09-04 02:18:56 +03:00
if ( IS_ERR ( desc ) & & PTR_ERR ( desc ) = = - ENOENT ) {
/* Special handling for regulator GPIOs if used */
2017-12-27 18:37:44 +03:00
desc = of_find_regulator_gpio ( dev , con_id , & of_flags ) ;
2019-09-04 02:18:56 +03:00
}
2017-12-27 18:37:44 +03:00
2019-09-11 10:52:05 +03:00
if ( IS_ERR ( desc ) & & PTR_ERR ( desc ) = = - ENOENT )
desc = of_find_arizona_gpio ( dev , con_id , & of_flags ) ;
2016-10-03 11:09:40 +03:00
if ( IS_ERR ( desc ) )
return desc ;
if ( of_flags & OF_GPIO_ACTIVE_LOW )
* flags | = GPIO_ACTIVE_LOW ;
if ( of_flags & OF_GPIO_SINGLE_ENDED ) {
2017-04-06 16:35:52 +03:00
if ( of_flags & OF_GPIO_OPEN_DRAIN )
2016-10-03 11:09:40 +03:00
* flags | = GPIO_OPEN_DRAIN ;
else
* flags | = GPIO_OPEN_SOURCE ;
}
2017-11-30 06:55:24 +03:00
if ( of_flags & OF_GPIO_TRANSITORY )
* flags | = GPIO_TRANSITORY ;
2017-05-23 17:47:29 +03:00
2019-02-07 19:28:58 +03:00
if ( of_flags & OF_GPIO_PULL_UP )
* flags | = GPIO_PULL_UP ;
if ( of_flags & OF_GPIO_PULL_DOWN )
* flags | = GPIO_PULL_DOWN ;
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
2016-06-14 13:07:04 +03:00
chip_np = chip - > of_node ;
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 ;
2015-02-02 20:44:44 +03:00
* dflags = 0 ;
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
if ( xlate_flags & OF_GPIO_ACTIVE_LOW )
* lflags | = GPIO_ACTIVE_LOW ;
2017-11-30 06:55:24 +03:00
if ( xlate_flags & OF_GPIO_TRANSITORY )
* lflags | = GPIO_TRANSITORY ;
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
}
/**
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 gpio_desc * desc = NULL ;
struct device_node * np ;
const char * name ;
2019-04-10 18:39:16 +03:00
unsigned long lflags ;
2015-02-02 20:44:44 +03:00
enum gpiod_flags dflags ;
2016-12-19 21:21:34 +03:00
unsigned int i ;
2016-03-11 16:43:22 +03:00
int ret ;
2015-02-02 20:44:44 +03:00
2016-03-11 16:43:20 +03:00
for_each_available_child_of_node ( chip - > of_node , np ) {
2015-02-02 20:44:44 +03:00
if ( ! of_property_read_bool ( np , " gpio-hog " ) )
continue ;
2016-12-19 21:21:34 +03:00
for ( i = 0 ; ; i + + ) {
desc = of_parse_own_gpio ( np , chip , i , & name , & lflags ,
& dflags ) ;
if ( IS_ERR ( desc ) )
break ;
ret = gpiod_hog ( desc , name , lflags , dflags ) ;
if ( ret < 0 ) {
of_node_put ( np ) ;
return ret ;
}
2016-10-29 19:13:52 +03:00
}
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
}
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
}
/**
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 ) ;
2010-06-08 17:48:16 +04:00
mm_gc - > gc . of_node = 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 :
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 ;
if ( ! mm_gc )
return ;
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 ) ;
2014-12-17 18:51:13 +03:00
2018-03-23 19:34:52 +03:00
static void of_gpiochip_init_valid_mask ( struct gpio_chip * chip )
{
int len , i ;
u32 start , count ;
struct device_node * np = chip - > of_node ;
len = of_property_count_u32_elems ( np , " gpio-reserved-ranges " ) ;
if ( len < 0 | | len % 2 ! = 0 )
return ;
for ( i = 0 ; i < len ; i + = 2 ) {
of_property_read_u32_index ( np , " gpio-reserved-ranges " ,
i , & start ) ;
of_property_read_u32_index ( np , " gpio-reserved-ranges " ,
i + 1 , & count ) ;
if ( start > = chip - > ngpio | | start + count > = chip - > ngpio )
continue ;
bitmap_clear ( chip - > valid_mask , start , count ) ;
}
} ;
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 device_node * np = chip - > of_node ;
struct of_phandle_args pinspec ;
2012-11-06 19:03:35 +04:00
struct pinctrl_dev * pctldev ;
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
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
{
2019-07-16 14:58:54 +03:00
int ret ;
2015-07-14 11:29:54 +03:00
2010-06-08 17:48:17 +04:00
if ( ! chip - > of_node )
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 ;
2018-03-23 19:34:52 +03:00
of_gpiochip_init_valid_mask ( chip ) ;
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
2016-04-19 16:26:26 +03:00
/* If the chip defines names itself, these take precedence */
if ( ! chip - > names )
2017-12-15 17:02:33 +03:00
devprop_gpiochip_set_names ( chip ,
of_fwnode_handle ( chip - > of_node ) ) ;
2016-04-19 16:26:26 +03:00
2010-06-08 17:48:17 +04:00
of_node_get ( chip - > of_node ) ;
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 )
2019-03-28 16:13:47 +03:00
of_node_put ( chip - > of_node ) ;
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 )
{
2014-08-08 14:07:51 +04:00
of_node_put ( chip - > of_node ) ;
2010-06-08 17:48:17 +04:00
}