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 if (!priv) { 91 dev_err(&pdev->dev, "called %s without drvdata!\n", __func__); 92 return -EFAULT; 93 } 94 95 /* 96 * You can lose return values below, but we report all errors, and it's 97 * more important to actually perform all of the steps. 98 */ 99 list_for_each(pos, &priv->bank_list) { 100 bank = list_entry(pos, struct brcmstb_gpio_bank, node); 101 ret = bgpio_remove(&bank->bgc); 102 if (ret) 103 dev_err(&pdev->dev, "gpiochip_remove fail in cleanup"); 104 } 105 return ret; 106 } 107 108 static int brcmstb_gpio_of_xlate(struct gpio_chip *gc, 109 const struct of_phandle_args *gpiospec, u32 *flags) 110 { 111 struct brcmstb_gpio_priv *priv = brcmstb_gpio_gc_to_priv(gc); 112 struct brcmstb_gpio_bank *bank = brcmstb_gpio_gc_to_bank(gc); 113 int offset; 114 115 if (gc->of_gpio_n_cells != 2) { 116 WARN_ON(1); 117 return -EINVAL; 118 } 119 120 if (WARN_ON(gpiospec->args_count < gc->of_gpio_n_cells)) 121 return -EINVAL; 122 123 offset = gpiospec->args[0] - (gc->base - priv->gpio_base); 124 if (offset >= gc->ngpio) 125 return -EINVAL; 126 127 if (unlikely(offset >= bank->width)) { 128 dev_warn_ratelimited(&priv->pdev->dev, 129 "Received request for invalid GPIO offset %d\n", 130 gpiospec->args[0]); 131 } 132 133 if (flags) 134 *flags = gpiospec->args[1]; 135 136 return offset; 137 } 138 139 static int brcmstb_gpio_probe(struct platform_device *pdev) 140 { 141 struct device *dev = &pdev->dev; 142 struct device_node *np = dev->of_node; 143 void __iomem *reg_base; 144 struct brcmstb_gpio_priv *priv; 145 struct resource *res; 146 struct property *prop; 147 const __be32 *p; 148 u32 bank_width; 149 int err; 150 static int gpio_base; 151 152 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 153 if (!priv) 154 return -ENOMEM; 155 platform_set_drvdata(pdev, priv); 156 INIT_LIST_HEAD(&priv->bank_list); 157 158 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 159 reg_base = devm_ioremap_resource(dev, res); 160 if (IS_ERR(reg_base)) 161 return PTR_ERR(reg_base); 162 163 priv->gpio_base = gpio_base; 164 priv->reg_base = reg_base; 165 priv->pdev = pdev; 166 167 if (brcmstb_gpio_sanity_check_banks(dev, np, res)) 168 return -EINVAL; 169 170 of_property_for_each_u32(np, "brcm,gpio-bank-widths", prop, p, 171 bank_width) { 172 struct brcmstb_gpio_bank *bank; 173 struct bgpio_chip *bgc; 174 struct gpio_chip *gc; 175 176 bank = devm_kzalloc(dev, sizeof(*bank), GFP_KERNEL); 177 if (!bank) { 178 err = -ENOMEM; 179 goto fail; 180 } 181 182 bank->parent_priv = priv; 183 bank->id = priv->num_banks; 184 if (bank_width <= 0 || bank_width > MAX_GPIO_PER_BANK) { 185 dev_err(dev, "Invalid bank width %d\n", bank_width); 186 goto fail; 187 } else { 188 bank->width = bank_width; 189 } 190 191 /* 192 * Regs are 4 bytes wide, have data reg, no set/clear regs, 193 * and direction bits have 0 = output and 1 = input 194 */ 195 bgc = &bank->bgc; 196 err = bgpio_init(bgc, dev, 4, 197 reg_base + GIO_DATA(bank->id), 198 NULL, NULL, NULL, 199 reg_base + GIO_IODIR(bank->id), 0); 200 if (err) { 201 dev_err(dev, "bgpio_init() failed\n"); 202 goto fail; 203 } 204 205 gc = &bgc->gc; 206 gc->of_node = np; 207 gc->owner = THIS_MODULE; 208 gc->label = np->full_name; 209 gc->base = gpio_base; 210 gc->of_gpio_n_cells = 2; 211 gc->of_xlate = brcmstb_gpio_of_xlate; 212 /* not all ngpio lines are valid, will use bank width later */ 213 gc->ngpio = MAX_GPIO_PER_BANK; 214 215 err = gpiochip_add(gc); 216 if (err) { 217 dev_err(dev, "Could not add gpiochip for bank %d\n", 218 bank->id); 219 goto fail; 220 } 221 gpio_base += gc->ngpio; 222 dev_dbg(dev, "bank=%d, base=%d, ngpio=%d, width=%d\n", bank->id, 223 gc->base, gc->ngpio, bank->width); 224 225 /* Everything looks good, so add bank to list */ 226 list_add(&bank->node, &priv->bank_list); 227 228 priv->num_banks++; 229 } 230 231 dev_info(dev, "Registered %d banks (GPIO(s): %d-%d)\n", 232 priv->num_banks, priv->gpio_base, gpio_base - 1); 233 234 return 0; 235 236 fail: 237 (void) brcmstb_gpio_remove(pdev); 238 return err; 239 } 240 241 static const struct of_device_id brcmstb_gpio_of_match[] = { 242 { .compatible = "brcm,brcmstb-gpio" }, 243 {}, 244 }; 245 246 MODULE_DEVICE_TABLE(of, brcmstb_gpio_of_match); 247 248 static struct platform_driver brcmstb_gpio_driver = { 249 .driver = { 250 .name = "brcmstb-gpio", 251 .of_match_table = brcmstb_gpio_of_match, 252 }, 253 .probe = brcmstb_gpio_probe, 254 .remove = brcmstb_gpio_remove, 255 }; 256 module_platform_driver(brcmstb_gpio_driver); 257 258 MODULE_AUTHOR("Gregory Fong"); 259 MODULE_DESCRIPTION("Driver for Broadcom BRCMSTB SoC UPG GPIO"); 260 MODULE_LICENSE("GPL v2"); 261