2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2015-10-19 19:59:14 +03:00
/*
* GPIO driver for the ACCES 104 - IDIO - 16 family
* Copyright ( C ) 2015 William Breathitt Gray
*
2016-05-02 01:45:11 +03:00
* This driver supports the following ACCES devices : 104 - IDIO - 16 ,
* 104 - IDIO - 16 E , 104 - IDO - 16 , 104 - IDIO - 8 , 104 - IDIO - 8 E , and 104 - IDO - 8.
2015-10-19 19:59:14 +03:00
*/
2022-10-25 10:57:57 +03:00
# include <linux/bitmap.h>
2015-10-19 19:59:14 +03:00
# include <linux/device.h>
# include <linux/errno.h>
# include <linux/gpio/driver.h>
# include <linux/io.h>
# include <linux/ioport.h>
2015-11-03 15:54:23 +03:00
# include <linux/interrupt.h>
# include <linux/irqdesc.h>
2016-05-02 01:45:11 +03:00
# include <linux/isa.h>
2015-10-19 19:59:14 +03:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/spinlock.h>
2022-07-20 16:45:58 +03:00
# include <linux/types.h>
2015-10-19 19:59:14 +03:00
2022-10-25 10:57:57 +03:00
# include "gpio-idio-16.h"
2016-05-02 01:45:11 +03:00
# define IDIO_16_EXTENT 8
# define MAX_NUM_IDIO_16 max_num_isa_dev(IDIO_16_EXTENT)
static unsigned int base [ MAX_NUM_IDIO_16 ] ;
static unsigned int num_idio_16 ;
2017-04-04 18:54:22 +03:00
module_param_hw_array ( base , uint , ioport , & num_idio_16 , 0 ) ;
2016-05-02 01:45:11 +03:00
MODULE_PARM_DESC ( base , " ACCES 104-IDIO-16 base addresses " ) ;
static unsigned int irq [ MAX_NUM_IDIO_16 ] ;
2022-08-18 19:28:14 +03:00
static unsigned int num_irq ;
module_param_hw_array ( irq , uint , irq , & num_irq , 0 ) ;
2016-05-02 01:45:11 +03:00
MODULE_PARM_DESC ( irq , " ACCES 104-IDIO-16 interrupt line numbers " ) ;
2015-10-19 19:59:14 +03:00
/**
* struct idio_16_gpio - GPIO device private data structure
* @ chip : instance of the gpio_chip
2015-11-03 15:54:23 +03:00
* @ lock : synchronization lock to prevent I / O race conditions
* @ irq_mask : I / O bits affected by interrupts
2022-07-20 16:45:58 +03:00
* @ reg : I / O address offset for the device registers
2022-10-25 10:57:57 +03:00
* @ state : ACCES IDIO - 16 device state
2015-10-19 19:59:14 +03:00
*/
struct idio_16_gpio {
struct gpio_chip chip ;
2017-03-22 01:43:08 +03:00
raw_spinlock_t lock ;
2015-11-03 15:54:23 +03:00
unsigned long irq_mask ;
2022-10-25 10:57:57 +03:00
struct idio_16 __iomem * reg ;
struct idio_16_state state ;
2015-10-19 19:59:14 +03:00
} ;
2021-05-25 07:57:17 +03:00
static int idio_16_gpio_get_direction ( struct gpio_chip * chip ,
unsigned int offset )
2015-10-19 19:59:14 +03:00
{
2022-10-25 10:57:57 +03:00
if ( idio_16_get_direction ( offset ) )
2019-11-06 11:54:12 +03:00
return GPIO_LINE_DIRECTION_IN ;
2015-10-19 19:59:14 +03:00
2019-11-06 11:54:12 +03:00
return GPIO_LINE_DIRECTION_OUT ;
2015-10-19 19:59:14 +03:00
}
2021-05-25 07:57:17 +03:00
static int idio_16_gpio_direction_input ( struct gpio_chip * chip ,
unsigned int offset )
2015-10-19 19:59:14 +03:00
{
return 0 ;
}
static int idio_16_gpio_direction_output ( struct gpio_chip * chip ,
2021-05-25 07:57:17 +03:00
unsigned int offset , int value )
2015-10-19 19:59:14 +03:00
{
chip - > set ( chip , offset , value ) ;
return 0 ;
}
2021-05-25 07:57:17 +03:00
static int idio_16_gpio_get ( struct gpio_chip * chip , unsigned int offset )
2015-10-19 19:59:14 +03:00
{
2015-12-03 20:18:06 +03:00
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2015-10-19 19:59:14 +03:00
2022-10-25 10:57:57 +03:00
return idio_16_get ( idio16gpio - > reg , & idio16gpio - > state , offset ) ;
2015-10-19 19:59:14 +03:00
}
2018-03-22 15:59:37 +03:00
static int idio_16_gpio_get_multiple ( struct gpio_chip * chip ,
unsigned long * mask , unsigned long * bits )
{
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2022-10-25 10:57:57 +03:00
idio_16_get_multiple ( idio16gpio - > reg , & idio16gpio - > state , mask , bits ) ;
2018-03-22 15:59:37 +03:00
return 0 ;
}
2021-05-25 07:57:17 +03:00
static void idio_16_gpio_set ( struct gpio_chip * chip , unsigned int offset ,
int value )
2015-10-19 19:59:14 +03:00
{
2015-12-03 20:18:06 +03:00
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2015-10-19 19:59:14 +03:00
2022-10-25 10:57:57 +03:00
idio_16_set ( idio16gpio - > reg , & idio16gpio - > state , offset , value ) ;
2015-10-19 19:59:14 +03:00
}
2017-01-19 18:05:37 +03:00
static void idio_16_gpio_set_multiple ( struct gpio_chip * chip ,
unsigned long * mask , unsigned long * bits )
{
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2022-10-25 10:57:57 +03:00
idio_16_set_multiple ( idio16gpio - > reg , & idio16gpio - > state , mask , bits ) ;
2017-01-19 18:05:37 +03:00
}
2015-11-03 15:54:23 +03:00
static void idio_16_irq_ack ( struct irq_data * data )
{
}
static void idio_16_irq_mask ( struct irq_data * data )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( data ) ;
2015-12-03 20:18:06 +03:00
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2022-09-02 20:45:25 +03:00
const unsigned long offset = irqd_to_hwirq ( data ) ;
2015-11-03 15:54:23 +03:00
unsigned long flags ;
2022-09-02 20:45:25 +03:00
idio16gpio - > irq_mask & = ~ BIT ( offset ) ;
gpiochip_disable_irq ( chip , offset ) ;
2015-11-03 15:54:23 +03:00
if ( ! idio16gpio - > irq_mask ) {
2017-03-22 01:43:08 +03:00
raw_spin_lock_irqsave ( & idio16gpio - > lock , flags ) ;
2015-11-03 15:54:23 +03:00
2022-07-20 16:45:58 +03:00
iowrite8 ( 0 , & idio16gpio - > reg - > irq_ctl ) ;
2015-11-03 15:54:23 +03:00
2017-03-22 01:43:08 +03:00
raw_spin_unlock_irqrestore ( & idio16gpio - > lock , flags ) ;
2015-11-03 15:54:23 +03:00
}
}
static void idio_16_irq_unmask ( struct irq_data * data )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( data ) ;
2015-12-03 20:18:06 +03:00
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( chip ) ;
2022-09-02 20:45:25 +03:00
const unsigned long offset = irqd_to_hwirq ( data ) ;
2015-11-03 15:54:23 +03:00
const unsigned long prev_irq_mask = idio16gpio - > irq_mask ;
unsigned long flags ;
2022-09-02 20:45:25 +03:00
gpiochip_enable_irq ( chip , offset ) ;
idio16gpio - > irq_mask | = BIT ( offset ) ;
2015-11-03 15:54:23 +03:00
if ( ! prev_irq_mask ) {
2017-03-22 01:43:08 +03:00
raw_spin_lock_irqsave ( & idio16gpio - > lock , flags ) ;
2015-11-03 15:54:23 +03:00
2022-07-20 16:45:58 +03:00
ioread8 ( & idio16gpio - > reg - > irq_ctl ) ;
2015-11-03 15:54:23 +03:00
2017-03-22 01:43:08 +03:00
raw_spin_unlock_irqrestore ( & idio16gpio - > lock , flags ) ;
2015-11-03 15:54:23 +03:00
}
}
2021-05-25 07:57:17 +03:00
static int idio_16_irq_set_type ( struct irq_data * data , unsigned int flow_type )
2015-11-03 15:54:23 +03:00
{
/* The only valid irq types are none and both-edges */
if ( flow_type ! = IRQ_TYPE_NONE & &
( flow_type & IRQ_TYPE_EDGE_BOTH ) ! = IRQ_TYPE_EDGE_BOTH )
return - EINVAL ;
return 0 ;
}
2022-09-02 20:45:25 +03:00
static const struct irq_chip idio_16_irqchip = {
2015-11-03 15:54:23 +03:00
. name = " 104-idio-16 " ,
. irq_ack = idio_16_irq_ack ,
. irq_mask = idio_16_irq_mask ,
. irq_unmask = idio_16_irq_unmask ,
2022-09-02 20:45:25 +03:00
. irq_set_type = idio_16_irq_set_type ,
. flags = IRQCHIP_IMMUTABLE ,
GPIOCHIP_IRQ_RESOURCE_HELPERS ,
2015-11-03 15:54:23 +03:00
} ;
static irqreturn_t idio_16_irq_handler ( int irq , void * dev_id )
{
struct idio_16_gpio * const idio16gpio = dev_id ;
struct gpio_chip * const chip = & idio16gpio - > chip ;
int gpio ;
for_each_set_bit ( gpio , & idio16gpio - > irq_mask , chip - > ngpio )
2021-05-04 19:42:18 +03:00
generic_handle_domain_irq ( chip - > irq . domain , gpio ) ;
2015-11-03 15:54:23 +03:00
2017-03-22 01:43:08 +03:00
raw_spin_lock ( & idio16gpio - > lock ) ;
2015-12-03 04:23:04 +03:00
2022-07-20 16:45:58 +03:00
iowrite8 ( 0 , & idio16gpio - > reg - > in0_7 ) ;
2015-12-03 04:23:04 +03:00
2017-03-22 01:43:08 +03:00
raw_spin_unlock ( & idio16gpio - > lock ) ;
2015-12-03 04:23:04 +03:00
2015-11-03 15:54:23 +03:00
return IRQ_HANDLED ;
}
2017-01-30 21:33:21 +03:00
# define IDIO_16_NGPIO 32
static const char * idio_16_names [ IDIO_16_NGPIO ] = {
" OUT0 " , " OUT1 " , " OUT2 " , " OUT3 " , " OUT4 " , " OUT5 " , " OUT6 " , " OUT7 " ,
" OUT8 " , " OUT9 " , " OUT10 " , " OUT11 " , " OUT12 " , " OUT13 " , " OUT14 " , " OUT15 " ,
" IIN0 " , " IIN1 " , " IIN2 " , " IIN3 " , " IIN4 " , " IIN5 " , " IIN6 " , " IIN7 " ,
" IIN8 " , " IIN9 " , " IIN10 " , " IIN11 " , " IIN12 " , " IIN13 " , " IIN14 " , " IIN15 "
} ;
2020-07-22 13:55:17 +03:00
static int idio_16_irq_init_hw ( struct gpio_chip * gc )
{
struct idio_16_gpio * const idio16gpio = gpiochip_get_data ( gc ) ;
/* Disable IRQ by default */
2022-07-20 16:45:58 +03:00
iowrite8 ( 0 , & idio16gpio - > reg - > irq_ctl ) ;
iowrite8 ( 0 , & idio16gpio - > reg - > in0_7 ) ;
2020-07-22 13:55:17 +03:00
return 0 ;
}
2016-05-02 01:45:11 +03:00
static int idio_16_probe ( struct device * dev , unsigned int id )
2015-10-19 19:59:14 +03:00
{
struct idio_16_gpio * idio16gpio ;
2015-11-18 02:58:16 +03:00
const char * const name = dev_name ( dev ) ;
2020-07-22 13:55:17 +03:00
struct gpio_irq_chip * girq ;
2015-10-19 19:59:14 +03:00
int err ;
idio16gpio = devm_kzalloc ( dev , sizeof ( * idio16gpio ) , GFP_KERNEL ) ;
if ( ! idio16gpio )
return - ENOMEM ;
2016-05-02 01:45:11 +03:00
if ( ! devm_request_region ( dev , base [ id ] , IDIO_16_EXTENT , name ) ) {
2016-02-03 23:17:02 +03:00
dev_err ( dev , " Unable to lock port addresses (0x%X-0x%X) \n " ,
2016-05-02 01:45:11 +03:00
base [ id ] , base [ id ] + IDIO_16_EXTENT ) ;
2016-02-03 23:17:02 +03:00
return - EBUSY ;
2015-10-19 19:59:14 +03:00
}
2022-07-20 16:45:58 +03:00
idio16gpio - > reg = devm_ioport_map ( dev , base [ id ] , IDIO_16_EXTENT ) ;
if ( ! idio16gpio - > reg )
2022-05-10 20:30:56 +03:00
return - ENOMEM ;
2015-11-18 02:58:16 +03:00
idio16gpio - > chip . label = name ;
2015-11-04 11:56:26 +03:00
idio16gpio - > chip . parent = dev ;
2015-10-19 19:59:14 +03:00
idio16gpio - > chip . owner = THIS_MODULE ;
idio16gpio - > chip . base = - 1 ;
2017-01-30 21:33:21 +03:00
idio16gpio - > chip . ngpio = IDIO_16_NGPIO ;
idio16gpio - > chip . names = idio_16_names ;
2015-10-19 19:59:14 +03:00
idio16gpio - > chip . get_direction = idio_16_gpio_get_direction ;
idio16gpio - > chip . direction_input = idio_16_gpio_direction_input ;
idio16gpio - > chip . direction_output = idio_16_gpio_direction_output ;
idio16gpio - > chip . get = idio_16_gpio_get ;
2018-03-22 15:59:37 +03:00
idio16gpio - > chip . get_multiple = idio_16_gpio_get_multiple ;
2015-10-19 19:59:14 +03:00
idio16gpio - > chip . set = idio_16_gpio_set ;
2017-01-19 18:05:37 +03:00
idio16gpio - > chip . set_multiple = idio_16_gpio_set_multiple ;
2022-10-25 10:57:57 +03:00
idio_16_state_init ( & idio16gpio - > state ) ;
/* FET off states are represented by bit values of "1" */
bitmap_fill ( idio16gpio - > state . out_state , IDIO_16_NOUT ) ;
2015-10-19 19:59:14 +03:00
2020-07-22 13:55:17 +03:00
girq = & idio16gpio - > chip . irq ;
2022-09-02 20:45:25 +03:00
gpio_irq_chip_set_chip ( girq , & idio_16_irqchip ) ;
2020-07-22 13:55:17 +03:00
/* This will let us handle the parent IRQ in the driver */
girq - > parent_handler = NULL ;
girq - > num_parents = 0 ;
girq - > parents = NULL ;
girq - > default_type = IRQ_TYPE_NONE ;
girq - > handler = handle_edge_irq ;
girq - > init_hw = idio_16_irq_init_hw ;
2017-03-22 01:43:08 +03:00
raw_spin_lock_init ( & idio16gpio - > lock ) ;
2015-10-19 19:59:14 +03:00
2017-01-24 23:00:54 +03:00
err = devm_gpiochip_add_data ( dev , & idio16gpio - > chip , idio16gpio ) ;
2015-10-19 19:59:14 +03:00
if ( err ) {
dev_err ( dev , " GPIO registering failed (%d) \n " , err ) ;
2016-02-03 23:17:02 +03:00
return err ;
2015-10-19 19:59:14 +03:00
}
2017-01-24 23:00:54 +03:00
err = devm_request_irq ( dev , irq [ id ] , idio_16_irq_handler , 0 , name ,
idio16gpio ) ;
2015-11-03 15:54:23 +03:00
if ( err ) {
dev_err ( dev , " IRQ handler registering failed (%d) \n " , err ) ;
2017-01-24 23:00:54 +03:00
return err ;
2015-11-03 15:54:23 +03:00
}
2015-10-19 19:59:14 +03:00
return 0 ;
}
2016-05-02 01:45:11 +03:00
static struct isa_driver idio_16_driver = {
. probe = idio_16_probe ,
2015-10-19 19:59:14 +03:00
. driver = {
. name = " 104-idio-16 "
} ,
} ;
2022-08-18 19:28:14 +03:00
module_isa_driver_with_irq ( idio_16_driver , num_idio_16 , num_irq ) ;
2015-10-19 19:59:14 +03:00
MODULE_AUTHOR ( " William Breathitt Gray <vilhelm.gray@gmail.com> " ) ;
MODULE_DESCRIPTION ( " ACCES 104-IDIO-16 GPIO driver " ) ;
2016-02-02 02:51:49 +03:00
MODULE_LICENSE ( " GPL v2 " ) ;
2022-10-25 10:57:57 +03:00
MODULE_IMPORT_NS ( GPIO_IDIO_16 ) ;