2019-05-27 08:55:21 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2016-01-20 13:50:11 -05:00
/*
2016-05-01 18:44:39 -04:00
* GPIO driver for the ACCES 104 - DIO - 48 E series
2016-01-20 13:50:11 -05:00
* Copyright ( C ) 2016 William Breathitt Gray
*
2016-05-01 18:44:39 -04:00
* This driver supports the following ACCES devices : 104 - DIO - 48 E and
* 104 - DIO - 24 E .
2016-01-20 13:50:11 -05:00
*/
2022-07-20 09:46:00 -04:00
# include <linux/bits.h>
2016-01-20 13:50:11 -05:00
# include <linux/device.h>
# include <linux/errno.h>
# include <linux/gpio/driver.h>
# include <linux/io.h>
# include <linux/ioport.h>
# include <linux/interrupt.h>
# include <linux/irqdesc.h>
2016-05-01 18:44:39 -04:00
# include <linux/isa.h>
2016-01-20 13:50:11 -05:00
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/spinlock.h>
2022-07-20 09:46:00 -04:00
# include <linux/types.h>
# include "gpio-i8255.h"
MODULE_IMPORT_NS ( I8255 ) ;
2016-01-20 13:50:11 -05:00
2016-05-01 18:44:39 -04:00
# define DIO48E_EXTENT 16
# define MAX_NUM_DIO48E max_num_isa_dev(DIO48E_EXTENT)
static unsigned int base [ MAX_NUM_DIO48E ] ;
static unsigned int num_dio48e ;
2017-04-04 16:54:22 +01:00
module_param_hw_array ( base , uint , ioport , & num_dio48e , 0 ) ;
2016-05-01 18:44:39 -04:00
MODULE_PARM_DESC ( base , " ACCES 104-DIO-48E base addresses " ) ;
static unsigned int irq [ MAX_NUM_DIO48E ] ;
2017-04-04 16:54:22 +01:00
module_param_hw_array ( irq , uint , irq , NULL , 0 ) ;
2016-05-01 18:44:39 -04:00
MODULE_PARM_DESC ( irq , " ACCES 104-DIO-48E interrupt line numbers " ) ;
2016-01-20 13:50:11 -05:00
2022-07-20 09:46:00 -04:00
# define DIO48E_NUM_PPI 2
/**
* struct dio48e_reg - device register structure
* @ ppi : Programmable Peripheral Interface groups
* @ enable_buffer : Enable / Disable Buffer groups
* @ unused1 : Unused
* @ enable_interrupt : Write : Enable Interrupt
* Read : Disable Interrupt
* @ unused2 : Unused
* @ enable_counter : Write : Enable Counter / Timer Addressing
* Read : Disable Counter / Timer Addressing
* @ unused3 : Unused
* @ clear_interrupt : Clear Interrupt
*/
struct dio48e_reg {
struct i8255 ppi [ DIO48E_NUM_PPI ] ;
u8 enable_buffer [ DIO48E_NUM_PPI ] ;
u8 unused1 ;
u8 enable_interrupt ;
u8 unused2 ;
u8 enable_counter ;
u8 unused3 ;
u8 clear_interrupt ;
} ;
2016-01-20 13:50:11 -05:00
/**
* struct dio48e_gpio - GPIO device private data structure
2022-07-20 09:46:00 -04:00
* @ chip : instance of the gpio_chip
* @ ppi_state : PPI device states
* @ lock : synchronization lock to prevent I / O race conditions
* @ reg : I / O address offset for the device registers
* @ irq_mask : I / O bits affected by interrupts
2016-01-20 13:50:11 -05:00
*/
struct dio48e_gpio {
struct gpio_chip chip ;
2022-07-20 09:46:00 -04:00
struct i8255_state ppi_state [ DIO48E_NUM_PPI ] ;
2017-03-09 10:21:52 -06:00
raw_spinlock_t lock ;
2022-07-20 09:46:00 -04:00
struct dio48e_reg __iomem * reg ;
2016-01-20 13:50:11 -05:00
unsigned char irq_mask ;
} ;
2021-04-08 10:53:34 -05:00
static int dio48e_gpio_get_direction ( struct gpio_chip * chip , unsigned int offset )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
if ( i8255_get_direction ( dio48egpio - > ppi_state , offset ) )
return GPIO_LINE_DIRECTION_IN ;
2019-11-06 10:54:12 +02:00
return GPIO_LINE_DIRECTION_OUT ;
2016-01-20 13:50:11 -05:00
}
2021-04-08 10:53:34 -05:00
static int dio48e_gpio_direction_input ( struct gpio_chip * chip , unsigned int offset )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
i8255_direction_input ( dio48egpio - > reg - > ppi , dio48egpio - > ppi_state ,
offset ) ;
2016-01-20 13:50:11 -05:00
return 0 ;
}
2021-04-08 10:53:34 -05:00
static int dio48e_gpio_direction_output ( struct gpio_chip * chip , unsigned int offset ,
int value )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
i8255_direction_output ( dio48egpio - > reg - > ppi , dio48egpio - > ppi_state ,
offset , value ) ;
2016-01-20 13:50:11 -05:00
return 0 ;
}
2021-04-08 10:53:34 -05:00
static int dio48e_gpio_get ( struct gpio_chip * chip , unsigned int offset )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
return i8255_get ( dio48egpio - > reg - > ppi , offset ) ;
2016-01-20 13:50:11 -05:00
}
2018-03-22 09:00:11 -04:00
static int dio48e_gpio_get_multiple ( struct gpio_chip * chip , unsigned long * mask ,
unsigned long * bits )
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
i8255_get_multiple ( dio48egpio - > reg - > ppi , mask , bits , chip - > ngpio ) ;
2018-03-22 09:00:11 -04:00
return 0 ;
}
2021-04-08 10:53:34 -05:00
static void dio48e_gpio_set ( struct gpio_chip * chip , unsigned int offset , int value )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
i8255_set ( dio48egpio - > reg - > ppi , dio48egpio - > ppi_state , offset , value ) ;
2016-01-20 13:50:11 -05:00
}
2017-01-19 10:05:27 -05:00
static void dio48e_gpio_set_multiple ( struct gpio_chip * chip ,
unsigned long * mask , unsigned long * bits )
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
2022-07-20 09:46:00 -04:00
i8255_set_multiple ( dio48egpio - > reg - > ppi , dio48egpio - > ppi_state , mask ,
bits , chip - > ngpio ) ;
2017-01-19 10:05:27 -05:00
}
2016-01-20 13:50:11 -05:00
static void dio48e_irq_ack ( struct irq_data * data )
{
}
static void dio48e_irq_mask ( struct irq_data * data )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( data ) ;
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
const unsigned long offset = irqd_to_hwirq ( data ) ;
unsigned long flags ;
/* only bit 3 on each respective Port C supports interrupts */
if ( offset ! = 19 & & offset ! = 43 )
return ;
2017-03-09 10:21:52 -06:00
raw_spin_lock_irqsave ( & dio48egpio - > lock , flags ) ;
2016-01-20 13:50:11 -05:00
if ( offset = = 19 )
dio48egpio - > irq_mask & = ~ BIT ( 0 ) ;
else
dio48egpio - > irq_mask & = ~ BIT ( 1 ) ;
2022-09-02 13:45:23 -04:00
gpiochip_disable_irq ( chip , offset ) ;
2016-01-20 13:50:11 -05:00
if ( ! dio48egpio - > irq_mask )
/* disable interrupts */
2022-07-20 09:46:00 -04:00
ioread8 ( & dio48egpio - > reg - > enable_interrupt ) ;
2016-01-20 13:50:11 -05:00
2017-03-09 10:21:52 -06:00
raw_spin_unlock_irqrestore ( & dio48egpio - > lock , flags ) ;
2016-01-20 13:50:11 -05:00
}
static void dio48e_irq_unmask ( struct irq_data * data )
{
struct gpio_chip * chip = irq_data_get_irq_chip_data ( data ) ;
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( chip ) ;
const unsigned long offset = irqd_to_hwirq ( data ) ;
unsigned long flags ;
/* only bit 3 on each respective Port C supports interrupts */
if ( offset ! = 19 & & offset ! = 43 )
return ;
2017-03-09 10:21:52 -06:00
raw_spin_lock_irqsave ( & dio48egpio - > lock , flags ) ;
2016-01-20 13:50:11 -05:00
if ( ! dio48egpio - > irq_mask ) {
/* enable interrupts */
2022-07-20 09:46:00 -04:00
iowrite8 ( 0x00 , & dio48egpio - > reg - > clear_interrupt ) ;
iowrite8 ( 0x00 , & dio48egpio - > reg - > enable_interrupt ) ;
2016-01-20 13:50:11 -05:00
}
2022-09-02 13:45:23 -04:00
gpiochip_enable_irq ( chip , offset ) ;
2016-01-20 13:50:11 -05:00
if ( offset = = 19 )
dio48egpio - > irq_mask | = BIT ( 0 ) ;
else
dio48egpio - > irq_mask | = BIT ( 1 ) ;
2017-03-09 10:21:52 -06:00
raw_spin_unlock_irqrestore ( & dio48egpio - > lock , flags ) ;
2016-01-20 13:50:11 -05:00
}
2021-04-08 10:53:34 -05:00
static int dio48e_irq_set_type ( struct irq_data * data , unsigned int flow_type )
2016-01-20 13:50:11 -05:00
{
const unsigned long offset = irqd_to_hwirq ( data ) ;
/* only bit 3 on each respective Port C supports interrupts */
if ( offset ! = 19 & & offset ! = 43 )
return - EINVAL ;
if ( flow_type ! = IRQ_TYPE_NONE & & flow_type ! = IRQ_TYPE_EDGE_RISING )
return - EINVAL ;
return 0 ;
}
2022-09-02 13:45:23 -04:00
static const struct irq_chip dio48e_irqchip = {
2016-01-20 13:50:11 -05:00
. name = " 104-dio-48e " ,
. irq_ack = dio48e_irq_ack ,
. irq_mask = dio48e_irq_mask ,
. irq_unmask = dio48e_irq_unmask ,
2022-09-02 13:45:23 -04:00
. irq_set_type = dio48e_irq_set_type ,
. flags = IRQCHIP_IMMUTABLE ,
GPIOCHIP_IRQ_RESOURCE_HELPERS ,
2016-01-20 13:50:11 -05:00
} ;
static irqreturn_t dio48e_irq_handler ( int irq , void * dev_id )
{
struct dio48e_gpio * const dio48egpio = dev_id ;
struct gpio_chip * const chip = & dio48egpio - > chip ;
const unsigned long irq_mask = dio48egpio - > irq_mask ;
unsigned long gpio ;
for_each_set_bit ( gpio , & irq_mask , 2 )
2021-05-04 17:42:18 +01:00
generic_handle_domain_irq ( chip - > irq . domain ,
19 + gpio * 24 ) ;
2016-01-20 13:50:11 -05:00
2017-03-09 10:21:52 -06:00
raw_spin_lock ( & dio48egpio - > lock ) ;
2016-01-20 13:50:11 -05:00
2022-07-20 09:46:00 -04:00
iowrite8 ( 0x00 , & dio48egpio - > reg - > clear_interrupt ) ;
2016-01-20 13:50:11 -05:00
2017-03-09 10:21:52 -06:00
raw_spin_unlock ( & dio48egpio - > lock ) ;
2016-01-20 13:50:11 -05:00
return IRQ_HANDLED ;
}
2017-01-30 13:32:58 -05:00
# define DIO48E_NGPIO 48
static const char * dio48e_names [ DIO48E_NGPIO ] = {
" PPI Group 0 Port A 0 " , " PPI Group 0 Port A 1 " , " PPI Group 0 Port A 2 " ,
" PPI Group 0 Port A 3 " , " PPI Group 0 Port A 4 " , " PPI Group 0 Port A 5 " ,
" PPI Group 0 Port A 6 " , " PPI Group 0 Port A 7 " , " PPI Group 0 Port B 0 " ,
" PPI Group 0 Port B 1 " , " PPI Group 0 Port B 2 " , " PPI Group 0 Port B 3 " ,
" PPI Group 0 Port B 4 " , " PPI Group 0 Port B 5 " , " PPI Group 0 Port B 6 " ,
" PPI Group 0 Port B 7 " , " PPI Group 0 Port C 0 " , " PPI Group 0 Port C 1 " ,
" PPI Group 0 Port C 2 " , " PPI Group 0 Port C 3 " , " PPI Group 0 Port C 4 " ,
" PPI Group 0 Port C 5 " , " PPI Group 0 Port C 6 " , " PPI Group 0 Port C 7 " ,
" PPI Group 1 Port A 0 " , " PPI Group 1 Port A 1 " , " PPI Group 1 Port A 2 " ,
" PPI Group 1 Port A 3 " , " PPI Group 1 Port A 4 " , " PPI Group 1 Port A 5 " ,
" PPI Group 1 Port A 6 " , " PPI Group 1 Port A 7 " , " PPI Group 1 Port B 0 " ,
" PPI Group 1 Port B 1 " , " PPI Group 1 Port B 2 " , " PPI Group 1 Port B 3 " ,
" PPI Group 1 Port B 4 " , " PPI Group 1 Port B 5 " , " PPI Group 1 Port B 6 " ,
" PPI Group 1 Port B 7 " , " PPI Group 1 Port C 0 " , " PPI Group 1 Port C 1 " ,
" PPI Group 1 Port C 2 " , " PPI Group 1 Port C 3 " , " PPI Group 1 Port C 4 " ,
" PPI Group 1 Port C 5 " , " PPI Group 1 Port C 6 " , " PPI Group 1 Port C 7 "
} ;
2020-07-22 12:39:15 +02:00
static int dio48e_irq_init_hw ( struct gpio_chip * gc )
{
struct dio48e_gpio * const dio48egpio = gpiochip_get_data ( gc ) ;
/* Disable IRQ by default */
2022-07-20 09:46:00 -04:00
ioread8 ( & dio48egpio - > reg - > enable_interrupt ) ;
2020-07-22 12:39:15 +02:00
return 0 ;
}
2022-07-20 09:46:00 -04:00
static void dio48e_init_ppi ( struct i8255 __iomem * const ppi ,
struct i8255_state * const ppi_state )
{
const unsigned long ngpio = 24 ;
const unsigned long mask = GENMASK ( ngpio - 1 , 0 ) ;
const unsigned long bits = 0 ;
unsigned long i ;
/* Initialize all GPIO to output 0 */
for ( i = 0 ; i < DIO48E_NUM_PPI ; i + + ) {
i8255_mode0_output ( & ppi [ i ] ) ;
i8255_set_multiple ( & ppi [ i ] , & ppi_state [ i ] , & mask , & bits , ngpio ) ;
}
}
2016-05-01 18:44:39 -04:00
static int dio48e_probe ( struct device * dev , unsigned int id )
2016-01-20 13:50:11 -05:00
{
struct dio48e_gpio * dio48egpio ;
const char * const name = dev_name ( dev ) ;
2020-07-22 12:39:15 +02:00
struct gpio_irq_chip * girq ;
2016-01-20 13:50:11 -05:00
int err ;
dio48egpio = devm_kzalloc ( dev , sizeof ( * dio48egpio ) , GFP_KERNEL ) ;
if ( ! dio48egpio )
return - ENOMEM ;
2016-05-01 18:44:39 -04:00
if ( ! devm_request_region ( dev , base [ id ] , DIO48E_EXTENT , name ) ) {
2016-02-03 15:15:21 -05:00
dev_err ( dev , " Unable to lock port addresses (0x%X-0x%X) \n " ,
2016-05-01 18:44:39 -04:00
base [ id ] , base [ id ] + DIO48E_EXTENT ) ;
2016-02-03 15:15:21 -05:00
return - EBUSY ;
2016-01-20 13:50:11 -05:00
}
2022-07-20 09:46:00 -04:00
dio48egpio - > reg = devm_ioport_map ( dev , base [ id ] , DIO48E_EXTENT ) ;
if ( ! dio48egpio - > reg )
2022-05-10 13:30:54 -04:00
return - ENOMEM ;
2016-01-20 13:50:11 -05:00
dio48egpio - > chip . label = name ;
dio48egpio - > chip . parent = dev ;
dio48egpio - > chip . owner = THIS_MODULE ;
dio48egpio - > chip . base = - 1 ;
2017-01-30 13:32:58 -05:00
dio48egpio - > chip . ngpio = DIO48E_NGPIO ;
dio48egpio - > chip . names = dio48e_names ;
2016-01-20 13:50:11 -05:00
dio48egpio - > chip . get_direction = dio48e_gpio_get_direction ;
dio48egpio - > chip . direction_input = dio48e_gpio_direction_input ;
dio48egpio - > chip . direction_output = dio48e_gpio_direction_output ;
dio48egpio - > chip . get = dio48e_gpio_get ;
2018-03-22 09:00:11 -04:00
dio48egpio - > chip . get_multiple = dio48e_gpio_get_multiple ;
2016-01-20 13:50:11 -05:00
dio48egpio - > chip . set = dio48e_gpio_set ;
2017-01-19 10:05:27 -05:00
dio48egpio - > chip . set_multiple = dio48e_gpio_set_multiple ;
2016-01-20 13:50:11 -05:00
2020-07-22 12:39:15 +02:00
girq = & dio48egpio - > chip . irq ;
2022-09-02 13:45:23 -04:00
gpio_irq_chip_set_chip ( girq , & dio48e_irqchip ) ;
2020-07-22 12:39:15 +02: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 = dio48e_irq_init_hw ;
2016-01-20 13:50:11 -05:00
2020-07-22 12:39:15 +02:00
raw_spin_lock_init ( & dio48egpio - > lock ) ;
2016-01-20 13:50:11 -05:00
2022-07-20 09:46:00 -04:00
i8255_state_init ( dio48egpio - > ppi_state , DIO48E_NUM_PPI ) ;
dio48e_init_ppi ( dio48egpio - > reg - > ppi , dio48egpio - > ppi_state ) ;
2016-01-20 13:50:11 -05:00
2020-07-22 12:39:15 +02:00
err = devm_gpiochip_add_data ( dev , & dio48egpio - > chip , dio48egpio ) ;
2016-01-20 13:50:11 -05:00
if ( err ) {
2020-07-22 12:39:15 +02:00
dev_err ( dev , " GPIO registering failed (%d) \n " , err ) ;
2017-01-24 15:00:31 -05:00
return err ;
2016-01-20 13:50:11 -05:00
}
2017-01-24 15:00:31 -05:00
err = devm_request_irq ( dev , irq [ id ] , dio48e_irq_handler , 0 , name ,
dio48egpio ) ;
2016-01-20 13:50:11 -05:00
if ( err ) {
dev_err ( dev , " IRQ handler registering failed (%d) \n " , err ) ;
2017-01-24 15:00:31 -05:00
return err ;
2016-01-20 13:50:11 -05:00
}
return 0 ;
}
2016-05-01 18:44:39 -04:00
static struct isa_driver dio48e_driver = {
. probe = dio48e_probe ,
2016-01-20 13:50:11 -05:00
. driver = {
. name = " 104-dio-48e "
} ,
} ;
2016-05-01 18:44:39 -04:00
module_isa_driver ( dio48e_driver , num_dio48e ) ;
2016-01-20 13:50:11 -05:00
MODULE_AUTHOR ( " William Breathitt Gray <vilhelm.gray@gmail.com> " ) ;
MODULE_DESCRIPTION ( " ACCES 104-DIO-48E GPIO driver " ) ;
2016-02-01 18:51:49 -05:00
MODULE_LICENSE ( " GPL v2 " ) ;