linux/drivers/gpio/gpio-vt8500.c
<<
>>
Prefs
   1/* drivers/gpio/gpio-vt8500.c
   2 *
   3 * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz>
   4 * Based on arch/arm/mach-vt8500/gpio.c:
   5 * - Copyright (C) 2010 Alexey Charkov <alchark@gmail.com>
   6 *
   7 * This software is licensed under the terms of the GNU General Public
   8 * License version 2, as published by the Free Software Foundation, and
   9 * may be copied, distributed, and modified under those terms.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 * GNU General Public License for more details.
  15 *
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/err.h>
  20#include <linux/io.h>
  21#include <linux/gpio.h>
  22#include <linux/platform_device.h>
  23#include <linux/bitops.h>
  24#include <linux/of.h>
  25#include <linux/of_address.h>
  26#include <linux/of_irq.h>
  27#include <linux/of_device.h>
  28
  29/*
  30        We handle GPIOs by bank, each bank containing up to 32 GPIOs covered
  31        by one set of registers (although not all may be valid).
  32
  33        Because different SoC's have different register offsets, we pass the
  34        register offsets as data in vt8500_gpio_dt_ids[].
  35
  36        A value of NO_REG is used to indicate that this register is not
  37        supported. Only used for ->en at the moment.
  38*/
  39
  40#define NO_REG  0xFFFF
  41
  42/*
  43 * struct vt8500_gpio_bank_regoffsets
  44 * @en: offset to enable register of the bank
  45 * @dir: offset to direction register of the bank
  46 * @data_out: offset to the data out register of the bank
  47 * @data_in: offset to the data in register of the bank
  48 * @ngpio: highest valid pin in this bank
  49 */
  50
  51struct vt8500_gpio_bank_regoffsets {
  52        unsigned int    en;
  53        unsigned int    dir;
  54        unsigned int    data_out;
  55        unsigned int    data_in;
  56        unsigned char   ngpio;
  57};
  58
  59struct vt8500_gpio_data {
  60        unsigned int                            num_banks;
  61        struct vt8500_gpio_bank_regoffsets      banks[];
  62};
  63
  64#define VT8500_BANK(__en, __dir, __out, __in, __ngpio)          \
  65{                                                               \
  66        .en = __en,                                             \
  67        .dir = __dir,                                           \
  68        .data_out = __out,                                      \
  69        .data_in = __in,                                        \
  70        .ngpio = __ngpio,                                       \
  71}
  72
  73static struct vt8500_gpio_data vt8500_data = {
  74        .num_banks      = 7,
  75        .banks  = {
  76                VT8500_BANK(0x00, 0x20, 0x40, 0x60, 26),
  77                VT8500_BANK(0x04, 0x24, 0x44, 0x64, 28),
  78                VT8500_BANK(0x08, 0x28, 0x48, 0x68, 31),
  79                VT8500_BANK(0x0C, 0x2C, 0x4C, 0x6C, 19),
  80                VT8500_BANK(0x10, 0x30, 0x50, 0x70, 19),
  81                VT8500_BANK(0x14, 0x34, 0x54, 0x74, 23),
  82                VT8500_BANK(NO_REG, 0x3C, 0x5C, 0x7C, 9),
  83        },
  84};
  85
  86static struct vt8500_gpio_data wm8505_data = {
  87        .num_banks      = 10,
  88        .banks  = {
  89                VT8500_BANK(0x40, 0x68, 0x90, 0xB8, 8),
  90                VT8500_BANK(0x44, 0x6C, 0x94, 0xBC, 32),
  91                VT8500_BANK(0x48, 0x70, 0x98, 0xC0, 6),
  92                VT8500_BANK(0x4C, 0x74, 0x9C, 0xC4, 16),
  93                VT8500_BANK(0x50, 0x78, 0xA0, 0xC8, 25),
  94                VT8500_BANK(0x54, 0x7C, 0xA4, 0xCC, 5),
  95                VT8500_BANK(0x58, 0x80, 0xA8, 0xD0, 5),
  96                VT8500_BANK(0x5C, 0x84, 0xAC, 0xD4, 12),
  97                VT8500_BANK(0x60, 0x88, 0xB0, 0xD8, 16),
  98                VT8500_BANK(0x64, 0x8C, 0xB4, 0xDC, 22),
  99                VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
 100        },
 101};
 102
 103/*
 104 * No information about which bits are valid so we just make
 105 * them all available until its figured out.
 106 */
 107static struct vt8500_gpio_data wm8650_data = {
 108        .num_banks      = 9,
 109        .banks  = {
 110                VT8500_BANK(0x40, 0x80, 0xC0, 0x00, 32),
 111                VT8500_BANK(0x44, 0x84, 0xC4, 0x04, 32),
 112                VT8500_BANK(0x48, 0x88, 0xC8, 0x08, 32),
 113                VT8500_BANK(0x4C, 0x8C, 0xCC, 0x0C, 32),
 114                VT8500_BANK(0x50, 0x90, 0xD0, 0x10, 32),
 115                VT8500_BANK(0x54, 0x94, 0xD4, 0x14, 32),
 116                VT8500_BANK(0x58, 0x98, 0xD8, 0x18, 32),
 117                VT8500_BANK(0x5C, 0x9C, 0xDC, 0x1C, 32),
 118                VT8500_BANK(0x7C, 0xBC, 0xFC, 0x3C, 32),
 119                VT8500_BANK(0x500, 0x504, 0x508, 0x50C, 6),
 120        },
 121};
 122
 123struct vt8500_gpio_chip {
 124        struct gpio_chip                chip;
 125
 126        const struct vt8500_gpio_bank_regoffsets *regs;
 127        void __iomem    *base;
 128};
 129
 130
 131#define to_vt8500(__chip) container_of(__chip, struct vt8500_gpio_chip, chip)
 132
 133static int vt8500_gpio_request(struct gpio_chip *chip, unsigned offset)
 134{
 135        u32 val;
 136        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 137
 138        if (vt8500_chip->regs->en == NO_REG)
 139                return 0;
 140
 141        val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
 142        val |= BIT(offset);
 143        writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
 144
 145        return 0;
 146}
 147
 148static void vt8500_gpio_free(struct gpio_chip *chip, unsigned offset)
 149{
 150        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 151        u32 val;
 152
 153        if (vt8500_chip->regs->en == NO_REG)
 154                return;
 155
 156        val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->en);
 157        val &= ~BIT(offset);
 158        writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->en);
 159}
 160
 161static int vt8500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 162{
 163        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 164
 165        u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
 166        val &= ~BIT(offset);
 167        writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
 168
 169        return 0;
 170}
 171
 172static int vt8500_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 173                                                                int value)
 174{
 175        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 176
 177        u32 val = readl_relaxed(vt8500_chip->base + vt8500_chip->regs->dir);
 178        val |= BIT(offset);
 179        writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->dir);
 180
 181        if (value) {
 182                val = readl_relaxed(vt8500_chip->base +
 183                                                vt8500_chip->regs->data_out);
 184                val |= BIT(offset);
 185                writel_relaxed(val, vt8500_chip->base +
 186                                                vt8500_chip->regs->data_out);
 187        }
 188        return 0;
 189}
 190
 191static int vt8500_gpio_get_value(struct gpio_chip *chip, unsigned offset)
 192{
 193        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 194
 195        return (readl_relaxed(vt8500_chip->base + vt8500_chip->regs->data_in) >>
 196                                                                offset) & 1;
 197}
 198
 199static void vt8500_gpio_set_value(struct gpio_chip *chip, unsigned offset,
 200                                                                int value)
 201{
 202        struct vt8500_gpio_chip *vt8500_chip = to_vt8500(chip);
 203
 204        u32 val = readl_relaxed(vt8500_chip->base +
 205                                                vt8500_chip->regs->data_out);
 206        if (value)
 207                val |= BIT(offset);
 208        else
 209                val &= ~BIT(offset);
 210
 211        writel_relaxed(val, vt8500_chip->base + vt8500_chip->regs->data_out);
 212}
 213
 214static int vt8500_of_xlate(struct gpio_chip *gc,
 215                            const struct of_phandle_args *gpiospec, u32 *flags)
 216{
 217        /* bank if specificed in gpiospec->args[0] */
 218        if (flags)
 219                *flags = gpiospec->args[2];
 220
 221        return gpiospec->args[1];
 222}
 223
 224static int vt8500_add_chips(struct platform_device *pdev, void __iomem *base,
 225                                const struct vt8500_gpio_data *data)
 226{
 227        struct vt8500_gpio_chip *vtchip;
 228        struct gpio_chip *chip;
 229        int i;
 230        int pin_cnt = 0;
 231
 232        vtchip = devm_kzalloc(&pdev->dev,
 233                        sizeof(struct vt8500_gpio_chip) * data->num_banks,
 234                        GFP_KERNEL);
 235        if (!vtchip) {
 236                pr_err("%s: failed to allocate chip memory\n", __func__);
 237                return -ENOMEM;
 238        }
 239
 240        for (i = 0; i < data->num_banks; i++) {
 241                vtchip[i].base = base;
 242                vtchip[i].regs = &data->banks[i];
 243
 244                chip = &vtchip[i].chip;
 245
 246                chip->of_xlate = vt8500_of_xlate;
 247                chip->of_gpio_n_cells = 3;
 248                chip->of_node = pdev->dev.of_node;
 249
 250                chip->request = vt8500_gpio_request;
 251                chip->free = vt8500_gpio_free;
 252                chip->direction_input = vt8500_gpio_direction_input;
 253                chip->direction_output = vt8500_gpio_direction_output;
 254                chip->get = vt8500_gpio_get_value;
 255                chip->set = vt8500_gpio_set_value;
 256                chip->can_sleep = 0;
 257                chip->base = pin_cnt;
 258                chip->ngpio = data->banks[i].ngpio;
 259
 260                pin_cnt += data->banks[i].ngpio;
 261
 262                gpiochip_add(chip);
 263        }
 264        return 0;
 265}
 266
 267static struct of_device_id vt8500_gpio_dt_ids[] = {
 268        { .compatible = "via,vt8500-gpio", .data = &vt8500_data, },
 269        { .compatible = "wm,wm8505-gpio", .data = &wm8505_data, },
 270        { .compatible = "wm,wm8650-gpio", .data = &wm8650_data, },
 271        { /* Sentinel */ },
 272};
 273
 274static int vt8500_gpio_probe(struct platform_device *pdev)
 275{
 276        void __iomem *gpio_base;
 277        struct device_node *np;
 278        const struct of_device_id *of_id =
 279                                of_match_device(vt8500_gpio_dt_ids, &pdev->dev);
 280
 281        if (!of_id) {
 282                dev_err(&pdev->dev, "Failed to find gpio controller\n");
 283                return -ENODEV;
 284        }
 285
 286        np = pdev->dev.of_node;
 287        if (!np) {
 288                dev_err(&pdev->dev, "Missing GPIO description in devicetree\n");
 289                return -EFAULT;
 290        }
 291
 292        gpio_base = of_iomap(np, 0);
 293        if (!gpio_base) {
 294                dev_err(&pdev->dev, "Unable to map GPIO registers\n");
 295                of_node_put(np);
 296                return -ENOMEM;
 297        }
 298
 299        vt8500_add_chips(pdev, gpio_base, of_id->data);
 300
 301        return 0;
 302}
 303
 304static struct platform_driver vt8500_gpio_driver = {
 305        .probe          = vt8500_gpio_probe,
 306        .driver         = {
 307                .name   = "vt8500-gpio",
 308                .owner  = THIS_MODULE,
 309                .of_match_table = vt8500_gpio_dt_ids,
 310        },
 311};
 312
 313module_platform_driver(vt8500_gpio_driver);
 314
 315MODULE_DESCRIPTION("VT8500 GPIO Driver");
 316MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>");
 317MODULE_LICENSE("GPL v2");
 318MODULE_DEVICE_TABLE(of, vt8500_gpio_dt_ids);
 319
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.