2011-07-06 14:32:13 +04:00
/*
* GPIO Driver for Dialog DA9052 PMICs .
*
* Copyright ( c ) 2011 Dialog Semiconductor Ltd .
*
* Author : David Dajun Chen < dchen @ diasemi . com >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation ; either version 2 of the License , or ( at your
* option ) any later version .
*
*/
# include <linux/module.h>
# include <linux/fs.h>
# include <linux/uaccess.h>
# include <linux/platform_device.h>
# include <linux/gpio.h>
# include <linux/syscalls.h>
# include <linux/seq_file.h>
# include <linux/mfd/da9052/da9052.h>
# include <linux/mfd/da9052/reg.h>
# include <linux/mfd/da9052/pdata.h>
# define DA9052_INPUT 1
# define DA9052_OUTPUT_OPENDRAIN 2
# define DA9052_OUTPUT_PUSHPULL 3
# define DA9052_SUPPLY_VDD_IO1 0
# define DA9052_DEBOUNCING_OFF 0
# define DA9052_DEBOUNCING_ON 1
# define DA9052_OUTPUT_LOWLEVEL 0
# define DA9052_ACTIVE_LOW 0
# define DA9052_ACTIVE_HIGH 1
# define DA9052_GPIO_MAX_PORTS_PER_REGISTER 8
# define DA9052_GPIO_SHIFT_COUNT(no) (no%8)
# define DA9052_GPIO_MASK_UPPER_NIBBLE 0xF0
# define DA9052_GPIO_MASK_LOWER_NIBBLE 0x0F
# define DA9052_GPIO_NIBBLE_SHIFT 4
2011-12-15 13:25:46 +04:00
# define DA9052_IRQ_GPI0 16
# define DA9052_GPIO_ODD_SHIFT 7
# define DA9052_GPIO_EVEN_SHIFT 3
2011-07-06 14:32:13 +04:00
struct da9052_gpio {
struct da9052 * da9052 ;
struct gpio_chip gp ;
} ;
static unsigned char da9052_gpio_port_odd ( unsigned offset )
{
return offset % 2 ;
}
static int da9052_gpio_get ( struct gpio_chip * gc , unsigned offset )
{
2015-12-04 18:19:52 +03:00
struct da9052_gpio * gpio = gpiochip_get_data ( gc ) ;
2011-07-06 14:32:13 +04:00
int da9052_port_direction = 0 ;
int ret ;
ret = da9052_reg_read ( gpio - > da9052 ,
DA9052_GPIO_0_1_REG + ( offset > > 1 ) ) ;
if ( ret < 0 )
return ret ;
if ( da9052_gpio_port_odd ( offset ) ) {
da9052_port_direction = ret & DA9052_GPIO_ODD_PORT_PIN ;
da9052_port_direction > > = 4 ;
} else {
da9052_port_direction = ret & DA9052_GPIO_EVEN_PORT_PIN ;
}
switch ( da9052_port_direction ) {
case DA9052_INPUT :
if ( offset < DA9052_GPIO_MAX_PORTS_PER_REGISTER )
ret = da9052_reg_read ( gpio - > da9052 ,
DA9052_STATUS_C_REG ) ;
else
ret = da9052_reg_read ( gpio - > da9052 ,
DA9052_STATUS_D_REG ) ;
if ( ret < 0 )
return ret ;
2015-12-21 12:30:02 +03:00
return ! ! ( ret & ( 1 < < DA9052_GPIO_SHIFT_COUNT ( offset ) ) ) ;
2011-07-06 14:32:13 +04:00
case DA9052_OUTPUT_PUSHPULL :
if ( da9052_gpio_port_odd ( offset ) )
2015-12-21 12:30:02 +03:00
return ! ! ( ret & DA9052_GPIO_ODD_PORT_MODE ) ;
2011-07-06 14:32:13 +04:00
else
2015-12-21 12:30:02 +03:00
return ! ! ( ret & DA9052_GPIO_EVEN_PORT_MODE ) ;
2011-07-06 14:32:13 +04:00
default :
return - EINVAL ;
}
}
static void da9052_gpio_set ( struct gpio_chip * gc , unsigned offset , int value )
{
2015-12-04 18:19:52 +03:00
struct da9052_gpio * gpio = gpiochip_get_data ( gc ) ;
2011-07-06 14:32:13 +04:00
int ret ;
if ( da9052_gpio_port_odd ( offset ) ) {
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_ODD_PORT_MODE ,
2011-12-15 13:25:46 +04:00
value < < DA9052_GPIO_ODD_SHIFT ) ;
2011-07-06 14:32:13 +04:00
if ( ret ! = 0 )
dev_err ( gpio - > da9052 - > dev ,
" Failed to updated gpio odd reg,%d " ,
ret ) ;
} else {
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_EVEN_PORT_MODE ,
2011-12-15 13:25:46 +04:00
value < < DA9052_GPIO_EVEN_SHIFT ) ;
2011-07-06 14:32:13 +04:00
if ( ret ! = 0 )
dev_err ( gpio - > da9052 - > dev ,
" Failed to updated gpio even reg,%d " ,
ret ) ;
}
}
static int da9052_gpio_direction_input ( struct gpio_chip * gc , unsigned offset )
{
2015-12-04 18:19:52 +03:00
struct da9052_gpio * gpio = gpiochip_get_data ( gc ) ;
2011-07-06 14:32:13 +04:00
unsigned char register_value ;
int ret ;
/* Format: function - 2 bits type - 1 bit mode - 1 bit */
register_value = DA9052_INPUT | DA9052_ACTIVE_LOW < < 2 |
DA9052_DEBOUNCING_ON < < 3 ;
if ( da9052_gpio_port_odd ( offset ) )
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_MASK_UPPER_NIBBLE ,
( register_value < <
DA9052_GPIO_NIBBLE_SHIFT ) ) ;
else
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_MASK_LOWER_NIBBLE ,
register_value ) ;
return ret ;
}
static int da9052_gpio_direction_output ( struct gpio_chip * gc ,
unsigned offset , int value )
{
2015-12-04 18:19:52 +03:00
struct da9052_gpio * gpio = gpiochip_get_data ( gc ) ;
2011-07-06 14:32:13 +04:00
unsigned char register_value ;
int ret ;
/* Format: Function - 2 bits Type - 1 bit Mode - 1 bit */
register_value = DA9052_OUTPUT_PUSHPULL | DA9052_SUPPLY_VDD_IO1 < < 2 |
value < < 3 ;
if ( da9052_gpio_port_odd ( offset ) )
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_MASK_UPPER_NIBBLE ,
( register_value < <
DA9052_GPIO_NIBBLE_SHIFT ) ) ;
else
ret = da9052_reg_update ( gpio - > da9052 , ( offset > > 1 ) +
DA9052_GPIO_0_1_REG ,
DA9052_GPIO_MASK_LOWER_NIBBLE ,
register_value ) ;
return ret ;
}
static int da9052_gpio_to_irq ( struct gpio_chip * gc , u32 offset )
{
2015-12-04 18:19:52 +03:00
struct da9052_gpio * gpio = gpiochip_get_data ( gc ) ;
2011-07-06 14:32:13 +04:00
struct da9052 * da9052 = gpio - > da9052 ;
2012-10-04 07:15:09 +04:00
int irq ;
irq = regmap_irq_get_virq ( da9052 - > irq_data , DA9052_IRQ_GPI0 + offset ) ;
return irq ;
2011-07-06 14:32:13 +04:00
}
2012-11-19 22:24:14 +04:00
static struct gpio_chip reference_gp = {
2011-07-06 14:32:13 +04:00
. label = " da9052-gpio " ,
. owner = THIS_MODULE ,
. get = da9052_gpio_get ,
. set = da9052_gpio_set ,
. direction_input = da9052_gpio_direction_input ,
. direction_output = da9052_gpio_direction_output ,
. to_irq = da9052_gpio_to_irq ,
2013-12-04 17:42:46 +04:00
. can_sleep = true ,
2011-12-15 13:25:46 +04:00
. ngpio = 16 ,
. base = - 1 ,
2011-07-06 14:32:13 +04:00
} ;
2012-11-19 22:22:34 +04:00
static int da9052_gpio_probe ( struct platform_device * pdev )
2011-07-06 14:32:13 +04:00
{
struct da9052_gpio * gpio ;
struct da9052_pdata * pdata ;
int ret ;
2012-09-01 13:34:15 +04:00
gpio = devm_kzalloc ( & pdev - > dev , sizeof ( * gpio ) , GFP_KERNEL ) ;
2015-03-31 07:19:11 +03:00
if ( ! gpio )
2011-07-06 14:32:13 +04:00
return - ENOMEM ;
gpio - > da9052 = dev_get_drvdata ( pdev - > dev . parent ) ;
2013-07-30 12:08:05 +04:00
pdata = dev_get_platdata ( gpio - > da9052 - > dev ) ;
2011-07-06 14:32:13 +04:00
gpio - > gp = reference_gp ;
if ( pdata & & pdata - > gpio_base )
gpio - > gp . base = pdata - > gpio_base ;
2016-02-22 15:13:28 +03:00
ret = devm_gpiochip_add_data ( & pdev - > dev , & gpio - > gp , gpio ) ;
2011-07-06 14:32:13 +04:00
if ( ret < 0 ) {
dev_err ( & pdev - > dev , " Could not register gpiochip, %d \n " , ret ) ;
2012-09-01 13:34:15 +04:00
return ret ;
2011-07-06 14:32:13 +04:00
}
platform_set_drvdata ( pdev , gpio ) ;
return 0 ;
}
static struct platform_driver da9052_gpio_driver = {
. probe = da9052_gpio_probe ,
. driver = {
. name = " da9052-gpio " ,
} ,
} ;
2011-12-07 20:24:00 +04:00
module_platform_driver ( da9052_gpio_driver ) ;
2011-07-06 14:32:13 +04:00
MODULE_AUTHOR ( " David Dajun Chen <dchen@diasemi.com> " ) ;
MODULE_DESCRIPTION ( " DA9052 GPIO Device Driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_ALIAS ( " platform:da9052-gpio " ) ;