18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2019 American Megatrends International LLC. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/hashtable.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/kernel.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 188c2ecf20Sopenharmony_ci#include <linux/string.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie, 228c2ecf20Sopenharmony_ci * slots within the clocked serial GPIO data). Since each HW GPIO is both an 238c2ecf20Sopenharmony_ci * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip 248c2ecf20Sopenharmony_ci * device. 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and 278c2ecf20Sopenharmony_ci * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_ci#define MAX_NR_HW_SGPIO 80 308c2ecf20Sopenharmony_ci#define SGPIO_OUTPUT_OFFSET MAX_NR_HW_SGPIO 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_CTRL 0x54 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_PINS_MASK GENMASK(9, 6) 358c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_CLK_DIV_MASK GENMASK(31, 16) 368c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_ENABLE BIT(0) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct aspeed_sgpio { 398c2ecf20Sopenharmony_ci struct gpio_chip chip; 408c2ecf20Sopenharmony_ci struct clk *pclk; 418c2ecf20Sopenharmony_ci spinlock_t lock; 428c2ecf20Sopenharmony_ci void __iomem *base; 438c2ecf20Sopenharmony_ci int irq; 448c2ecf20Sopenharmony_ci int n_sgpio; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistruct aspeed_sgpio_bank { 488c2ecf20Sopenharmony_ci uint16_t val_regs; 498c2ecf20Sopenharmony_ci uint16_t rdata_reg; 508c2ecf20Sopenharmony_ci uint16_t irq_regs; 518c2ecf20Sopenharmony_ci const char names[4][3]; 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * Note: The "value" register returns the input value when the GPIO is 568c2ecf20Sopenharmony_ci * configured as an input. 578c2ecf20Sopenharmony_ci * 588c2ecf20Sopenharmony_ci * The "rdata" register returns the output value when the GPIO is 598c2ecf20Sopenharmony_ci * configured as an output. 608c2ecf20Sopenharmony_ci */ 618c2ecf20Sopenharmony_cistatic const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = { 628c2ecf20Sopenharmony_ci { 638c2ecf20Sopenharmony_ci .val_regs = 0x0000, 648c2ecf20Sopenharmony_ci .rdata_reg = 0x0070, 658c2ecf20Sopenharmony_ci .irq_regs = 0x0004, 668c2ecf20Sopenharmony_ci .names = { "A", "B", "C", "D" }, 678c2ecf20Sopenharmony_ci }, 688c2ecf20Sopenharmony_ci { 698c2ecf20Sopenharmony_ci .val_regs = 0x001C, 708c2ecf20Sopenharmony_ci .rdata_reg = 0x0074, 718c2ecf20Sopenharmony_ci .irq_regs = 0x0020, 728c2ecf20Sopenharmony_ci .names = { "E", "F", "G", "H" }, 738c2ecf20Sopenharmony_ci }, 748c2ecf20Sopenharmony_ci { 758c2ecf20Sopenharmony_ci .val_regs = 0x0038, 768c2ecf20Sopenharmony_ci .rdata_reg = 0x0078, 778c2ecf20Sopenharmony_ci .irq_regs = 0x003C, 788c2ecf20Sopenharmony_ci .names = { "I", "J" }, 798c2ecf20Sopenharmony_ci }, 808c2ecf20Sopenharmony_ci}; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cienum aspeed_sgpio_reg { 838c2ecf20Sopenharmony_ci reg_val, 848c2ecf20Sopenharmony_ci reg_rdata, 858c2ecf20Sopenharmony_ci reg_irq_enable, 868c2ecf20Sopenharmony_ci reg_irq_type0, 878c2ecf20Sopenharmony_ci reg_irq_type1, 888c2ecf20Sopenharmony_ci reg_irq_type2, 898c2ecf20Sopenharmony_ci reg_irq_status, 908c2ecf20Sopenharmony_ci}; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci#define GPIO_VAL_VALUE 0x00 938c2ecf20Sopenharmony_ci#define GPIO_IRQ_ENABLE 0x00 948c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE0 0x04 958c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE1 0x08 968c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE2 0x0C 978c2ecf20Sopenharmony_ci#define GPIO_IRQ_STATUS 0x10 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic void __iomem *bank_reg(struct aspeed_sgpio *gpio, 1008c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank, 1018c2ecf20Sopenharmony_ci const enum aspeed_sgpio_reg reg) 1028c2ecf20Sopenharmony_ci{ 1038c2ecf20Sopenharmony_ci switch (reg) { 1048c2ecf20Sopenharmony_ci case reg_val: 1058c2ecf20Sopenharmony_ci return gpio->base + bank->val_regs + GPIO_VAL_VALUE; 1068c2ecf20Sopenharmony_ci case reg_rdata: 1078c2ecf20Sopenharmony_ci return gpio->base + bank->rdata_reg; 1088c2ecf20Sopenharmony_ci case reg_irq_enable: 1098c2ecf20Sopenharmony_ci return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE; 1108c2ecf20Sopenharmony_ci case reg_irq_type0: 1118c2ecf20Sopenharmony_ci return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0; 1128c2ecf20Sopenharmony_ci case reg_irq_type1: 1138c2ecf20Sopenharmony_ci return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1; 1148c2ecf20Sopenharmony_ci case reg_irq_type2: 1158c2ecf20Sopenharmony_ci return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2; 1168c2ecf20Sopenharmony_ci case reg_irq_status: 1178c2ecf20Sopenharmony_ci return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS; 1188c2ecf20Sopenharmony_ci default: 1198c2ecf20Sopenharmony_ci /* acturally if code runs to here, it's an error case */ 1208c2ecf20Sopenharmony_ci BUG(); 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci#define GPIO_BANK(x) ((x % SGPIO_OUTPUT_OFFSET) >> 5) 1258c2ecf20Sopenharmony_ci#define GPIO_OFFSET(x) ((x % SGPIO_OUTPUT_OFFSET) & 0x1f) 1268c2ecf20Sopenharmony_ci#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic const struct aspeed_sgpio_bank *to_bank(unsigned int offset) 1298c2ecf20Sopenharmony_ci{ 1308c2ecf20Sopenharmony_ci unsigned int bank; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci bank = GPIO_BANK(offset); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); 1358c2ecf20Sopenharmony_ci return &aspeed_sgpio_banks[bank]; 1368c2ecf20Sopenharmony_ci} 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc, 1398c2ecf20Sopenharmony_ci unsigned long *valid_mask, unsigned int ngpios) 1408c2ecf20Sopenharmony_ci{ 1418c2ecf20Sopenharmony_ci struct aspeed_sgpio *sgpio = gpiochip_get_data(gc); 1428c2ecf20Sopenharmony_ci int n = sgpio->n_sgpio; 1438c2ecf20Sopenharmony_ci int c = SGPIO_OUTPUT_OFFSET - n; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* input GPIOs in the lower range */ 1488c2ecf20Sopenharmony_ci bitmap_set(valid_mask, 0, n); 1498c2ecf20Sopenharmony_ci bitmap_clear(valid_mask, n, c); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* output GPIOS above SGPIO_OUTPUT_OFFSET */ 1528c2ecf20Sopenharmony_ci bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n); 1538c2ecf20Sopenharmony_ci bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return 0; 1568c2ecf20Sopenharmony_ci} 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc, 1598c2ecf20Sopenharmony_ci unsigned long *valid_mask, unsigned int ngpios) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci struct aspeed_sgpio *sgpio = gpiochip_get_data(gc); 1628c2ecf20Sopenharmony_ci int n = sgpio->n_sgpio; 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* input GPIOs in the lower range */ 1678c2ecf20Sopenharmony_ci bitmap_set(valid_mask, 0, n); 1688c2ecf20Sopenharmony_ci bitmap_clear(valid_mask, n, ngpios - n); 1698c2ecf20Sopenharmony_ci} 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistatic bool aspeed_sgpio_is_input(unsigned int offset) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci return offset < SGPIO_OUTPUT_OFFSET; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 1798c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank = to_bank(offset); 1808c2ecf20Sopenharmony_ci unsigned long flags; 1818c2ecf20Sopenharmony_ci enum aspeed_sgpio_reg reg; 1828c2ecf20Sopenharmony_ci int rc = 0; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata; 1878c2ecf20Sopenharmony_ci rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return rc; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 1978c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank = to_bank(offset); 1988c2ecf20Sopenharmony_ci void __iomem *addr_r, *addr_w; 1998c2ecf20Sopenharmony_ci u32 reg = 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (aspeed_sgpio_is_input(offset)) 2028c2ecf20Sopenharmony_ci return -EINVAL; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* Since this is an output, read the cached value from rdata, then 2058c2ecf20Sopenharmony_ci * update val. */ 2068c2ecf20Sopenharmony_ci addr_r = bank_reg(gpio, bank, reg_rdata); 2078c2ecf20Sopenharmony_ci addr_w = bank_reg(gpio, bank, reg_val); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci reg = ioread32(addr_r); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci if (val) 2128c2ecf20Sopenharmony_ci reg |= GPIO_BIT(offset); 2138c2ecf20Sopenharmony_ci else 2148c2ecf20Sopenharmony_ci reg &= ~GPIO_BIT(offset); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci iowrite32(reg, addr_w); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci return 0; 2198c2ecf20Sopenharmony_ci} 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 2248c2ecf20Sopenharmony_ci unsigned long flags; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci sgpio_set_value(gc, offset, val); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_cistatic int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) 2348c2ecf20Sopenharmony_ci{ 2358c2ecf20Sopenharmony_ci return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_cistatic int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio = gpiochip_get_data(gc); 2418c2ecf20Sopenharmony_ci unsigned long flags; 2428c2ecf20Sopenharmony_ci int rc; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* No special action is required for setting the direction; we'll 2458c2ecf20Sopenharmony_ci * error-out in sgpio_set_value if this isn't an output GPIO */ 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 2488c2ecf20Sopenharmony_ci rc = sgpio_set_value(gc, offset, val); 2498c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci return rc; 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci return !!aspeed_sgpio_is_input(offset); 2578c2ecf20Sopenharmony_ci} 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic void irqd_to_aspeed_sgpio_data(struct irq_data *d, 2608c2ecf20Sopenharmony_ci struct aspeed_sgpio **gpio, 2618c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank **bank, 2628c2ecf20Sopenharmony_ci u32 *bit, int *offset) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct aspeed_sgpio *internal; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci *offset = irqd_to_hwirq(d); 2678c2ecf20Sopenharmony_ci internal = irq_data_get_irq_chip_data(d); 2688c2ecf20Sopenharmony_ci WARN_ON(!internal); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci *gpio = internal; 2718c2ecf20Sopenharmony_ci *bank = to_bank(*offset); 2728c2ecf20Sopenharmony_ci *bit = GPIO_BIT(*offset); 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_ack(struct irq_data *d) 2768c2ecf20Sopenharmony_ci{ 2778c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank; 2788c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio; 2798c2ecf20Sopenharmony_ci unsigned long flags; 2808c2ecf20Sopenharmony_ci void __iomem *status_addr; 2818c2ecf20Sopenharmony_ci int offset; 2828c2ecf20Sopenharmony_ci u32 bit; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci status_addr = bank_reg(gpio, bank, reg_irq_status); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci iowrite32(bit, status_addr); 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank; 2988c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio; 2998c2ecf20Sopenharmony_ci unsigned long flags; 3008c2ecf20Sopenharmony_ci u32 reg, bit; 3018c2ecf20Sopenharmony_ci void __iomem *addr; 3028c2ecf20Sopenharmony_ci int offset; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 3058c2ecf20Sopenharmony_ci addr = bank_reg(gpio, bank, reg_irq_enable); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci reg = ioread32(addr); 3108c2ecf20Sopenharmony_ci if (set) 3118c2ecf20Sopenharmony_ci reg |= bit; 3128c2ecf20Sopenharmony_ci else 3138c2ecf20Sopenharmony_ci reg &= ~bit; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci iowrite32(reg, addr); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_mask(struct irq_data *d) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci aspeed_sgpio_irq_set_mask(d, false); 3238c2ecf20Sopenharmony_ci} 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_unmask(struct irq_data *d) 3268c2ecf20Sopenharmony_ci{ 3278c2ecf20Sopenharmony_ci aspeed_sgpio_irq_set_mask(d, true); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci u32 type0 = 0; 3338c2ecf20Sopenharmony_ci u32 type1 = 0; 3348c2ecf20Sopenharmony_ci u32 type2 = 0; 3358c2ecf20Sopenharmony_ci u32 bit, reg; 3368c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank; 3378c2ecf20Sopenharmony_ci irq_flow_handler_t handler; 3388c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio; 3398c2ecf20Sopenharmony_ci unsigned long flags; 3408c2ecf20Sopenharmony_ci void __iomem *addr; 3418c2ecf20Sopenharmony_ci int offset; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci switch (type & IRQ_TYPE_SENSE_MASK) { 3468c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 3478c2ecf20Sopenharmony_ci type2 |= bit; 3488c2ecf20Sopenharmony_ci fallthrough; 3498c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 3508c2ecf20Sopenharmony_ci type0 |= bit; 3518c2ecf20Sopenharmony_ci fallthrough; 3528c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 3538c2ecf20Sopenharmony_ci handler = handle_edge_irq; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 3568c2ecf20Sopenharmony_ci type0 |= bit; 3578c2ecf20Sopenharmony_ci fallthrough; 3588c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 3598c2ecf20Sopenharmony_ci type1 |= bit; 3608c2ecf20Sopenharmony_ci handler = handle_level_irq; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci return -EINVAL; 3648c2ecf20Sopenharmony_ci } 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci spin_lock_irqsave(&gpio->lock, flags); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci addr = bank_reg(gpio, bank, reg_irq_type0); 3698c2ecf20Sopenharmony_ci reg = ioread32(addr); 3708c2ecf20Sopenharmony_ci reg = (reg & ~bit) | type0; 3718c2ecf20Sopenharmony_ci iowrite32(reg, addr); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci addr = bank_reg(gpio, bank, reg_irq_type1); 3748c2ecf20Sopenharmony_ci reg = ioread32(addr); 3758c2ecf20Sopenharmony_ci reg = (reg & ~bit) | type1; 3768c2ecf20Sopenharmony_ci iowrite32(reg, addr); 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci addr = bank_reg(gpio, bank, reg_irq_type2); 3798c2ecf20Sopenharmony_ci reg = ioread32(addr); 3808c2ecf20Sopenharmony_ci reg = (reg & ~bit) | type2; 3818c2ecf20Sopenharmony_ci iowrite32(reg, addr); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&gpio->lock, flags); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci irq_set_handler_locked(d, handler); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_handler(struct irq_desc *desc) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 3938c2ecf20Sopenharmony_ci struct irq_chip *ic = irq_desc_get_chip(desc); 3948c2ecf20Sopenharmony_ci struct aspeed_sgpio *data = gpiochip_get_data(gc); 3958c2ecf20Sopenharmony_ci unsigned int i, p, girq; 3968c2ecf20Sopenharmony_ci unsigned long reg; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci chained_irq_enter(ic, desc); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { 4018c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i]; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci reg = ioread32(bank_reg(data, bank, reg_irq_status)); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci for_each_set_bit(p, ®, 32) { 4068c2ecf20Sopenharmony_ci girq = irq_find_mapping(gc->irq.domain, i * 32 + p); 4078c2ecf20Sopenharmony_ci generic_handle_irq(girq); 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci chained_irq_exit(ic, desc); 4138c2ecf20Sopenharmony_ci} 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_cistatic struct irq_chip aspeed_sgpio_irqchip = { 4168c2ecf20Sopenharmony_ci .name = "aspeed-sgpio", 4178c2ecf20Sopenharmony_ci .irq_ack = aspeed_sgpio_irq_ack, 4188c2ecf20Sopenharmony_ci .irq_mask = aspeed_sgpio_irq_mask, 4198c2ecf20Sopenharmony_ci .irq_unmask = aspeed_sgpio_irq_unmask, 4208c2ecf20Sopenharmony_ci .irq_set_type = aspeed_sgpio_set_type, 4218c2ecf20Sopenharmony_ci}; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, 4248c2ecf20Sopenharmony_ci struct platform_device *pdev) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci int rc, i; 4278c2ecf20Sopenharmony_ci const struct aspeed_sgpio_bank *bank; 4288c2ecf20Sopenharmony_ci struct gpio_irq_chip *irq; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci rc = platform_get_irq(pdev, 0); 4318c2ecf20Sopenharmony_ci if (rc < 0) 4328c2ecf20Sopenharmony_ci return rc; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci gpio->irq = rc; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */ 4378c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { 4388c2ecf20Sopenharmony_ci bank = &aspeed_sgpio_banks[i]; 4398c2ecf20Sopenharmony_ci /* disable irq enable bits */ 4408c2ecf20Sopenharmony_ci iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable)); 4418c2ecf20Sopenharmony_ci /* clear status bits */ 4428c2ecf20Sopenharmony_ci iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status)); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci irq = &gpio->chip.irq; 4468c2ecf20Sopenharmony_ci irq->chip = &aspeed_sgpio_irqchip; 4478c2ecf20Sopenharmony_ci irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask; 4488c2ecf20Sopenharmony_ci irq->handler = handle_bad_irq; 4498c2ecf20Sopenharmony_ci irq->default_type = IRQ_TYPE_NONE; 4508c2ecf20Sopenharmony_ci irq->parent_handler = aspeed_sgpio_irq_handler; 4518c2ecf20Sopenharmony_ci irq->parent_handler_data = gpio; 4528c2ecf20Sopenharmony_ci irq->parents = &gpio->irq; 4538c2ecf20Sopenharmony_ci irq->num_parents = 1; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* Apply default IRQ settings */ 4568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { 4578c2ecf20Sopenharmony_ci bank = &aspeed_sgpio_banks[i]; 4588c2ecf20Sopenharmony_ci /* set falling or level-low irq */ 4598c2ecf20Sopenharmony_ci iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); 4608c2ecf20Sopenharmony_ci /* trigger type is edge */ 4618c2ecf20Sopenharmony_ci iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); 4628c2ecf20Sopenharmony_ci /* single edge trigger */ 4638c2ecf20Sopenharmony_ci iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2)); 4648c2ecf20Sopenharmony_ci } 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci return 0; 4678c2ecf20Sopenharmony_ci} 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_cistatic const struct of_device_id aspeed_sgpio_of_table[] = { 4708c2ecf20Sopenharmony_ci { .compatible = "aspeed,ast2400-sgpio" }, 4718c2ecf20Sopenharmony_ci { .compatible = "aspeed,ast2500-sgpio" }, 4728c2ecf20Sopenharmony_ci {} 4738c2ecf20Sopenharmony_ci}; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_cistatic int __init aspeed_sgpio_probe(struct platform_device *pdev) 4788c2ecf20Sopenharmony_ci{ 4798c2ecf20Sopenharmony_ci struct aspeed_sgpio *gpio; 4808c2ecf20Sopenharmony_ci u32 nr_gpios, sgpio_freq, sgpio_clk_div; 4818c2ecf20Sopenharmony_ci int rc; 4828c2ecf20Sopenharmony_ci unsigned long apb_freq; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); 4858c2ecf20Sopenharmony_ci if (!gpio) 4868c2ecf20Sopenharmony_ci return -ENOMEM; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci gpio->base = devm_platform_ioremap_resource(pdev, 0); 4898c2ecf20Sopenharmony_ci if (IS_ERR(gpio->base)) 4908c2ecf20Sopenharmony_ci return PTR_ERR(gpio->base); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios); 4938c2ecf20Sopenharmony_ci if (rc < 0) { 4948c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not read ngpios property\n"); 4958c2ecf20Sopenharmony_ci return -EINVAL; 4968c2ecf20Sopenharmony_ci } else if (nr_gpios > MAX_NR_HW_SGPIO) { 4978c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", 4988c2ecf20Sopenharmony_ci MAX_NR_HW_SGPIO, nr_gpios); 4998c2ecf20Sopenharmony_ci return -EINVAL; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci gpio->n_sgpio = nr_gpios; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); 5048c2ecf20Sopenharmony_ci if (rc < 0) { 5058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not read bus-frequency property\n"); 5068c2ecf20Sopenharmony_ci return -EINVAL; 5078c2ecf20Sopenharmony_ci } 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci gpio->pclk = devm_clk_get(&pdev->dev, NULL); 5108c2ecf20Sopenharmony_ci if (IS_ERR(gpio->pclk)) { 5118c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "devm_clk_get failed\n"); 5128c2ecf20Sopenharmony_ci return PTR_ERR(gpio->pclk); 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci apb_freq = clk_get_rate(gpio->pclk); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * From the datasheet, 5198c2ecf20Sopenharmony_ci * SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1) 5208c2ecf20Sopenharmony_ci * period = 2 * (GPIO254[31:16] + 1) / PCLK 5218c2ecf20Sopenharmony_ci * frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK) 5228c2ecf20Sopenharmony_ci * frequency = PCLK / (2 * (GPIO254[31:16] + 1)) 5238c2ecf20Sopenharmony_ci * frequency * 2 * (GPIO254[31:16] + 1) = PCLK 5248c2ecf20Sopenharmony_ci * GPIO254[31:16] = PCLK / (frequency * 2) - 1 5258c2ecf20Sopenharmony_ci */ 5268c2ecf20Sopenharmony_ci if (sgpio_freq == 0) 5278c2ecf20Sopenharmony_ci return -EINVAL; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1; 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci if (sgpio_clk_div > (1 << 16) - 1) 5328c2ecf20Sopenharmony_ci return -EINVAL; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) | 5358c2ecf20Sopenharmony_ci FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) | 5368c2ecf20Sopenharmony_ci ASPEED_SGPIO_ENABLE, 5378c2ecf20Sopenharmony_ci gpio->base + ASPEED_SGPIO_CTRL); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci spin_lock_init(&gpio->lock); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci gpio->chip.parent = &pdev->dev; 5428c2ecf20Sopenharmony_ci gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2; 5438c2ecf20Sopenharmony_ci gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask; 5448c2ecf20Sopenharmony_ci gpio->chip.direction_input = aspeed_sgpio_dir_in; 5458c2ecf20Sopenharmony_ci gpio->chip.direction_output = aspeed_sgpio_dir_out; 5468c2ecf20Sopenharmony_ci gpio->chip.get_direction = aspeed_sgpio_get_direction; 5478c2ecf20Sopenharmony_ci gpio->chip.request = NULL; 5488c2ecf20Sopenharmony_ci gpio->chip.free = NULL; 5498c2ecf20Sopenharmony_ci gpio->chip.get = aspeed_sgpio_get; 5508c2ecf20Sopenharmony_ci gpio->chip.set = aspeed_sgpio_set; 5518c2ecf20Sopenharmony_ci gpio->chip.set_config = NULL; 5528c2ecf20Sopenharmony_ci gpio->chip.label = dev_name(&pdev->dev); 5538c2ecf20Sopenharmony_ci gpio->chip.base = -1; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci aspeed_sgpio_setup_irqs(gpio, pdev); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); 5588c2ecf20Sopenharmony_ci if (rc < 0) 5598c2ecf20Sopenharmony_ci return rc; 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic struct platform_driver aspeed_sgpio_driver = { 5658c2ecf20Sopenharmony_ci .driver = { 5668c2ecf20Sopenharmony_ci .name = KBUILD_MODNAME, 5678c2ecf20Sopenharmony_ci .of_match_table = aspeed_sgpio_of_table, 5688c2ecf20Sopenharmony_ci }, 5698c2ecf20Sopenharmony_ci}; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cimodule_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe); 5728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Aspeed Serial GPIO Driver"); 5738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 574