linux/drivers/pinctrl/pinctrl-digicolor.c
<<
>>
Prefs
   1/*
   2 *  Driver for Conexant Digicolor General Purpose Pin Mapping
   3 *
   4 * Author: Baruch Siach <baruch@tkos.co.il>
   5 *
   6 * Copyright (C) 2015 Paradox Innovation Ltd.
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * TODO:
  14 * - GPIO interrupt support
  15 * - Pin pad configuration (pull up/down, strength)
  16 */
  17
  18#include <linux/init.h>
  19#include <linux/platform_device.h>
  20#include <linux/of.h>
  21#include <linux/of_device.h>
  22#include <linux/io.h>
  23#include <linux/gpio.h>
  24#include <linux/gpio/driver.h>
  25#include <linux/spinlock.h>
  26#include <linux/pinctrl/machine.h>
  27#include <linux/pinctrl/pinconf.h>
  28#include <linux/pinctrl/pinconf-generic.h>
  29#include <linux/pinctrl/pinctrl.h>
  30#include <linux/pinctrl/pinmux.h>
  31#include "pinctrl-utils.h"
  32
  33#define DRIVER_NAME     "pinctrl-digicolor"
  34
  35#define GP_CLIENTSEL(clct)      ((clct)*8 + 0x20)
  36#define GP_DRIVE0(clct)         (GP_CLIENTSEL(clct) + 2)
  37#define GP_OUTPUT0(clct)        (GP_CLIENTSEL(clct) + 3)
  38#define GP_INPUT(clct)          (GP_CLIENTSEL(clct) + 6)
  39
  40#define PIN_COLLECTIONS         ('R' - 'A' + 1)
  41#define PINS_PER_COLLECTION     8
  42#define PINS_COUNT              (PIN_COLLECTIONS * PINS_PER_COLLECTION)
  43
  44struct dc_pinmap {
  45        void __iomem            *regs;
  46        struct device           *dev;
  47        struct pinctrl_dev      *pctl;
  48
  49        struct pinctrl_desc     *desc;
  50        const char              *pin_names[PINS_COUNT];
  51
  52        struct gpio_chip        chip;
  53        spinlock_t              lock;
  54};
  55
  56static int dc_get_groups_count(struct pinctrl_dev *pctldev)
  57{
  58        return PINS_COUNT;
  59}
  60
  61static const char *dc_get_group_name(struct pinctrl_dev *pctldev,
  62                                     unsigned selector)
  63{
  64        struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  65
  66        /* Exactly one group per pin */
  67        return pmap->desc->pins[selector].name;
  68}
  69
  70static int dc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
  71                             const unsigned **pins,
  72                             unsigned *num_pins)
  73{
  74        struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
  75
  76        *pins = &pmap->desc->pins[selector].number;
  77        *num_pins = 1;
  78
  79        return 0;
  80}
  81
  82static const struct pinctrl_ops dc_pinctrl_ops = {
  83        .get_groups_count       = dc_get_groups_count,
  84        .get_group_name         = dc_get_group_name,
  85        .get_group_pins         = dc_get_group_pins,
  86        .dt_node_to_map         = pinconf_generic_dt_node_to_map_pin,
  87        .dt_free_map            = pinctrl_utils_free_map,
  88};
  89
  90static const char *const dc_functions[] = {
  91        "gpio",
  92        "client_a",
  93        "client_b",
  94        "client_c",
  95};
  96
  97static int dc_get_functions_count(struct pinctrl_dev *pctldev)
  98{
  99        return ARRAY_SIZE(dc_functions);
 100}
 101
 102static const char *dc_get_fname(struct pinctrl_dev *pctldev, unsigned selector)
 103{
 104        return dc_functions[selector];
 105}
 106
 107static int dc_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
 108                         const char * const **groups,
 109                         unsigned * const num_groups)
 110{
 111        struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
 112
 113        *groups = pmap->pin_names;
 114        *num_groups = PINS_COUNT;
 115
 116        return 0;
 117}
 118
 119static void dc_client_sel(int pin_num, int *reg, int *bit)
 120{
 121        *bit = (pin_num % PINS_PER_COLLECTION) * 2;
 122        *reg = GP_CLIENTSEL(pin_num/PINS_PER_COLLECTION);
 123
 124        if (*bit >= PINS_PER_COLLECTION) {
 125                *bit -= PINS_PER_COLLECTION;
 126                *reg += 1;
 127        }
 128}
 129
 130static int dc_set_mux(struct pinctrl_dev *pctldev, unsigned selector,
 131                      unsigned group)
 132{
 133        struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pctldev);
 134        int bit_off, reg_off;
 135        u8 reg;
 136
 137        dc_client_sel(group, &reg_off, &bit_off);
 138
 139        reg = readb_relaxed(pmap->regs + reg_off);
 140        reg &= ~(3 << bit_off);
 141        reg |= (selector << bit_off);
 142        writeb_relaxed(reg, pmap->regs + reg_off);
 143
 144        return 0;
 145}
 146
 147static int dc_pmx_request_gpio(struct pinctrl_dev *pcdev,
 148                               struct pinctrl_gpio_range *range,
 149                               unsigned offset)
 150{
 151        struct dc_pinmap *pmap = pinctrl_dev_get_drvdata(pcdev);
 152        int bit_off, reg_off;
 153        u8 reg;
 154
 155        dc_client_sel(offset, &reg_off, &bit_off);
 156
 157        reg = readb_relaxed(pmap->regs + reg_off);
 158        if ((reg & (3 << bit_off)) != 0)
 159                return -EBUSY;
 160
 161        return 0;
 162}
 163
 164static const struct pinmux_ops dc_pmxops = {
 165        .get_functions_count    = dc_get_functions_count,
 166        .get_function_name      = dc_get_fname,
 167        .get_function_groups    = dc_get_groups,
 168        .set_mux                = dc_set_mux,
 169        .gpio_request_enable    = dc_pmx_request_gpio,
 170};
 171
 172static int dc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
 173{
 174        struct dc_pinmap *pmap = gpiochip_get_data(chip);
 175        int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
 176        int bit_off = gpio % PINS_PER_COLLECTION;
 177        u8 drive;
 178        unsigned long flags;
 179
 180        spin_lock_irqsave(&pmap->lock, flags);
 181        drive = readb_relaxed(pmap->regs + reg_off);
 182        drive &= ~BIT(bit_off);
 183        writeb_relaxed(drive, pmap->regs + reg_off);
 184        spin_unlock_irqrestore(&pmap->lock, flags);
 185
 186        return 0;
 187}
 188
 189static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value);
 190
 191static int dc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
 192                                    int value)
 193{
 194        struct dc_pinmap *pmap = gpiochip_get_data(chip);
 195        int reg_off = GP_DRIVE0(gpio/PINS_PER_COLLECTION);
 196        int bit_off = gpio % PINS_PER_COLLECTION;
 197        u8 drive;
 198        unsigned long flags;
 199
 200        dc_gpio_set(chip, gpio, value);
 201
 202        spin_lock_irqsave(&pmap->lock, flags);
 203        drive = readb_relaxed(pmap->regs + reg_off);
 204        drive |= BIT(bit_off);
 205        writeb_relaxed(drive, pmap->regs + reg_off);
 206        spin_unlock_irqrestore(&pmap->lock, flags);
 207
 208        return 0;
 209}
 210
 211static int dc_gpio_get(struct gpio_chip *chip, unsigned gpio)
 212{
 213        struct dc_pinmap *pmap = gpiochip_get_data(chip);
 214        int reg_off = GP_INPUT(gpio/PINS_PER_COLLECTION);
 215        int bit_off = gpio % PINS_PER_COLLECTION;
 216        u8 input;
 217
 218        input = readb_relaxed(pmap->regs + reg_off);
 219
 220        return !!(input & BIT(bit_off));
 221}
 222
 223static void dc_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
 224{
 225        struct dc_pinmap *pmap = gpiochip_get_data(chip);
 226        int reg_off = GP_OUTPUT0(gpio/PINS_PER_COLLECTION);
 227        int bit_off = gpio % PINS_PER_COLLECTION;
 228        u8 output;
 229        unsigned long flags;
 230
 231        spin_lock_irqsave(&pmap->lock, flags);
 232        output = readb_relaxed(pmap->regs + reg_off);
 233        if (value)
 234                output |= BIT(bit_off);
 235        else
 236                output &= ~BIT(bit_off);
 237        writeb_relaxed(output, pmap->regs + reg_off);
 238        spin_unlock_irqrestore(&pmap->lock, flags);
 239}
 240
 241static int dc_gpiochip_add(struct dc_pinmap *pmap, struct device_node *np)
 242{
 243        struct gpio_chip *chip = &pmap->chip;
 244        int ret;
 245
 246        chip->label             = DRIVER_NAME;
 247        chip->parent            = pmap->dev;
 248        chip->request           = gpiochip_generic_request;
 249        chip->free              = gpiochip_generic_free;
 250        chip->direction_input   = dc_gpio_direction_input;
 251        chip->direction_output  = dc_gpio_direction_output;
 252        chip->get               = dc_gpio_get;
 253        chip->set               = dc_gpio_set;
 254        chip->base              = -1;
 255        chip->ngpio             = PINS_COUNT;
 256        chip->of_node           = np;
 257        chip->of_gpio_n_cells   = 2;
 258
 259        spin_lock_init(&pmap->lock);
 260
 261        ret = gpiochip_add_data(chip, pmap);
 262        if (ret < 0)
 263                return ret;
 264
 265        ret = gpiochip_add_pin_range(chip, dev_name(pmap->dev), 0, 0,
 266                                     PINS_COUNT);
 267        if (ret < 0) {
 268                gpiochip_remove(chip);
 269                return ret;
 270        }
 271
 272        return 0;
 273}
 274
 275static int dc_pinctrl_probe(struct platform_device *pdev)
 276{
 277        struct dc_pinmap *pmap;
 278        struct resource *r;
 279        struct pinctrl_pin_desc *pins;
 280        struct pinctrl_desc *pctl_desc;
 281        char *pin_names;
 282        int name_len = strlen("GP_xx") + 1;
 283        int i, j;
 284
 285        pmap = devm_kzalloc(&pdev->dev, sizeof(*pmap), GFP_KERNEL);
 286        if (!pmap)
 287                return -ENOMEM;
 288
 289        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 290        pmap->regs = devm_ioremap_resource(&pdev->dev, r);
 291        if (IS_ERR(pmap->regs))
 292                return PTR_ERR(pmap->regs);
 293
 294        pins = devm_kzalloc(&pdev->dev, sizeof(*pins)*PINS_COUNT, GFP_KERNEL);
 295        if (!pins)
 296                return -ENOMEM;
 297        pin_names = devm_kzalloc(&pdev->dev, name_len * PINS_COUNT,
 298                                 GFP_KERNEL);
 299        if (!pin_names)
 300                return -ENOMEM;
 301
 302        for (i = 0; i < PIN_COLLECTIONS; i++) {
 303                for (j = 0; j < PINS_PER_COLLECTION; j++) {
 304                        int pin_id = i*PINS_PER_COLLECTION + j;
 305                        char *name = &pin_names[pin_id * name_len];
 306
 307                        snprintf(name, name_len, "GP_%c%c", 'A'+i, '0'+j);
 308
 309                        pins[pin_id].number = pin_id;
 310                        pins[pin_id].name = name;
 311                        pmap->pin_names[pin_id] = name;
 312                }
 313        }
 314
 315        pctl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctl_desc), GFP_KERNEL);
 316        if (!pctl_desc)
 317                return -ENOMEM;
 318
 319        pctl_desc->name = DRIVER_NAME,
 320        pctl_desc->owner = THIS_MODULE,
 321        pctl_desc->pctlops = &dc_pinctrl_ops,
 322        pctl_desc->pmxops = &dc_pmxops,
 323        pctl_desc->npins = PINS_COUNT;
 324        pctl_desc->pins = pins;
 325        pmap->desc = pctl_desc;
 326
 327        pmap->dev = &pdev->dev;
 328
 329        pmap->pctl = devm_pinctrl_register(&pdev->dev, pctl_desc, pmap);
 330        if (IS_ERR(pmap->pctl)) {
 331                dev_err(&pdev->dev, "pinctrl driver registration failed\n");
 332                return PTR_ERR(pmap->pctl);
 333        }
 334
 335        return dc_gpiochip_add(pmap, pdev->dev.of_node);
 336}
 337
 338static const struct of_device_id dc_pinctrl_ids[] = {
 339        { .compatible = "cnxt,cx92755-pinctrl" },
 340        { /* sentinel */ }
 341};
 342
 343static struct platform_driver dc_pinctrl_driver = {
 344        .driver = {
 345                .name = DRIVER_NAME,
 346                .of_match_table = dc_pinctrl_ids,
 347                .suppress_bind_attrs = true,
 348        },
 349        .probe = dc_pinctrl_probe,
 350};
 351builtin_platform_driver(dc_pinctrl_driver);
 352