2010-10-28 02:33:15 +04:00
/*
2011-06-05 04:38:28 +04:00
* Generic driver for memory - mapped GPIO controllers .
2010-10-28 02:33:15 +04:00
*
* Copyright 2008 MontaVista Software , Inc .
* Copyright 2008 , 2010 Anton Vorontsov < cbouatmailru @ gmail . 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 .
*
* . . . . ` ` . ` ` ` ~ ~ ~ ~ ` ` ` ` . ` . ` . ` . ` . ` ` ` ` ` ` ` ' ' , , , . . . . . . . . . ` ` ` ` ` . . . . . . ` . . . . . . .
* . . . ` ` ` ` ` ` ` ` ` . .
* . . The simplest form of a GPIO controller that the driver supports is ` `
* ` . just a single " data " register , where GPIO state can be read and / or `
* ` , . . written . , , . . ` ` ~ ~ ~ ~ . . . . . ` ` . ` . ` . ~ ~ . ` ` ` . ` . . . . . . . . . ` ` ` ` ` ` . ` ` ` ` ` ` `
* ` ` ` ` ` ` ` ` `
___
_ / ~ ~ | ___ / ~ | . ` ` ` ~ ~ ~ ~ ~ ~ ___ / ___ \ ___ , ~ . ` . ` . ` . ` ` ` ` ` . ~ ~ . . . , , , , . . .
__________ | ~ $ @ ~ ~ ~ % ~ / o * o * o * o * o * o \ . . Implementing such a GPIO .
o ` ~ ~ ~ ~ \ ___ / ~ ~ ~ ~ ` controller in FPGA is , . `
` . . . . trivial . . ' ~ ` . ` ` ` . ` ` `
* ` ` ` ` ` ` `
* . ` ` ` ` ` ` ` ~ ~ ~ ~ ` . . ` . ` ` . ` ` .
* . The driver supports ` . . . , . . ` ` ` . ` ~ ~ ~ ` ` ` ` ` ` ` ` ` ` ` ` ` ` ` . . . . ` ` ` ` . ` ` , ,
* . big - endian notation , just ` . . . A bit more sophisticated controllers ,
* . register the device with - be ` . . with a pair of set / clear - bit registers ,
* ` . . suffix . ` ` ` ~ ~ ` ` ` ` ` . . . . ` . ` . affecting the data register and the . `
* ` ` . ` . ` ` . . . ` ` ` ` ` ` . . output pins are also supported . `
* ^ ^ ` ` ` ` ` . ` ` ` ` ` ` ` ` ` . , ` ` ~ ` ` ~ ` ` ~ ~ ` ` ` ` ` `
* . ^ ^
* , . . ` . ` . ` . . . ` ` ` ` ` ` ` ` ` ` ` ` . . . . . . ` . ` . ` . ` . ` . ` . . ` . ` . ` . .
* . . The expectation is that in at least some cases . , - ~ ~ ~ - ,
* . this will be used with roll - your - own ASIC / FPGA . ` \ /
* . logic in Verilog or VHDL . ~ ~ ~ ` ` ` ` ` ` ` ` ` . . ` ` ` ` ` ~ ~ ` \ /
* . . ` ` ` ` ` ` ` ` . . . . . . ` ` ` ` ` ` ` ` ` ` ` \ o_
* |
* ^ ^ / \
*
* . . . ` ` ` ` ` ~ ~ ` . . . . . ` ` . ` . . . . . . . . . . ` ` ` ` ` ` . ` . ` ` . ` ` ` . . . . . . . . ` ` .
* ` 8 , 16 , 32 and 64 bits registers are supported , and ` ` .
* . the number of GPIOs is determined by the width of ~
* . . the registers . , . . . . . . . . . . . . ` ` ` . ` . ` . . ` . ` . ~ ~ ~ . ` . ` . ` ~
* ` . . . . . . . ` ` ` ` . ` ` `
*/
# include <linux/init.h>
2011-05-20 10:40:19 +04:00
# include <linux/err.h>
2010-10-28 02:33:15 +04:00
# include <linux/bug.h>
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/spinlock.h>
# include <linux/compiler.h>
# include <linux/types.h>
# include <linux/errno.h>
# include <linux/log2.h>
# include <linux/ioport.h>
# include <linux/io.h>
# include <linux/gpio.h>
# include <linux/slab.h>
# include <linux/platform_device.h>
# include <linux/mod_devicetable.h>
# include <linux/basic_mmio_gpio.h>
2011-05-20 10:40:14 +04:00
static void bgpio_write8 ( void __iomem * reg , unsigned long data )
2010-10-28 02:33:15 +04:00
{
2011-05-20 10:40:17 +04:00
writeb ( data , reg ) ;
2010-10-28 02:33:15 +04:00
}
2011-05-20 10:40:14 +04:00
static unsigned long bgpio_read8 ( void __iomem * reg )
2010-10-28 02:33:15 +04:00
{
2011-05-20 10:40:17 +04:00
return readb ( reg ) ;
2011-05-20 10:40:14 +04:00
}
static void bgpio_write16 ( void __iomem * reg , unsigned long data )
{
2011-05-20 10:40:17 +04:00
writew ( data , reg ) ;
2011-05-20 10:40:14 +04:00
}
static unsigned long bgpio_read16 ( void __iomem * reg )
{
2011-05-20 10:40:17 +04:00
return readw ( reg ) ;
2011-05-20 10:40:14 +04:00
}
static void bgpio_write32 ( void __iomem * reg , unsigned long data )
{
2011-05-20 10:40:17 +04:00
writel ( data , reg ) ;
2011-05-20 10:40:14 +04:00
}
static unsigned long bgpio_read32 ( void __iomem * reg )
{
2011-05-20 10:40:17 +04:00
return readl ( reg ) ;
2011-05-20 10:40:14 +04:00
}
2010-10-28 02:33:15 +04:00
# if BITS_PER_LONG >= 64
2011-05-20 10:40:14 +04:00
static void bgpio_write64 ( void __iomem * reg , unsigned long data )
{
2011-05-20 10:40:17 +04:00
writeq ( data , reg ) ;
2011-05-20 10:40:14 +04:00
}
static unsigned long bgpio_read64 ( void __iomem * reg )
{
2011-05-20 10:40:17 +04:00
return readq ( reg ) ;
2010-10-28 02:33:15 +04:00
}
2011-05-20 10:40:14 +04:00
# endif /* BITS_PER_LONG >= 64 */
2010-10-28 02:33:15 +04:00
2013-03-15 17:45:38 +04:00
static void bgpio_write16be ( void __iomem * reg , unsigned long data )
{
iowrite16be ( data , reg ) ;
}
static unsigned long bgpio_read16be ( void __iomem * reg )
{
return ioread16be ( reg ) ;
}
static void bgpio_write32be ( void __iomem * reg , unsigned long data )
{
iowrite32be ( data , reg ) ;
}
static unsigned long bgpio_read32be ( void __iomem * reg )
{
return ioread32be ( reg ) ;
}
2010-10-28 02:33:15 +04:00
static unsigned long bgpio_pin2mask ( struct bgpio_chip * bgc , unsigned int pin )
{
2011-05-20 10:40:14 +04:00
return 1 < < pin ;
}
static unsigned long bgpio_pin2mask_be ( struct bgpio_chip * bgc ,
unsigned int pin )
{
return 1 < < ( bgc - > bits - 1 - pin ) ;
2010-10-28 02:33:15 +04:00
}
2015-04-29 18:34:59 +03:00
static int bgpio_get_set ( struct gpio_chip * gc , unsigned int gpio )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long pinmask = bgc - > pin2mask ( bgc , gpio ) ;
if ( bgc - > dir & pinmask )
return bgc - > read_reg ( bgc - > reg_set ) & pinmask ;
else
return bgc - > read_reg ( bgc - > reg_dat ) & pinmask ;
}
2010-10-28 02:33:15 +04:00
static int bgpio_get ( struct gpio_chip * gc , unsigned int gpio )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
2014-02-05 17:08:02 +04:00
return ! ! ( bgc - > read_reg ( bgc - > reg_dat ) & bgc - > pin2mask ( bgc , gpio ) ) ;
2010-10-28 02:33:15 +04:00
}
2015-07-22 16:05:18 +03:00
static void bgpio_set_none ( struct gpio_chip * gc , unsigned int gpio , int val )
{
}
2010-10-28 02:33:15 +04:00
static void bgpio_set ( struct gpio_chip * gc , unsigned int gpio , int val )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
2011-05-20 10:40:14 +04:00
unsigned long mask = bgc - > pin2mask ( bgc , gpio ) ;
2010-10-28 02:33:15 +04:00
unsigned long flags ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
if ( val )
bgc - > data | = mask ;
else
bgc - > data & = ~ mask ;
2011-05-20 10:40:14 +04:00
bgc - > write_reg ( bgc - > reg_dat , bgc - > data ) ;
2010-10-28 02:33:15 +04:00
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
}
2011-05-20 10:40:16 +04:00
static void bgpio_set_with_clear ( struct gpio_chip * gc , unsigned int gpio ,
int val )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long mask = bgc - > pin2mask ( bgc , gpio ) ;
if ( val )
bgc - > write_reg ( bgc - > reg_set , mask ) ;
else
bgc - > write_reg ( bgc - > reg_clr , mask ) ;
}
2011-05-20 10:40:16 +04:00
static void bgpio_set_set ( struct gpio_chip * gc , unsigned int gpio , int val )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long mask = bgc - > pin2mask ( bgc , gpio ) ;
unsigned long flags ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
if ( val )
bgc - > data | = mask ;
else
bgc - > data & = ~ mask ;
bgc - > write_reg ( bgc - > reg_set , bgc - > data ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
}
2015-01-14 17:46:38 +03:00
static void bgpio_multiple_get_masks ( struct bgpio_chip * bgc ,
unsigned long * mask , unsigned long * bits ,
unsigned long * set_mask ,
unsigned long * clear_mask )
{
int i ;
* set_mask = 0 ;
* clear_mask = 0 ;
for ( i = 0 ; i < bgc - > bits ; i + + ) {
if ( * mask = = 0 )
break ;
if ( __test_and_clear_bit ( i , mask ) ) {
if ( test_bit ( i , bits ) )
* set_mask | = bgc - > pin2mask ( bgc , i ) ;
else
* clear_mask | = bgc - > pin2mask ( bgc , i ) ;
}
}
}
static void bgpio_set_multiple_single_reg ( struct bgpio_chip * bgc ,
unsigned long * mask ,
unsigned long * bits ,
void __iomem * reg )
{
unsigned long flags ;
unsigned long set_mask , clear_mask ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
bgpio_multiple_get_masks ( bgc , mask , bits , & set_mask , & clear_mask ) ;
bgc - > data | = set_mask ;
bgc - > data & = ~ clear_mask ;
bgc - > write_reg ( reg , bgc - > data ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
}
static void bgpio_set_multiple ( struct gpio_chip * gc , unsigned long * mask ,
unsigned long * bits )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
bgpio_set_multiple_single_reg ( bgc , mask , bits , bgc - > reg_dat ) ;
}
static void bgpio_set_multiple_set ( struct gpio_chip * gc , unsigned long * mask ,
unsigned long * bits )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
bgpio_set_multiple_single_reg ( bgc , mask , bits , bgc - > reg_set ) ;
}
static void bgpio_set_multiple_with_clear ( struct gpio_chip * gc ,
unsigned long * mask ,
unsigned long * bits )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long set_mask , clear_mask ;
bgpio_multiple_get_masks ( bgc , mask , bits , & set_mask , & clear_mask ) ;
if ( set_mask )
bgc - > write_reg ( bgc - > reg_set , set_mask ) ;
if ( clear_mask )
bgc - > write_reg ( bgc - > reg_clr , clear_mask ) ;
}
2011-05-20 10:40:17 +04:00
static int bgpio_simple_dir_in ( struct gpio_chip * gc , unsigned int gpio )
{
return 0 ;
}
2015-07-22 16:05:18 +03:00
static int bgpio_dir_out_err ( struct gpio_chip * gc , unsigned int gpio ,
int val )
{
return - EINVAL ;
}
2011-05-20 10:40:17 +04:00
static int bgpio_simple_dir_out ( struct gpio_chip * gc , unsigned int gpio ,
int val )
{
gc - > set ( gc , gpio , val ) ;
return 0 ;
}
2010-10-28 02:33:15 +04:00
static int bgpio_dir_in ( struct gpio_chip * gc , unsigned int gpio )
{
2011-05-20 10:40:17 +04:00
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long flags ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
bgc - > dir & = ~ bgc - > pin2mask ( bgc , gpio ) ;
bgc - > write_reg ( bgc - > reg_dir , bgc - > dir ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
2010-10-28 02:33:15 +04:00
return 0 ;
}
2015-06-12 19:20:35 +03:00
static int bgpio_get_dir ( struct gpio_chip * gc , unsigned int gpio )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
return ( bgc - > read_reg ( bgc - > reg_dir ) & bgc - > pin2mask ( bgc , gpio ) ) ?
GPIOF_DIR_OUT : GPIOF_DIR_IN ;
}
2010-10-28 02:33:15 +04:00
static int bgpio_dir_out ( struct gpio_chip * gc , unsigned int gpio , int val )
{
2011-05-20 10:40:17 +04:00
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long flags ;
gc - > set ( gc , gpio , val ) ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
bgc - > dir | = bgc - > pin2mask ( bgc , gpio ) ;
bgc - > write_reg ( bgc - > reg_dir , bgc - > dir ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
static int bgpio_dir_in_inv ( struct gpio_chip * gc , unsigned int gpio )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long flags ;
spin_lock_irqsave ( & bgc - > lock , flags ) ;
bgc - > dir | = bgc - > pin2mask ( bgc , gpio ) ;
bgc - > write_reg ( bgc - > reg_dir , bgc - > dir ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
return 0 ;
}
static int bgpio_dir_out_inv ( struct gpio_chip * gc , unsigned int gpio , int val )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
unsigned long flags ;
2011-05-20 10:40:16 +04:00
gc - > set ( gc , gpio , val ) ;
2011-05-20 10:40:17 +04:00
spin_lock_irqsave ( & bgc - > lock , flags ) ;
bgc - > dir & = ~ bgc - > pin2mask ( bgc , gpio ) ;
bgc - > write_reg ( bgc - > reg_dir , bgc - > dir ) ;
spin_unlock_irqrestore ( & bgc - > lock , flags ) ;
2010-10-28 02:33:15 +04:00
return 0 ;
}
2015-06-12 19:20:35 +03:00
static int bgpio_get_dir_inv ( struct gpio_chip * gc , unsigned int gpio )
{
struct bgpio_chip * bgc = to_bgpio_chip ( gc ) ;
return ( bgc - > read_reg ( bgc - > reg_dir ) & bgc - > pin2mask ( bgc , gpio ) ) ?
GPIOF_DIR_IN : GPIOF_DIR_OUT ;
}
2011-05-20 10:40:19 +04:00
static int bgpio_setup_accessors ( struct device * dev ,
struct bgpio_chip * bgc ,
2013-03-15 17:45:38 +04:00
bool bit_be ,
bool byte_be )
2010-10-28 02:33:15 +04:00
{
2011-05-20 10:40:14 +04:00
switch ( bgc - > bits ) {
case 8 :
bgc - > read_reg = bgpio_read8 ;
bgc - > write_reg = bgpio_write8 ;
break ;
case 16 :
2013-03-15 17:45:38 +04:00
if ( byte_be ) {
bgc - > read_reg = bgpio_read16be ;
bgc - > write_reg = bgpio_write16be ;
} else {
bgc - > read_reg = bgpio_read16 ;
bgc - > write_reg = bgpio_write16 ;
}
2011-05-20 10:40:14 +04:00
break ;
case 32 :
2013-03-15 17:45:38 +04:00
if ( byte_be ) {
bgc - > read_reg = bgpio_read32be ;
bgc - > write_reg = bgpio_write32be ;
} else {
bgc - > read_reg = bgpio_read32 ;
bgc - > write_reg = bgpio_write32 ;
}
2011-05-20 10:40:14 +04:00
break ;
# if BITS_PER_LONG >= 64
case 64 :
2013-03-15 17:45:38 +04:00
if ( byte_be ) {
dev_err ( dev ,
" 64 bit big endian byte order unsupported \n " ) ;
return - EINVAL ;
} else {
bgc - > read_reg = bgpio_read64 ;
bgc - > write_reg = bgpio_write64 ;
}
2011-05-20 10:40:14 +04:00
break ;
# endif /* BITS_PER_LONG >= 64 */
default :
2011-05-20 10:40:19 +04:00
dev_err ( dev , " unsupported data width %u bits \n " , bgc - > bits ) ;
2011-05-20 10:40:14 +04:00
return - EINVAL ;
}
2013-03-15 17:45:38 +04:00
bgc - > pin2mask = bit_be ? bgpio_pin2mask_be : bgpio_pin2mask ;
2011-05-20 10:40:14 +04:00
return 0 ;
}
2011-05-20 10:40:16 +04:00
/*
* Create the device and allocate the resources . For setting GPIO ' s there are
2011-05-20 10:40:16 +04:00
* three supported configurations :
2011-05-20 10:40:16 +04:00
*
2011-05-20 10:40:16 +04:00
* - single input / output register resource ( named " dat " ) .
2011-05-20 10:40:16 +04:00
* - set / clear pair ( named " set " and " clr " ) .
2011-05-20 10:40:16 +04:00
* - single output register resource and single input resource ( " set " and
* dat " ).
2011-05-20 10:40:16 +04:00
*
* For the single output register , this drives a 1 by setting a bit and a zero
* by clearing a bit . For the set clr pair , this drives a 1 by setting a bit
* in the set register and clears it by setting a bit in the clear register .
* The configuration is detected by which resources are present .
2011-05-20 10:40:17 +04:00
*
* For setting the GPIO direction , there are three supported configurations :
*
* - simple bidirection GPIO that requires no configuration .
* - an output direction register ( named " dirout " ) where a 1 bit
* indicates the GPIO is an output .
* - an input direction register ( named " dirin " ) where a 1 bit indicates
* the GPIO is an input .
2011-05-20 10:40:16 +04:00
*/
2011-05-20 10:40:19 +04:00
static int bgpio_setup_io ( struct bgpio_chip * bgc ,
void __iomem * dat ,
void __iomem * set ,
2015-04-29 18:34:59 +03:00
void __iomem * clr ,
unsigned long flags )
2011-05-20 10:40:14 +04:00
{
2010-10-28 02:33:15 +04:00
2011-05-20 10:40:19 +04:00
bgc - > reg_dat = dat ;
2010-10-28 02:33:15 +04:00
if ( ! bgc - > reg_dat )
2011-05-20 10:40:19 +04:00
return - EINVAL ;
2011-05-20 10:40:16 +04:00
2011-05-20 10:40:19 +04:00
if ( set & & clr ) {
bgc - > reg_set = set ;
bgc - > reg_clr = clr ;
2011-05-20 10:40:16 +04:00
bgc - > gc . set = bgpio_set_with_clear ;
2015-01-14 17:46:38 +03:00
bgc - > gc . set_multiple = bgpio_set_multiple_with_clear ;
2011-05-20 10:40:19 +04:00
} else if ( set & & ! clr ) {
bgc - > reg_set = set ;
2011-05-20 10:40:16 +04:00
bgc - > gc . set = bgpio_set_set ;
2015-01-14 17:46:38 +03:00
bgc - > gc . set_multiple = bgpio_set_multiple_set ;
2015-07-22 16:05:18 +03:00
} else if ( flags & BGPIOF_NO_OUTPUT ) {
bgc - > gc . set = bgpio_set_none ;
bgc - > gc . set_multiple = NULL ;
2011-05-20 10:40:16 +04:00
} else {
bgc - > gc . set = bgpio_set ;
2015-01-14 17:46:38 +03:00
bgc - > gc . set_multiple = bgpio_set_multiple ;
2010-10-28 02:33:15 +04:00
}
2015-04-29 18:34:59 +03:00
if ( ! ( flags & BGPIOF_UNREADABLE_REG_SET ) & &
( flags & BGPIOF_READ_OUTPUT_REG_SET ) )
bgc - > gc . get = bgpio_get_set ;
else
bgc - > gc . get = bgpio_get ;
2011-05-20 10:40:16 +04:00
2011-05-20 10:40:16 +04:00
return 0 ;
}
2011-05-20 10:40:19 +04:00
static int bgpio_setup_direction ( struct bgpio_chip * bgc ,
void __iomem * dirout ,
2015-07-22 16:05:18 +03:00
void __iomem * dirin ,
unsigned long flags )
2011-05-20 10:40:17 +04:00
{
2011-05-20 10:40:19 +04:00
if ( dirout & & dirin ) {
2011-05-20 10:40:17 +04:00
return - EINVAL ;
2011-05-20 10:40:19 +04:00
} else if ( dirout ) {
bgc - > reg_dir = dirout ;
2011-05-20 10:40:17 +04:00
bgc - > gc . direction_output = bgpio_dir_out ;
bgc - > gc . direction_input = bgpio_dir_in ;
2015-06-12 19:20:35 +03:00
bgc - > gc . get_direction = bgpio_get_dir ;
2011-05-20 10:40:19 +04:00
} else if ( dirin ) {
bgc - > reg_dir = dirin ;
2011-05-20 10:40:17 +04:00
bgc - > gc . direction_output = bgpio_dir_out_inv ;
bgc - > gc . direction_input = bgpio_dir_in_inv ;
2015-06-12 19:20:35 +03:00
bgc - > gc . get_direction = bgpio_get_dir_inv ;
2011-05-20 10:40:17 +04:00
} else {
2015-07-22 16:05:18 +03:00
if ( flags & BGPIOF_NO_OUTPUT )
bgc - > gc . direction_output = bgpio_dir_out_err ;
else
bgc - > gc . direction_output = bgpio_simple_dir_out ;
2011-05-20 10:40:17 +04:00
bgc - > gc . direction_input = bgpio_simple_dir_in ;
}
return 0 ;
}
2014-05-19 21:49:14 +04:00
static int bgpio_request ( struct gpio_chip * chip , unsigned gpio_pin )
{
if ( gpio_pin < chip - > ngpio )
return 0 ;
return - EINVAL ;
}
2011-09-15 03:22:29 +04:00
int bgpio_remove ( struct bgpio_chip * bgc )
2011-05-20 10:40:19 +04:00
{
2014-07-13 00:30:12 +04:00
gpiochip_remove ( & bgc - > gc ) ;
return 0 ;
2011-05-20 10:40:19 +04:00
}
EXPORT_SYMBOL_GPL ( bgpio_remove ) ;
2011-09-15 03:22:29 +04:00
int bgpio_init ( struct bgpio_chip * bgc , struct device * dev ,
unsigned long sz , void __iomem * dat , void __iomem * set ,
void __iomem * clr , void __iomem * dirout , void __iomem * dirin ,
2012-05-19 17:34:58 +04:00
unsigned long flags )
2011-05-20 10:40:16 +04:00
{
int ret ;
2011-05-20 10:40:19 +04:00
if ( ! is_power_of_2 ( sz ) )
return - EINVAL ;
2011-05-20 10:40:16 +04:00
2011-05-20 10:40:19 +04:00
bgc - > bits = sz * 8 ;
if ( bgc - > bits > BITS_PER_LONG )
return - EINVAL ;
spin_lock_init ( & bgc - > lock ) ;
bgc - > gc . dev = dev ;
bgc - > gc . label = dev_name ( dev ) ;
bgc - > gc . base = - 1 ;
bgc - > gc . ngpio = bgc - > bits ;
2014-05-19 21:49:14 +04:00
bgc - > gc . request = bgpio_request ;
2011-05-20 10:40:19 +04:00
2015-04-29 18:34:59 +03:00
ret = bgpio_setup_io ( bgc , dat , set , clr , flags ) ;
2011-05-20 10:40:16 +04:00
if ( ret )
return ret ;
2010-10-28 02:33:15 +04:00
2013-03-15 17:45:38 +04:00
ret = bgpio_setup_accessors ( dev , bgc , flags & BGPIOF_BIG_ENDIAN ,
flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER ) ;
2011-05-20 10:40:14 +04:00
if ( ret )
return ret ;
2010-10-28 02:33:15 +04:00
2015-07-22 16:05:18 +03:00
ret = bgpio_setup_direction ( bgc , dirout , dirin , flags ) ;
2011-05-20 10:40:17 +04:00
if ( ret )
return ret ;
2011-05-20 10:40:14 +04:00
bgc - > data = bgc - > read_reg ( bgc - > reg_dat ) ;
2012-05-19 17:34:58 +04:00
if ( bgc - > gc . set = = bgpio_set_set & &
! ( flags & BGPIOF_UNREADABLE_REG_SET ) )
bgc - > data = bgc - > read_reg ( bgc - > reg_set ) ;
if ( bgc - > reg_dir & & ! ( flags & BGPIOF_UNREADABLE_REG_DIR ) )
bgc - > dir = bgc - > read_reg ( bgc - > reg_dir ) ;
2011-05-20 10:40:15 +04:00
2011-05-20 10:40:19 +04:00
return ret ;
}
EXPORT_SYMBOL_GPL ( bgpio_init ) ;
2010-10-28 02:33:15 +04:00
2011-06-05 04:38:28 +04:00
# ifdef CONFIG_GPIO_GENERIC_PLATFORM
2010-10-28 02:33:15 +04:00
2011-05-20 10:40:19 +04:00
static void __iomem * bgpio_map ( struct platform_device * pdev ,
const char * name ,
2015-10-01 00:52:36 +03:00
resource_size_t sane_sz )
2011-05-20 10:40:19 +04:00
{
struct resource * r ;
resource_size_t sz ;
r = platform_get_resource_byname ( pdev , IORESOURCE_MEM , name ) ;
2015-10-01 00:52:36 +03:00
if ( ! r )
2015-10-21 10:12:00 +03:00
return NULL ;
2011-05-20 10:40:19 +04:00
sz = resource_size ( r ) ;
2015-10-01 00:52:36 +03:00
if ( sz ! = sane_sz )
return IOMEM_ERR_PTR ( - EINVAL ) ;
2011-05-20 10:40:19 +04:00
2015-10-01 00:52:36 +03:00
return devm_ioremap_resource ( & pdev - > dev , r ) ;
2010-10-28 02:33:15 +04:00
}
2012-11-19 22:22:34 +04:00
static int bgpio_pdev_probe ( struct platform_device * pdev )
2011-05-20 10:40:19 +04:00
{
struct device * dev = & pdev - > dev ;
struct resource * r ;
void __iomem * dat ;
void __iomem * set ;
void __iomem * clr ;
void __iomem * dirout ;
void __iomem * dirin ;
unsigned long sz ;
2014-03-16 09:10:34 +04:00
unsigned long flags = pdev - > id_entry - > driver_data ;
2011-05-20 10:40:19 +04:00
int err ;
struct bgpio_chip * bgc ;
struct bgpio_pdata * pdata = dev_get_platdata ( dev ) ;
r = platform_get_resource_byname ( pdev , IORESOURCE_MEM , " dat " ) ;
if ( ! r )
return - EINVAL ;
sz = resource_size ( r ) ;
2015-10-01 00:52:36 +03:00
dat = bgpio_map ( pdev , " dat " , sz ) ;
if ( IS_ERR ( dat ) )
return PTR_ERR ( dat ) ;
2011-05-20 10:40:19 +04:00
2015-10-01 00:52:36 +03:00
set = bgpio_map ( pdev , " set " , sz ) ;
if ( IS_ERR ( set ) )
return PTR_ERR ( set ) ;
2011-05-20 10:40:19 +04:00
2015-10-01 00:52:36 +03:00
clr = bgpio_map ( pdev , " clr " , sz ) ;
if ( IS_ERR ( clr ) )
return PTR_ERR ( clr ) ;
2011-05-20 10:40:19 +04:00
2015-10-01 00:52:36 +03:00
dirout = bgpio_map ( pdev , " dirout " , sz ) ;
if ( IS_ERR ( dirout ) )
return PTR_ERR ( dirout ) ;
2011-05-20 10:40:19 +04:00
2015-10-01 00:52:36 +03:00
dirin = bgpio_map ( pdev , " dirin " , sz ) ;
if ( IS_ERR ( dirin ) )
return PTR_ERR ( dirin ) ;
2011-05-20 10:40:19 +04:00
bgc = devm_kzalloc ( & pdev - > dev , sizeof ( * bgc ) , GFP_KERNEL ) ;
if ( ! bgc )
return - ENOMEM ;
2012-05-19 17:34:58 +04:00
err = bgpio_init ( bgc , dev , sz , dat , set , clr , dirout , dirin , flags ) ;
2011-05-20 10:40:19 +04:00
if ( err )
return err ;
if ( pdata ) {
2014-01-30 17:18:57 +04:00
if ( pdata - > label )
bgc - > gc . label = pdata - > label ;
2011-05-20 10:40:19 +04:00
bgc - > gc . base = pdata - > base ;
if ( pdata - > ngpio > 0 )
bgc - > gc . ngpio = pdata - > ngpio ;
}
platform_set_drvdata ( pdev , bgc ) ;
return gpiochip_add ( & bgc - > gc ) ;
}
2012-11-19 22:25:50 +04:00
static int bgpio_pdev_remove ( struct platform_device * pdev )
2010-10-28 02:33:15 +04:00
{
2011-05-20 10:40:14 +04:00
struct bgpio_chip * bgc = platform_get_drvdata ( pdev ) ;
2010-10-28 02:33:15 +04:00
2011-05-20 10:40:19 +04:00
return bgpio_remove ( bgc ) ;
2010-10-28 02:33:15 +04:00
}
static const struct platform_device_id bgpio_id_table [ ] = {
2014-03-16 09:10:34 +04:00
{
. name = " basic-mmio-gpio " ,
. driver_data = 0 ,
} , {
. name = " basic-mmio-gpio-be " ,
. driver_data = BGPIOF_BIG_ENDIAN ,
} ,
{ }
2010-10-28 02:33:15 +04:00
} ;
MODULE_DEVICE_TABLE ( platform , bgpio_id_table ) ;
static struct platform_driver bgpio_driver = {
. driver = {
. name = " basic-mmio-gpio " ,
} ,
. id_table = bgpio_id_table ,
2011-05-20 10:40:19 +04:00
. probe = bgpio_pdev_probe ,
2012-11-19 22:20:08 +04:00
. remove = bgpio_pdev_remove ,
2010-10-28 02:33:15 +04:00
} ;
2011-12-07 20:24:00 +04:00
module_platform_driver ( bgpio_driver ) ;
2011-05-20 10:40:19 +04:00
2011-06-05 04:38:28 +04:00
# endif /* CONFIG_GPIO_GENERIC_PLATFORM */
2010-10-28 02:33:15 +04:00
MODULE_DESCRIPTION ( " Driver for basic memory-mapped GPIO controllers " ) ;
MODULE_AUTHOR ( " Anton Vorontsov <cbouatmailru@gmail.com> " ) ;
MODULE_LICENSE ( " GPL " ) ;