海思GPIO
阿新 • • 發佈:2019-01-04
#include <asm/io.h> #include <mach/irqs.h> #include <mach/hardware.h> #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); } }