linux/drivers/gpio/gpio-etraxfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <linux/kernel.h>
   3#include <linux/init.h>
   4#include <linux/gpio/driver.h>
   5#include <linux/of_gpio.h>
   6#include <linux/io.h>
   7#include <linux/interrupt.h>
   8#include <linux/platform_device.h>
   9
  10#define ETRAX_FS_rw_pa_dout     0
  11#define ETRAX_FS_r_pa_din       4
  12#define ETRAX_FS_rw_pa_oe       8
  13#define ETRAX_FS_rw_intr_cfg    12
  14#define ETRAX_FS_rw_intr_mask   16
  15#define ETRAX_FS_rw_ack_intr    20
  16#define ETRAX_FS_r_intr         24
  17#define ETRAX_FS_r_masked_intr  28
  18#define ETRAX_FS_rw_pb_dout     32
  19#define ETRAX_FS_r_pb_din       36
  20#define ETRAX_FS_rw_pb_oe       40
  21#define ETRAX_FS_rw_pc_dout     48
  22#define ETRAX_FS_r_pc_din       52
  23#define ETRAX_FS_rw_pc_oe       56
  24#define ETRAX_FS_rw_pd_dout     64
  25#define ETRAX_FS_r_pd_din       68
  26#define ETRAX_FS_rw_pd_oe       72
  27#define ETRAX_FS_rw_pe_dout     80
  28#define ETRAX_FS_r_pe_din       84
  29#define ETRAX_FS_rw_pe_oe       88
  30
  31#define ARTPEC3_r_pa_din        0
  32#define ARTPEC3_rw_pa_dout      4
  33#define ARTPEC3_rw_pa_oe        8
  34#define ARTPEC3_r_pb_din        44
  35#define ARTPEC3_rw_pb_dout      48
  36#define ARTPEC3_rw_pb_oe        52
  37#define ARTPEC3_r_pc_din        88
  38#define ARTPEC3_rw_pc_dout      92
  39#define ARTPEC3_rw_pc_oe        96
  40#define ARTPEC3_r_pd_din        116
  41#define ARTPEC3_rw_intr_cfg     120
  42#define ARTPEC3_rw_intr_pins    124
  43#define ARTPEC3_rw_intr_mask    128
  44#define ARTPEC3_rw_ack_intr     132
  45#define ARTPEC3_r_masked_intr   140
  46
  47#define GIO_CFG_OFF             0
  48#define GIO_CFG_HI              1
  49#define GIO_CFG_LO              2
  50#define GIO_CFG_SET             3
  51#define GIO_CFG_POSEDGE         5
  52#define GIO_CFG_NEGEDGE         6
  53#define GIO_CFG_ANYEDGE         7
  54
  55struct etraxfs_gpio_info;
  56
  57struct etraxfs_gpio_block {
  58        raw_spinlock_t lock;
  59        u32 mask;
  60        u32 cfg;
  61        u32 pins;
  62        unsigned int group[8];
  63
  64        void __iomem *regs;
  65        const struct etraxfs_gpio_info *info;
  66};
  67
  68struct etraxfs_gpio_chip {
  69        struct gpio_chip gc;
  70        struct etraxfs_gpio_block *block;
  71};
  72
  73struct etraxfs_gpio_port {
  74        const char *label;
  75        unsigned int oe;
  76        unsigned int dout;
  77        unsigned int din;
  78        unsigned int ngpio;
  79};
  80
  81struct etraxfs_gpio_info {
  82        unsigned int num_ports;
  83        const struct etraxfs_gpio_port *ports;
  84
  85        unsigned int rw_ack_intr;
  86        unsigned int rw_intr_mask;
  87        unsigned int rw_intr_cfg;
  88        unsigned int rw_intr_pins;
  89        unsigned int r_masked_intr;
  90};
  91
  92static const struct etraxfs_gpio_port etraxfs_gpio_etraxfs_ports[] = {
  93        {
  94                .label  = "A",
  95                .ngpio  = 8,
  96                .oe     = ETRAX_FS_rw_pa_oe,
  97                .dout   = ETRAX_FS_rw_pa_dout,
  98                .din    = ETRAX_FS_r_pa_din,
  99        },
 100        {
 101                .label  = "B",
 102                .ngpio  = 18,
 103                .oe     = ETRAX_FS_rw_pb_oe,
 104                .dout   = ETRAX_FS_rw_pb_dout,
 105                .din    = ETRAX_FS_r_pb_din,
 106        },
 107        {
 108                .label  = "C",
 109                .ngpio  = 18,
 110                .oe     = ETRAX_FS_rw_pc_oe,
 111                .dout   = ETRAX_FS_rw_pc_dout,
 112                .din    = ETRAX_FS_r_pc_din,
 113        },
 114        {
 115                .label  = "D",
 116                .ngpio  = 18,
 117                .oe     = ETRAX_FS_rw_pd_oe,
 118                .dout   = ETRAX_FS_rw_pd_dout,
 119                .din    = ETRAX_FS_r_pd_din,
 120        },
 121        {
 122                .label  = "E",
 123                .ngpio  = 18,
 124                .oe     = ETRAX_FS_rw_pe_oe,
 125                .dout   = ETRAX_FS_rw_pe_dout,
 126                .din    = ETRAX_FS_r_pe_din,
 127        },
 128};
 129
 130static const struct etraxfs_gpio_info etraxfs_gpio_etraxfs = {
 131        .num_ports = ARRAY_SIZE(etraxfs_gpio_etraxfs_ports),
 132        .ports = etraxfs_gpio_etraxfs_ports,
 133        .rw_ack_intr    = ETRAX_FS_rw_ack_intr,
 134        .rw_intr_mask   = ETRAX_FS_rw_intr_mask,
 135        .rw_intr_cfg    = ETRAX_FS_rw_intr_cfg,
 136        .r_masked_intr  = ETRAX_FS_r_masked_intr,
 137};
 138
 139static const struct etraxfs_gpio_port etraxfs_gpio_artpec3_ports[] = {
 140        {
 141                .label  = "A",
 142                .ngpio  = 32,
 143                .oe     = ARTPEC3_rw_pa_oe,
 144                .dout   = ARTPEC3_rw_pa_dout,
 145                .din    = ARTPEC3_r_pa_din,
 146        },
 147        {
 148                .label  = "B",
 149                .ngpio  = 32,
 150                .oe     = ARTPEC3_rw_pb_oe,
 151                .dout   = ARTPEC3_rw_pb_dout,
 152                .din    = ARTPEC3_r_pb_din,
 153        },
 154        {
 155                .label  = "C",
 156                .ngpio  = 16,
 157                .oe     = ARTPEC3_rw_pc_oe,
 158                .dout   = ARTPEC3_rw_pc_dout,
 159                .din    = ARTPEC3_r_pc_din,
 160        },
 161        {
 162                .label  = "D",
 163                .ngpio  = 32,
 164                .din    = ARTPEC3_r_pd_din,
 165        },
 166};
 167
 168static const struct etraxfs_gpio_info etraxfs_gpio_artpec3 = {
 169        .num_ports = ARRAY_SIZE(etraxfs_gpio_artpec3_ports),
 170        .ports = etraxfs_gpio_artpec3_ports,
 171        .rw_ack_intr    = ARTPEC3_rw_ack_intr,
 172        .rw_intr_mask   = ARTPEC3_rw_intr_mask,
 173        .rw_intr_cfg    = ARTPEC3_rw_intr_cfg,
 174        .r_masked_intr  = ARTPEC3_r_masked_intr,
 175        .rw_intr_pins   = ARTPEC3_rw_intr_pins,
 176};
 177
 178static unsigned int etraxfs_gpio_chip_to_port(struct gpio_chip *gc)
 179{
 180        return gc->label[0] - 'A';
 181}
 182
 183static int etraxfs_gpio_of_xlate(struct gpio_chip *gc,
 184                               const struct of_phandle_args *gpiospec,
 185                               u32 *flags)
 186{
 187        /*
 188         * Port numbers are A to E, and the properties are integers, so we
 189         * specify them as 0xA - 0xE.
 190         */
 191        if (etraxfs_gpio_chip_to_port(gc) + 0xA != gpiospec->args[2])
 192                return -EINVAL;
 193
 194        return of_gpio_simple_xlate(gc, gpiospec, flags);
 195}
 196
 197static const struct of_device_id etraxfs_gpio_of_table[] = {
 198        {
 199                .compatible = "axis,etraxfs-gio",
 200                .data = &etraxfs_gpio_etraxfs,
 201        },
 202        {
 203                .compatible = "axis,artpec3-gio",
 204                .data = &etraxfs_gpio_artpec3,
 205        },
 206        {},
 207};
 208
 209static unsigned int etraxfs_gpio_to_group_irq(unsigned int gpio)
 210{
 211        return gpio % 8;
 212}
 213
 214static unsigned int etraxfs_gpio_to_group_pin(struct etraxfs_gpio_chip *chip,
 215                                              unsigned int gpio)
 216{
 217        return 4 * etraxfs_gpio_chip_to_port(&chip->gc) + gpio / 8;
 218}
 219
 220static void etraxfs_gpio_irq_ack(struct irq_data *d)
 221{
 222        struct etraxfs_gpio_chip *chip =
 223                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 224        struct etraxfs_gpio_block *block = chip->block;
 225        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 226
 227        writel(BIT(grpirq), block->regs + block->info->rw_ack_intr);
 228}
 229
 230static void etraxfs_gpio_irq_mask(struct irq_data *d)
 231{
 232        struct etraxfs_gpio_chip *chip =
 233                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 234        struct etraxfs_gpio_block *block = chip->block;
 235        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 236
 237        raw_spin_lock(&block->lock);
 238        block->mask &= ~BIT(grpirq);
 239        writel(block->mask, block->regs + block->info->rw_intr_mask);
 240        raw_spin_unlock(&block->lock);
 241}
 242
 243static void etraxfs_gpio_irq_unmask(struct irq_data *d)
 244{
 245        struct etraxfs_gpio_chip *chip =
 246                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 247        struct etraxfs_gpio_block *block = chip->block;
 248        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 249
 250        raw_spin_lock(&block->lock);
 251        block->mask |= BIT(grpirq);
 252        writel(block->mask, block->regs + block->info->rw_intr_mask);
 253        raw_spin_unlock(&block->lock);
 254}
 255
 256static int etraxfs_gpio_irq_set_type(struct irq_data *d, u32 type)
 257{
 258        struct etraxfs_gpio_chip *chip =
 259                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 260        struct etraxfs_gpio_block *block = chip->block;
 261        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 262        u32 cfg;
 263
 264        switch (type) {
 265        case IRQ_TYPE_EDGE_RISING:
 266                cfg = GIO_CFG_POSEDGE;
 267                break;
 268        case IRQ_TYPE_EDGE_FALLING:
 269                cfg = GIO_CFG_NEGEDGE;
 270                break;
 271        case IRQ_TYPE_EDGE_BOTH:
 272                cfg = GIO_CFG_ANYEDGE;
 273                break;
 274        case IRQ_TYPE_LEVEL_LOW:
 275                cfg = GIO_CFG_LO;
 276                break;
 277        case IRQ_TYPE_LEVEL_HIGH:
 278                cfg = GIO_CFG_HI;
 279                break;
 280        default:
 281                return -EINVAL;
 282        }
 283
 284        raw_spin_lock(&block->lock);
 285        block->cfg &= ~(0x7 << (grpirq * 3));
 286        block->cfg |= (cfg << (grpirq * 3));
 287        writel(block->cfg, block->regs + block->info->rw_intr_cfg);
 288        raw_spin_unlock(&block->lock);
 289
 290        return 0;
 291}
 292
 293static int etraxfs_gpio_irq_request_resources(struct irq_data *d)
 294{
 295        struct etraxfs_gpio_chip *chip =
 296                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 297        struct etraxfs_gpio_block *block = chip->block;
 298        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 299        int ret = -EBUSY;
 300
 301        raw_spin_lock(&block->lock);
 302        if (block->group[grpirq])
 303                goto out;
 304
 305        ret = gpiochip_lock_as_irq(&chip->gc, d->hwirq);
 306        if (ret)
 307                goto out;
 308
 309        block->group[grpirq] = d->irq;
 310        if (block->info->rw_intr_pins) {
 311                unsigned int pin = etraxfs_gpio_to_group_pin(chip, d->hwirq);
 312
 313                block->pins &= ~(0xf << (grpirq * 4));
 314                block->pins |= (pin << (grpirq * 4));
 315
 316                writel(block->pins, block->regs + block->info->rw_intr_pins);
 317        }
 318
 319out:
 320        raw_spin_unlock(&block->lock);
 321        return ret;
 322}
 323
 324static void etraxfs_gpio_irq_release_resources(struct irq_data *d)
 325{
 326        struct etraxfs_gpio_chip *chip =
 327                gpiochip_get_data(irq_data_get_irq_chip_data(d));
 328        struct etraxfs_gpio_block *block = chip->block;
 329        unsigned int grpirq = etraxfs_gpio_to_group_irq(d->hwirq);
 330
 331        raw_spin_lock(&block->lock);
 332        block->group[grpirq] = 0;
 333        gpiochip_unlock_as_irq(&chip->gc, d->hwirq);
 334        raw_spin_unlock(&block->lock);
 335}
 336
 337static struct irq_chip etraxfs_gpio_irq_chip = {
 338        .name           = "gpio-etraxfs",
 339        .irq_ack        = etraxfs_gpio_irq_ack,
 340        .irq_mask       = etraxfs_gpio_irq_mask,
 341        .irq_unmask     = etraxfs_gpio_irq_unmask,
 342        .irq_set_type   = etraxfs_gpio_irq_set_type,
 343        .irq_request_resources = etraxfs_gpio_irq_request_resources,
 344        .irq_release_resources = etraxfs_gpio_irq_release_resources,
 345};
 346
 347static irqreturn_t etraxfs_gpio_interrupt(int irq, void *dev_id)
 348{
 349        struct etraxfs_gpio_block *block = dev_id;
 350        unsigned long intr = readl(block->regs + block->info->r_masked_intr);
 351        int bit;
 352
 353        for_each_set_bit(bit, &intr, 8)
 354                generic_handle_irq(block->group[bit]);
 355
 356        return IRQ_RETVAL(intr & 0xff);
 357}
 358
 359static int etraxfs_gpio_probe(struct platform_device *pdev)
 360{
 361        struct device *dev = &pdev->dev;
 362        const struct etraxfs_gpio_info *info;
 363        const struct of_device_id *match;
 364        struct etraxfs_gpio_block *block;
 365        struct etraxfs_gpio_chip *chips;
 366        struct resource *res, *irq;
 367        bool allportsirq = false;
 368        void __iomem *regs;
 369        int ret;
 370        int i;
 371
 372        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 373        regs = devm_ioremap_resource(dev, res);
 374        if (IS_ERR(regs))
 375                return PTR_ERR(regs);
 376
 377        match = of_match_node(etraxfs_gpio_of_table, dev->of_node);
 378        if (!match)
 379                return -EINVAL;
 380
 381        info = match->data;
 382
 383        chips = devm_kzalloc(dev, sizeof(*chips) * info->num_ports, GFP_KERNEL);
 384        if (!chips)
 385                return -ENOMEM;
 386
 387        irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 388        if (!irq)
 389                return -EINVAL;
 390
 391        block = devm_kzalloc(dev, sizeof(*block), GFP_KERNEL);
 392        if (!block)
 393                return -ENOMEM;
 394
 395        raw_spin_lock_init(&block->lock);
 396
 397        block->regs = regs;
 398        block->info = info;
 399
 400        writel(0, block->regs + info->rw_intr_mask);
 401        writel(0, block->regs + info->rw_intr_cfg);
 402        if (info->rw_intr_pins) {
 403                allportsirq = true;
 404                writel(0, block->regs + info->rw_intr_pins);
 405        }
 406
 407        ret = devm_request_irq(dev, irq->start, etraxfs_gpio_interrupt,
 408                               IRQF_SHARED, dev_name(dev), block);
 409        if (ret) {
 410                dev_err(dev, "Unable to request irq %d\n", ret);
 411                return ret;
 412        }
 413
 414        for (i = 0; i < info->num_ports; i++) {
 415                struct etraxfs_gpio_chip *chip = &chips[i];
 416                struct gpio_chip *gc = &chip->gc;
 417                const struct etraxfs_gpio_port *port = &info->ports[i];
 418                unsigned long flags = BGPIOF_READ_OUTPUT_REG_SET;
 419                void __iomem *dat = regs + port->din;
 420                void __iomem *set = regs + port->dout;
 421                void __iomem *dirout = regs + port->oe;
 422
 423                chip->block = block;
 424
 425                if (dirout == set) {
 426                        dirout = set = NULL;
 427                        flags = BGPIOF_NO_OUTPUT;
 428                }
 429
 430                ret = bgpio_init(gc, dev, 4,
 431                                 dat, set, NULL, dirout, NULL,
 432                                 flags);
 433                if (ret) {
 434                        dev_err(dev, "Unable to init port %s\n",
 435                                port->label);
 436                        continue;
 437                }
 438
 439                gc->ngpio = port->ngpio;
 440                gc->label = port->label;
 441
 442                gc->of_node = dev->of_node;
 443                gc->of_gpio_n_cells = 3;
 444                gc->of_xlate = etraxfs_gpio_of_xlate;
 445
 446                ret = gpiochip_add_data(gc, chip);
 447                if (ret) {
 448                        dev_err(dev, "Unable to register port %s\n",
 449                                gc->label);
 450                        continue;
 451                }
 452
 453                if (i > 0 && !allportsirq)
 454                        continue;
 455
 456                ret = gpiochip_irqchip_add(gc, &etraxfs_gpio_irq_chip, 0,
 457                                           handle_level_irq, IRQ_TYPE_NONE);
 458                if (ret) {
 459                        dev_err(dev, "Unable to add irqchip to port %s\n",
 460                                gc->label);
 461                }
 462        }
 463
 464        return 0;
 465}
 466
 467static struct platform_driver etraxfs_gpio_driver = {
 468        .driver = {
 469                .name           = "etraxfs-gpio",
 470                .of_match_table = of_match_ptr(etraxfs_gpio_of_table),
 471        },
 472        .probe  = etraxfs_gpio_probe,
 473};
 474
 475builtin_platform_driver(etraxfs_gpio_driver);
 476