2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2014-02-24 23:54:58 +04:00
/*
* GPIO controller in LSI ZEVIO SoCs .
*
* Author : Fabian Vogt < fabian @ ritter - vogt . de >
*/
2023-01-12 19:39:41 +03:00
# include <linux/bitops.h>
2014-02-24 23:54:58 +04:00
# include <linux/errno.h>
2016-05-10 02:59:58 +03:00
# include <linux/init.h>
2014-02-24 23:54:58 +04:00
# include <linux/io.h>
2023-01-12 19:39:41 +03:00
# include <linux/mod_devicetable.h>
2023-01-21 14:18:35 +03:00
# include <linux/platform_device.h>
2014-02-24 23:54:58 +04:00
# include <linux/slab.h>
2023-01-12 19:39:41 +03:00
# include <linux/spinlock.h>
2018-09-03 01:18:51 +03:00
# include <linux/gpio/driver.h>
2014-02-24 23:54:58 +04:00
/*
* Memory layout :
* This chip has four gpio sections , each controls 8 GPIOs .
* Bit 0 in section 0 is GPIO 0 , bit 2 in section 1 is GPIO 10.
* Disclaimer : Reverse engineered !
* For more information refer to :
* http : //hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
*
* 0x00 - 0x3F : Section 0
* + 0x00 : Masked interrupt status ( read - only )
* + 0x04 : R : Interrupt status W : Reset interrupt status
* + 0x08 : R : Interrupt mask W : Mask interrupt
* + 0x0C : W : Unmask interrupt ( write - only )
* + 0x10 : Direction : I / O = 1 / 0
* + 0x14 : Output
* + 0x18 : Input ( read - only )
* + 0x20 : R : Level interrupt W : Set as level interrupt
* 0x40 - 0x7F : Section 1
* 0x80 - 0xBF : Section 2
* 0xC0 - 0xFF : Section 3
*/
# define ZEVIO_GPIO_SECTION_SIZE 0x40
/* Offsets to various registers */
# define ZEVIO_GPIO_INT_MASKED_STATUS 0x00
# define ZEVIO_GPIO_INT_STATUS 0x04
# define ZEVIO_GPIO_INT_UNMASK 0x08
# define ZEVIO_GPIO_INT_MASK 0x0C
# define ZEVIO_GPIO_DIRECTION 0x10
# define ZEVIO_GPIO_OUTPUT 0x14
# define ZEVIO_GPIO_INPUT 0x18
# define ZEVIO_GPIO_INT_STICKY 0x20
/* Bit number of GPIO in its section */
# define ZEVIO_GPIO_BIT(gpio) (gpio&7)
struct zevio_gpio {
2022-05-12 10:14:15 +03:00
struct gpio_chip chip ;
2014-02-24 23:54:58 +04:00
spinlock_t lock ;
2022-05-12 10:14:15 +03:00
void __iomem * regs ;
2014-02-24 23:54:58 +04:00
} ;
static inline u32 zevio_gpio_port_get ( struct zevio_gpio * c , unsigned pin ,
unsigned port_offset )
{
unsigned section_offset = ( ( pin > > 3 ) & 3 ) * ZEVIO_GPIO_SECTION_SIZE ;
2022-05-12 10:14:15 +03:00
return readl ( IOMEM ( c - > regs + section_offset + port_offset ) ) ;
2014-02-24 23:54:58 +04:00
}
static inline void zevio_gpio_port_set ( struct zevio_gpio * c , unsigned pin ,
unsigned port_offset , u32 val )
{
unsigned section_offset = ( ( pin > > 3 ) & 3 ) * ZEVIO_GPIO_SECTION_SIZE ;
2022-05-12 10:14:15 +03:00
writel ( val , IOMEM ( c - > regs + section_offset + port_offset ) ) ;
2014-02-24 23:54:58 +04:00
}
/* Functions for struct gpio_chip */
static int zevio_gpio_get ( struct gpio_chip * chip , unsigned pin )
{
2015-12-07 17:26:02 +03:00
struct zevio_gpio * controller = gpiochip_get_data ( chip ) ;
2014-04-08 03:59:39 +04:00
u32 val , dir ;
2014-02-24 23:54:58 +04:00
2014-04-08 03:59:39 +04:00
spin_lock ( & controller - > lock ) ;
dir = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_DIRECTION ) ;
if ( dir & BIT ( ZEVIO_GPIO_BIT ( pin ) ) )
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_INPUT ) ;
else
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_OUTPUT ) ;
spin_unlock ( & controller - > lock ) ;
2014-02-24 23:54:58 +04:00
return ( val > > ZEVIO_GPIO_BIT ( pin ) ) & 0x1 ;
}
static void zevio_gpio_set ( struct gpio_chip * chip , unsigned pin , int value )
{
2015-12-07 17:26:02 +03:00
struct zevio_gpio * controller = gpiochip_get_data ( chip ) ;
2014-02-24 23:54:58 +04:00
u32 val ;
spin_lock ( & controller - > lock ) ;
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_OUTPUT ) ;
if ( value )
val | = BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
else
val & = ~ BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
zevio_gpio_port_set ( controller , pin , ZEVIO_GPIO_OUTPUT , val ) ;
spin_unlock ( & controller - > lock ) ;
}
static int zevio_gpio_direction_input ( struct gpio_chip * chip , unsigned pin )
{
2015-12-07 17:26:02 +03:00
struct zevio_gpio * controller = gpiochip_get_data ( chip ) ;
2014-02-24 23:54:58 +04:00
u32 val ;
spin_lock ( & controller - > lock ) ;
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_DIRECTION ) ;
val | = BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
zevio_gpio_port_set ( controller , pin , ZEVIO_GPIO_DIRECTION , val ) ;
spin_unlock ( & controller - > lock ) ;
return 0 ;
}
static int zevio_gpio_direction_output ( struct gpio_chip * chip ,
unsigned pin , int value )
{
2015-12-07 17:26:02 +03:00
struct zevio_gpio * controller = gpiochip_get_data ( chip ) ;
2014-02-24 23:54:58 +04:00
u32 val ;
spin_lock ( & controller - > lock ) ;
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_OUTPUT ) ;
if ( value )
val | = BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
else
val & = ~ BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
zevio_gpio_port_set ( controller , pin , ZEVIO_GPIO_OUTPUT , val ) ;
val = zevio_gpio_port_get ( controller , pin , ZEVIO_GPIO_DIRECTION ) ;
val & = ~ BIT ( ZEVIO_GPIO_BIT ( pin ) ) ;
zevio_gpio_port_set ( controller , pin , ZEVIO_GPIO_DIRECTION , val ) ;
spin_unlock ( & controller - > lock ) ;
return 0 ;
}
static int zevio_gpio_to_irq ( struct gpio_chip * chip , unsigned pin )
{
/*
* TODO : Implement IRQs .
* Not implemented yet due to weird lockups
*/
return - ENXIO ;
}
2017-08-20 21:27:46 +03:00
static const struct gpio_chip zevio_gpio_chip = {
2014-02-24 23:54:58 +04:00
. direction_input = zevio_gpio_direction_input ,
. direction_output = zevio_gpio_direction_output ,
. set = zevio_gpio_set ,
. get = zevio_gpio_get ,
. to_irq = zevio_gpio_to_irq ,
. base = 0 ,
. owner = THIS_MODULE ,
. ngpio = 32 ,
} ;
/* Initialization */
static int zevio_gpio_probe ( struct platform_device * pdev )
{
struct zevio_gpio * controller ;
int status , i ;
controller = devm_kzalloc ( & pdev - > dev , sizeof ( * controller ) , GFP_KERNEL ) ;
2014-04-29 12:46:22 +04:00
if ( ! controller )
2014-02-24 23:54:58 +04:00
return - ENOMEM ;
2015-01-18 14:39:31 +03:00
platform_set_drvdata ( pdev , controller ) ;
2014-02-24 23:54:58 +04:00
/* Copy our reference */
2022-05-12 10:14:15 +03:00
controller - > chip = zevio_gpio_chip ;
controller - > chip . parent = & pdev - > dev ;
2014-02-24 23:54:58 +04:00
2022-05-12 10:14:15 +03:00
controller - > regs = devm_platform_ioremap_resource ( pdev , 0 ) ;
if ( IS_ERR ( controller - > regs ) )
return dev_err_probe ( & pdev - > dev , PTR_ERR ( controller - > regs ) ,
" failed to ioremap memory resource \n " ) ;
status = devm_gpiochip_add_data ( & pdev - > dev , & controller - > chip , controller ) ;
2014-02-24 23:54:58 +04:00
if ( status ) {
dev_err ( & pdev - > dev , " failed to add gpiochip: %d \n " , status ) ;
return status ;
}
spin_lock_init ( & controller - > lock ) ;
/* Disable interrupts, they only cause errors */
2022-05-12 10:14:15 +03:00
for ( i = 0 ; i < controller - > chip . ngpio ; i + = 8 )
2014-02-24 23:54:58 +04:00
zevio_gpio_port_set ( controller , i , ZEVIO_GPIO_INT_MASK , 0xFF ) ;
2022-05-12 10:14:15 +03:00
dev_dbg ( controller - > chip . parent , " ZEVIO GPIO controller set up! \n " ) ;
2014-02-24 23:54:58 +04:00
return 0 ;
}
2014-05-07 13:09:01 +04:00
static const struct of_device_id zevio_gpio_of_match [ ] = {
2014-02-24 23:54:58 +04:00
{ . compatible = " lsi,zevio-gpio " , } ,
{ } ,
} ;
static struct platform_driver zevio_gpio_driver = {
. driver = {
. name = " gpio-zevio " ,
2014-04-08 07:44:49 +04:00
. of_match_table = zevio_gpio_of_match ,
2016-05-10 02:59:58 +03:00
. suppress_bind_attrs = true ,
2014-02-24 23:54:58 +04:00
} ,
. probe = zevio_gpio_probe ,
} ;
2016-05-10 02:59:58 +03:00
builtin_platform_driver ( zevio_gpio_driver ) ;