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 >
*/
# include <linux/spinlock.h>
# 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/bitops.h>
# include <linux/io.h>
# include <linux/of_device.h>
# include <linux/of_gpio.h>
# include <linux/slab.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 {
spinlock_t lock ;
struct of_mm_gpio_chip chip ;
} ;
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 ;
return readl ( IOMEM ( c - > chip . regs + section_offset + port_offset ) ) ;
}
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 ;
writel ( val , IOMEM ( c - > chip . regs + section_offset + port_offset ) ) ;
}
/* 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 ,
. of_gpio_n_cells = 2 ,
} ;
/* 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 */
controller - > chip . gc = zevio_gpio_chip ;
2015-11-04 11:56:26 +03:00
controller - > chip . gc . parent = & pdev - > dev ;
2014-02-24 23:54:58 +04:00
2015-12-07 17:26:02 +03:00
status = of_mm_gpiochip_add_data ( pdev - > dev . of_node ,
& ( 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 */
for ( i = 0 ; i < controller - > chip . gc . ngpio ; i + = 8 )
zevio_gpio_port_set ( controller , i , ZEVIO_GPIO_INT_MASK , 0xFF ) ;
2015-11-04 11:56:26 +03:00
dev_dbg ( controller - > chip . gc . 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 ) ;