#include
#include
#include
#define GPIO_DIR 0x400
#define GPIO_IS 0x404
#define GPIO_IBE 0x408
#define GPIO_IEV 0x40C
#define GPIO_IE 0x410
#define GPIO_RIS 0x414
#define GPIO_MIS 0x418
#define GPIO_IC 0x41C
/************************************************************************/
/* gpio interface */
/************************************************************************/
/**
* _set_gpio_direction - set gpio direction
*
* @port:
* @offset:
* @dir: 0 -- input, 1 -- output
*/
static void _set_gpio_direction(struct hisi_gpio_port *port, unsigned offset, int dir)
{
u32 l;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
l = __raw_readl(port->base + GPIO_DIR);
if (dir)
l |= (1 << offset);
else
l &= ~(1 << offset);
__raw_writel(l, port->base + GPIO_DIR);
spin_unlock_irqrestore(&port->lock, flags);
}
/**
* hisi_gpio_set - get gpio data
*
*/
static void hisi_gpio_set(struct hisi_gpio_port *port, unsigned offset, int value)
{
void __iomem *reg = port->base + (1 << (offset + 2));
u32 l;
unsigned long flags;
spin_lock_irqsave(&port->lock, flags);
l = (__raw_readl(reg) & (~(1 << offset))) | (!!value << offset);
__raw_writel(l, reg);
spin_unlock_irqrestore(&port->lock, flags);
}
/**
* hisi_gpio_get - get gpio value
*
*/
static int hisi_gpio_get(struct hisi_gpio_port *port, unsigned offset)
{
void __iomem *reg = port->base + (1 << (offset + 2));
u32 gpio_direction;
gpio_direction = __raw_readl(port->base + GPIO_DIR);
if (((gpio_direction >> offset) & 1)) /* output mode */
return (__raw_readl(reg) >> offset) & 1;
else /* input mode */
return 0;
}
/**
* hisi_gpio_direction_input - gpio direction input
*
*/
static int hisi_gpio_direction_input(struct hisi_gpio_port *port, unsigned offset)
{
_set_gpio_direction(port, offset, 0);
return 0;
}
/**
* hisi_gpio_direction_output - gpio direction output
*
*/
static int hisi_gpio_direction_output(struct hisi_gpio_port *port, unsigned offset, int value)
{
hisi_gpio_set(port, offset, value);
_set_gpio_direction(port, offset, 1);
return 0;
}
/**
* hisi_gpio_init - gpio init functions
*
* @ int_trigger_type: 0~4, ref GT911 datasheet
*
* Must be called by goodix_ts_probe functions only once.
*/
static int hisi_gpio_init(struct hisi_gpio_port *port, int int_trigger_type)
{
int i, j;
u32 l;
unsigned offset;
const uint8_t irq_table[] = GTP_IRQ_TAB;
static bool initialed;
if (initialed)
return 0;
printk(KERN_INFO "HISI GPIO hardware\n");
/*1. ioremap */
port->base = ioremap_nocache(GTP_BASE_ADDRESS, GTP_RANGE_SIZE);
if (!port->base) {
dev_err(&ts->client->dev,
"Can't remap gpio address: 0x%x, size:0x%dx\n", GTP_BASE_ADDRESS, GTP_RANGE_SIZE);
return -1;
}
/*2. IOMUX */
/*
writel(reg, IOCONFIG_BASE + 0x178);
writel(reg, IOCONFIG_BASE + 0x17C);
*/
/*3. config rest */
offset = 7;
hisi_gpio_direction_output(port, offset); // output mode
/*4. config int */
offset = 6;
hisi_gpio_direction_input(port, offset); // input mode
//
switch (irq_table[int_trigger_type])
{
case IRQ_TYPE_EDGE_RISING:
{
/* */
l = __raw_readl(port->base + GPIO_IS) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IS);
/* */
l = __raw_readl(port->base + GPIO_IEV) | (1 << offset);
__raw_writel(l, port->base + GPIO_IEV);
/**/
l = __raw_readl(port->base + GPIO_IBE) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IBE);
}
break;
case IRQ_TYPE_EDGE_FALLING:
{
/* */
l = __raw_readl(port->base + GPIO_IS) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IS);
/* */
l = __raw_readl(port->base + GPIO_IEV) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IEV);
/**/
l = __raw_readl(port->base + GPIO_IBE) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IBE);
}
break;
case IRQ_TYPE_LEVEL_LOW:
{
/* */
l = __raw_readl(port->base + GPIO_IS) | (1 << offset);
__raw_writel(l, port->base + GPIO_IS);
/* */
l = __raw_readl(port->base + GPIO_IEV) & (~(1 << offset));
__raw_writel(l, port->base + GPIO_IEV);
}
break;
case IRQ_TYPE_LEVEL_HIGH:
{
/* */
l = __raw_readl(port->base + GPIO_IS) | (1 << offset);
__raw_writel(l, port->base + GPIO_IS);
/* */
l = __raw_readl(port->base + GPIO_IEV) | (1 << offset);
__raw_writel(l, port->base + GPIO_IEV);
}
break;
default:
break;
}
/* disable the interrupt and clear the status */
__raw_writel(~0, port->base + GPIO_IC);
__raw_writel(~0, port->base + GPIO_IE);
spin_lock_init(&port->lock);
initialed = true;
return 0;
}
/**
* hisi_gpio_deinit - DeInit functions
*
*/
static void hisi_gpio_deinit(struct hisi_gpio_port *port)
{
if (!port)
return;
__raw_writel(~0, port->base + GPIO_IC);
__raw_writel(0, port->base + GPIO_IE);
if (port->base)
{
iounmap(port->base);
}
}