1 /* 2 * Copyright (C) 2015 Broadcom Corporation 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation version 2. 7 * 8 * This program is distributed "as is" WITHOUT ANY WARRANTY of any 9 * kind, whether express or implied; without even the implied warranty 10 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 */ 13 14 #include <linux/bitops.h> 15 #include <linux/gpio/driver.h> 16 #include <linux/of_device.h> 17 #include <linux/of_irq.h> 18 #include <linux/module.h> 19 #include <linux/basic_mmio_gpio.h> 20 21 #define GIO_BANK_SIZE 0x20 22 #define GIO_ODEN(bank) (((bank) * GIO_BANK_SIZE) + 0x00) 23 #define GIO_DATA(bank) (((bank) * GIO_BANK_SIZE) + 0x04) 24 #define GIO_IODIR(bank) (((bank) * GIO_BANK_SIZE) + 0x08) 25 #define GIO_EC(bank) (((bank) * GIO_BANK_SIZE) + 0x0c) 26 #define GIO_EI(bank) (((bank) * GIO_BANK_SIZE) + 0x10) 27 #define GIO_MASK(bank) (((bank) * GIO_BANK_SIZE) + 0x14) 28 #define GIO_LEVEL(bank) (((bank) * GIO_BANK_SIZE) + 0x18) 29 #define GIO_STAT(bank) (((bank) * GIO_BANK_SIZE) + 0x1c) 30 31 struct brcmstb_gpio_bank { 32 struct list_head node; 33 int id; 34 struct bgpio_chip bgc; 35 struct brcmstb_gpio_priv *parent_priv; 36 u32 width; 37 }; 38 39 struct brcmstb_gpio_priv { 40 struct list_head bank_list; 41 void __iomem *reg_base; 42 int num_banks; 43 struct platform_device *pdev; 44 int gpio_base; 45 }; 46 47 #define MAX_GPIO_PER_BANK 32 48 #define GPIO_BANK(gpio) ((gpio) >> 5) 49 /* assumes MAX_GPIO_PER_BANK is a multiple of 2 */ 50 #define GPIO_BIT(gpio) ((gpio) & (MAX_GPIO_PER_BANK - 1)) 51 52 static inline struct brcmstb_gpio_bank * 53 brcmstb_gpio_gc_to_bank(struct gpio_chip *gc) 54 { 55 struct bgpio_chip *bgc = to_bgpio_chip(gc); 56 return container_of(bgc, struct brcmstb_gpio_bank, bgc); 57 } 58 59 static inline struct brcmstb_gpio_priv * 60 brcmstb_gpio_gc_to_priv(struct gpio_chip *gc) 61 { 62 struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); 63 return bank->parent_priv; 64 } 65 66 /* Make sure that the number of banks matches up between properties */ 67 static int brcmstb_gpio_sanity_check_banks(struct device *dev, 68 struct device_node *np, struct resource *res) 69 { 70 int res_num_banks = resource_size(res) / GIO_BANK_SIZE; 71 int num_banks = 72 of_property_count_u32_elems(np, "brcm,gpio-bank-widths"); 73 74 if (res_num_banks != num_banks) { 75 dev_err(dev, "Mismatch in banks: res had %d, bank-widths had %d\n", 76 res_num_banks, num_banks); 77 return -EINVAL; 78 } else { 79 return 0; 80 } 81 } 82 83 static int brcmstb_gpio_remove(struct platform_device *pdev) 84 { 85 struct brcmstb_gpio_priv *priv = platform_get_drvdata(pdev); 86 struct list_head *pos; 87 struct brcmstb_gpio_bank *bank; 88 int ret = 0; 89 90 list_for_each(pos, &priv->bank_list) { 91 bank = list_entry(pos, struct brcmstb_gpio_bank, node); 92 ret = bgpio_remove(&bank->bgc); 93 if (ret) 94 dev_err(&pdev->dev, "gpiochip_remove fail in cleanup"); 95 } 96 return ret; 97 } 98 99 static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, 100 const struct of_phandle_args *gpiospec, u32 *flags) 101 { 102 struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); 103 struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); 104 int offset; 105 106 if (gc->of_gpio_n_cells != 2) { 107 WARN_ON(1); 108 return -EINVAL; 109 } 110 111 if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) 112 return -EINVAL; 113 114 offset = gpiospec->args[0] - (gc->base - priv->gpio_base); 115 if (offset >= gc->ngpio) 116 return -EINVAL; 117 118 if (unlikely(offset >= bank->width)) { 119 dev_warn_ratelimited(&priv->pdev->dev, 120 "Received request for invalid GPIO offset %d\n", 121 gpiospec->args[0]); 122 } 123 124 if (flags) 125 *flags = gpiospec->args[1]; 126 127 return offset; 128 } 129 130 static int brcmstb_gpio_probe(struct platform_device *pdev) 131 { 132 struct device *dev = &pdev->dev; 133 struct device_node *np = dev->of_node; 134 void __iomem *reg_base; 135 struct brcmstb_gpio_priv *priv; 136 struct resource *res; 137 struct property *prop; 138 const __be32 *p; 139 u32 bank_width; 140 int err; 141 static int gpio_base; 142 143 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 144 if (!priv) 145 return -ENOMEM; 146 147 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 148 reg_base = devm_ioremap_resource(dev, res); 149 if (IS_ERR(reg_base)) 150 return PTR_ERR(reg_base); 151 152 priv->gpio_base = gpio_base; 153 priv->reg_base = reg_base; 154 priv->pdev = pdev; 155 156 INIT_LIST_HEAD(&priv->bank_list); 157 if (brcmstb_gpio_sanity_check_banks(dev, np, res)) 158 return -EINVAL; 159 160 of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, 161 bank_width) { 162 struct brcmstb_gpio_bank *bank; 163 struct bgpio_chip *bgc; 164 struct gpio_chip *gc; 165 166 bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); 167 if (!bank) { 168 err = -ENOMEM; 169 goto fail; 170 } 171 172 bank->parent_priv = priv; 173 bank->id = priv->num_banks; 174 if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) { 175 dev_err(dev, "Invalid bank width %d\n", bank_width); 176 goto fail; 177 } else { 178 bank->width = bank_width; 179 } 180 181 /* 182 * Regs are 4 bytes wide, have data reg, no set/clear regs, 183 * and direction bits have 0 = output and 1 = input 184 */ 185 bgc = &bank->bgc; 186 err = bgpio_init(bgc, dev, 4, 187 reg_base + GIO_DATA(bank->id), 188 NULL, NULL, NULL, 189 reg_base + GIO_IODIR(bank->id), 0); 190 if (err) { 191 dev_err(dev, "bgpio_init() failed\n"); 192 goto fail; 193 } 194 195 gc = &bgc->gc; 196 gc->of_node = np; 197 gc->owner = THIS_MODULE; 198 gc->label = np->full_name; 199 gc->base = gpio_base; 200 gc->of_gpio_n_cells = 2; 201 gc->of_xlate = brcmstb_gpio_of_xlate; 202 /* not all ngpio lines are valid, will use bank width later */ 203 gc->ngpio = MAX_GPIO_PER_BANK; 204 205 err = gpiochip_add(gc); 206 if (err) { 207 dev_err(dev, "Could not add gpiochip for bank %d\n", 208 bank->id); 209 goto fail; 210 } 211 gpio_base += gc->ngpio; 212 dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, 213 gc->base, gc->ngpio, bank->width); 214 215 /* Everything looks good, so add bank to list */ 216 list_add(&bank->node, &priv->bank_list); 217 218 priv->num_banks++; 219 } 220 221 dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", 222 priv->num_banks, priv->gpio_base, gpio_base - 1); 223 224 platform_set_drvdata(pdev, priv); 225 226 return 0; 227 228 fail: 229 (void) brcmstb_gpio_remove(pdev); 230 return err; 231 } 232 233 static const struct of_device_id brcmstb_gpio_of_match[] = { 234 { .compatible = "brcm,brcmstb-gpio" }, 235 {}, 236 }; 237 238 MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match); 239 240 static struct platform_driver brcmstb_gpio_driver = { 241 .driver = { 242 .name = "brcmstb-gpio", 243 .of_match_table = brcmstb_gpio_of_match, 244 }, 245 .probe = brcmstb_gpio_probe, 246 .remove = brcmstb_gpio_remove, 247 }; 248 module_platform_driver(brcmstb_gpio_driver); 249 250 MODULE_AUTHOR("Gregory Fong"); 251 MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO"); 252 MODULE_LICENSE("GPL v2"); 253