2013-01-19 01:30:34 +04:00
/*
* Allwinner A1X SoCs pinctrl driver .
*
* Copyright ( C ) 2012 Maxime Ripard
*
* Maxime Ripard < maxime . ripard @ free - electrons . com >
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed " as is " without any
* warranty of any kind , whether express or implied .
*/
# ifndef __PINCTRL_SUNXI_H
# define __PINCTRL_SUNXI_H
# include <linux/kernel.h>
2013-08-04 14:38:48 +04:00
# include <linux/spinlock.h>
2013-01-19 01:30:34 +04:00
# define PA_BASE 0
# define PB_BASE 32
# define PC_BASE 64
# define PD_BASE 96
# define PE_BASE 128
# define PF_BASE 160
# define PG_BASE 192
2013-01-26 18:36:53 +04:00
# define PH_BASE 224
# define PI_BASE 256
2014-04-10 17:52:42 +04:00
# define PL_BASE 352
# define PM_BASE 384
2014-10-29 00:41:26 +03:00
# define PN_BASE 416
2013-01-19 01:30:34 +04:00
2014-04-24 18:06:52 +04:00
# define SUNXI_PINCTRL_PIN(bank, pin) \
PINCTRL_PIN ( P # # bank # # _BASE + ( pin ) , " P " # bank # pin )
2014-04-10 17:52:42 +04:00
2013-01-29 00:33:12 +04:00
# define SUNXI_PIN_NAME_MAX_LEN 5
2013-01-19 01:30:34 +04:00
# define BANK_MEM_SIZE 0x24
# define MUX_REGS_OFFSET 0x0
2013-01-29 00:33:12 +04:00
# define DATA_REGS_OFFSET 0x10
2013-01-19 01:30:34 +04:00
# define DLEVEL_REGS_OFFSET 0x14
# define PULL_REGS_OFFSET 0x1c
# define PINS_PER_BANK 32
# define MUX_PINS_PER_REG 8
# define MUX_PINS_BITS 4
# define MUX_PINS_MASK 0x0f
2013-01-29 00:33:12 +04:00
# define DATA_PINS_PER_REG 32
# define DATA_PINS_BITS 1
# define DATA_PINS_MASK 0x01
2013-01-19 01:30:34 +04:00
# define DLEVEL_PINS_PER_REG 16
# define DLEVEL_PINS_BITS 2
# define DLEVEL_PINS_MASK 0x03
# define PULL_PINS_PER_REG 16
# define PULL_PINS_BITS 2
# define PULL_PINS_MASK 0x03
2014-06-05 17:26:04 +04:00
# define IRQ_PER_BANK 32
2013-06-08 14:05:44 +04:00
# define IRQ_CFG_REG 0x200
# define IRQ_CFG_IRQ_PER_REG 8
# define IRQ_CFG_IRQ_BITS 4
# define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1)
# define IRQ_CTRL_REG 0x210
# define IRQ_CTRL_IRQ_PER_REG 32
# define IRQ_CTRL_IRQ_BITS 1
# define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1)
# define IRQ_STATUS_REG 0x214
# define IRQ_STATUS_IRQ_PER_REG 32
# define IRQ_STATUS_IRQ_BITS 1
# define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
2014-06-05 17:26:04 +04:00
# define IRQ_MEM_SIZE 0x20
2013-06-08 14:05:44 +04:00
# define IRQ_EDGE_RISING 0x00
# define IRQ_EDGE_FALLING 0x01
# define IRQ_LEVEL_HIGH 0x02
# define IRQ_LEVEL_LOW 0x03
# define IRQ_EDGE_BOTH 0x04
2015-03-09 00:13:57 +03:00
# define SUN4I_FUNC_INPUT 0
# define SUN4I_FUNC_IRQ 6
2013-01-19 01:30:34 +04:00
struct sunxi_desc_function {
const char * name ;
u8 muxval ;
2014-06-05 17:26:01 +04:00
u8 irqbank ;
2013-06-08 14:05:44 +04:00
u8 irqnum ;
2013-01-19 01:30:34 +04:00
} ;
struct sunxi_desc_pin {
struct pinctrl_pin_desc pin ;
struct sunxi_desc_function * functions ;
} ;
struct sunxi_pinctrl_desc {
const struct sunxi_desc_pin * pins ;
int npins ;
2014-04-10 17:52:43 +04:00
unsigned pin_base ;
2014-06-05 17:26:02 +04:00
unsigned irq_banks ;
2015-03-09 00:13:57 +03:00
bool irq_read_needs_mux ;
2013-01-19 01:30:34 +04:00
} ;
struct sunxi_pinctrl_function {
const char * name ;
const char * * groups ;
unsigned ngroups ;
} ;
struct sunxi_pinctrl_group {
const char * name ;
unsigned long config ;
unsigned pin ;
} ;
struct sunxi_pinctrl {
void __iomem * membase ;
2013-01-29 00:33:12 +04:00
struct gpio_chip * chip ;
2014-04-18 21:34:07 +04:00
const struct sunxi_pinctrl_desc * desc ;
2013-01-19 01:30:34 +04:00
struct device * dev ;
2013-06-08 14:05:44 +04:00
struct irq_domain * domain ;
2013-01-19 01:30:34 +04:00
struct sunxi_pinctrl_function * functions ;
unsigned nfunctions ;
struct sunxi_pinctrl_group * groups ;
unsigned ngroups ;
2014-06-05 17:26:04 +04:00
int * irq ;
unsigned * irq_array ;
2013-08-04 14:38:48 +04:00
spinlock_t lock ;
2013-01-19 01:30:34 +04:00
struct pinctrl_dev * pctl_dev ;
} ;
# define SUNXI_PIN(_pin, ...) \
{ \
. pin = _pin , \
. functions = ( struct sunxi_desc_function [ ] ) { \
__VA_ARGS__ , { } } , \
}
# define SUNXI_FUNCTION(_val, _name) \
{ \
. name = _name , \
. muxval = _val , \
}
2013-06-08 14:05:44 +04:00
# define SUNXI_FUNCTION_IRQ(_val, _irq) \
{ \
. name = " irq " , \
. muxval = _val , \
. irqnum = _irq , \
}
2014-06-05 17:26:01 +04:00
# define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq) \
{ \
. name = " irq " , \
. muxval = _val , \
. irqbank = _bank , \
. irqnum = _irq , \
}
2013-01-19 01:30:34 +04:00
/*
* The sunXi PIO registers are organized as is :
* 0x00 - 0x0c Muxing values .
* 8 pins per register , each pin having a 4 bits value
* 0x10 Pin values
* 32 bits per register , each pin corresponding to one bit
* 0x14 - 0x18 Drive level
* 16 pins per register , each pin having a 2 bits value
* 0x1c - 0x20 Pull - Up values
* 16 pins per register , each pin having a 2 bits value
*
* This is for the first bank . Each bank will have the same layout ,
* with an offset being a multiple of 0x24 .
*
* The following functions calculate from the pin number the register
* and the bit offset that we should access .
*/
static inline u32 sunxi_mux_reg ( u16 pin )
{
u8 bank = pin / PINS_PER_BANK ;
u32 offset = bank * BANK_MEM_SIZE ;
offset + = MUX_REGS_OFFSET ;
offset + = pin % PINS_PER_BANK / MUX_PINS_PER_REG * 0x04 ;
return round_down ( offset , 4 ) ;
}
static inline u32 sunxi_mux_offset ( u16 pin )
{
u32 pin_num = pin % MUX_PINS_PER_REG ;
return pin_num * MUX_PINS_BITS ;
}
2013-01-29 00:33:12 +04:00
static inline u32 sunxi_data_reg ( u16 pin )
{
u8 bank = pin / PINS_PER_BANK ;
u32 offset = bank * BANK_MEM_SIZE ;
offset + = DATA_REGS_OFFSET ;
offset + = pin % PINS_PER_BANK / DATA_PINS_PER_REG * 0x04 ;
return round_down ( offset , 4 ) ;
}
static inline u32 sunxi_data_offset ( u16 pin )
{
u32 pin_num = pin % DATA_PINS_PER_REG ;
return pin_num * DATA_PINS_BITS ;
}
2013-01-19 01:30:34 +04:00
static inline u32 sunxi_dlevel_reg ( u16 pin )
{
u8 bank = pin / PINS_PER_BANK ;
u32 offset = bank * BANK_MEM_SIZE ;
offset + = DLEVEL_REGS_OFFSET ;
offset + = pin % PINS_PER_BANK / DLEVEL_PINS_PER_REG * 0x04 ;
return round_down ( offset , 4 ) ;
}
static inline u32 sunxi_dlevel_offset ( u16 pin )
{
u32 pin_num = pin % DLEVEL_PINS_PER_REG ;
return pin_num * DLEVEL_PINS_BITS ;
}
static inline u32 sunxi_pull_reg ( u16 pin )
{
u8 bank = pin / PINS_PER_BANK ;
u32 offset = bank * BANK_MEM_SIZE ;
offset + = PULL_REGS_OFFSET ;
offset + = pin % PINS_PER_BANK / PULL_PINS_PER_REG * 0x04 ;
return round_down ( offset , 4 ) ;
}
static inline u32 sunxi_pull_offset ( u16 pin )
{
u32 pin_num = pin % PULL_PINS_PER_REG ;
return pin_num * PULL_PINS_BITS ;
}
2013-06-08 14:05:44 +04:00
static inline u32 sunxi_irq_cfg_reg ( u16 irq )
{
2014-06-05 17:26:04 +04:00
u8 bank = irq / IRQ_PER_BANK ;
u8 reg = ( irq % IRQ_PER_BANK ) / IRQ_CFG_IRQ_PER_REG * 0x04 ;
return IRQ_CFG_REG + bank * IRQ_MEM_SIZE + reg ;
2013-06-08 14:05:44 +04:00
}
static inline u32 sunxi_irq_cfg_offset ( u16 irq )
{
u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG ;
return irq_num * IRQ_CFG_IRQ_BITS ;
}
2014-06-05 17:26:04 +04:00
static inline u32 sunxi_irq_ctrl_reg_from_bank ( u8 bank )
{
return IRQ_CTRL_REG + bank * IRQ_MEM_SIZE ;
}
2013-06-08 14:05:44 +04:00
static inline u32 sunxi_irq_ctrl_reg ( u16 irq )
{
2014-06-05 17:26:04 +04:00
u8 bank = irq / IRQ_PER_BANK ;
return sunxi_irq_ctrl_reg_from_bank ( bank ) ;
2013-06-08 14:05:44 +04:00
}
static inline u32 sunxi_irq_ctrl_offset ( u16 irq )
{
u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG ;
return irq_num * IRQ_CTRL_IRQ_BITS ;
}
2014-06-05 17:26:04 +04:00
static inline u32 sunxi_irq_status_reg_from_bank ( u8 bank )
{
return IRQ_STATUS_REG + bank * IRQ_MEM_SIZE ;
}
2013-06-08 14:05:44 +04:00
static inline u32 sunxi_irq_status_reg ( u16 irq )
{
2014-06-05 17:26:04 +04:00
u8 bank = irq / IRQ_PER_BANK ;
return sunxi_irq_status_reg_from_bank ( bank ) ;
2013-06-08 14:05:44 +04:00
}
static inline u32 sunxi_irq_status_offset ( u16 irq )
{
u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG ;
return irq_num * IRQ_STATUS_IRQ_BITS ;
}
2014-04-18 22:10:41 +04:00
int sunxi_pinctrl_init ( struct platform_device * pdev ,
const struct sunxi_pinctrl_desc * desc ) ;
2013-01-19 01:30:34 +04:00
# endif /* __PINCTRL_SUNXI_H */