162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Generic driver for memory-mapped GPIO controllers. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008 MontaVista Software, Inc. 662306a36Sopenharmony_ci * Copyright 2008,2010 Anton Vorontsov <cbouatmailru@gmail.com> 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * ....``.```~~~~````.`.`.`.`.```````'',,,.........`````......`....... 962306a36Sopenharmony_ci * ...`` ```````.. 1062306a36Sopenharmony_ci * ..The simplest form of a GPIO controller that the driver supports is`` 1162306a36Sopenharmony_ci * `.just a single "data" register, where GPIO state can be read and/or ` 1262306a36Sopenharmony_ci * `,..written. ,,..``~~~~ .....``.`.`.~~.```.`.........``````.``````` 1362306a36Sopenharmony_ci * ````````` 1462306a36Sopenharmony_ci ___ 1562306a36Sopenharmony_ci_/~~|___/~| . ```~~~~~~ ___/___\___ ,~.`.`.`.`````.~~...,,,,... 1662306a36Sopenharmony_ci__________|~$@~~~ %~ /o*o*o*o*o*o\ .. Implementing such a GPIO . 1762306a36Sopenharmony_cio ` ~~~~\___/~~~~ ` controller in FPGA is ,.` 1862306a36Sopenharmony_ci `....trivial..'~`.```.``` 1962306a36Sopenharmony_ci * ``````` 2062306a36Sopenharmony_ci * .```````~~~~`..`.``.``. 2162306a36Sopenharmony_ci * . The driver supports `... ,..```.`~~~```````````````....````.``,, 2262306a36Sopenharmony_ci * . big-endian notation, just`. .. A bit more sophisticated controllers , 2362306a36Sopenharmony_ci * . register the device with -be`. .with a pair of set/clear-bit registers , 2462306a36Sopenharmony_ci * `.. suffix. ```~~`````....`.` . affecting the data register and the .` 2562306a36Sopenharmony_ci * ``.`.``...``` ```.. output pins are also supported.` 2662306a36Sopenharmony_ci * ^^ `````.`````````.,``~``~``~~`````` 2762306a36Sopenharmony_ci * . ^^ 2862306a36Sopenharmony_ci * ,..`.`.`...````````````......`.`.`.`.`.`..`.`.`.. 2962306a36Sopenharmony_ci * .. The expectation is that in at least some cases . ,-~~~-, 3062306a36Sopenharmony_ci * .this will be used with roll-your-own ASIC/FPGA .` \ / 3162306a36Sopenharmony_ci * .logic in Verilog or VHDL. ~~~`````````..`````~~` \ / 3262306a36Sopenharmony_ci * ..````````......``````````` \o_ 3362306a36Sopenharmony_ci * | 3462306a36Sopenharmony_ci * ^^ / \ 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * ...`````~~`.....``.`..........``````.`.``.```........``. 3762306a36Sopenharmony_ci * ` 8, 16, 32 and 64 bits registers are supported, and``. 3862306a36Sopenharmony_ci * . the number of GPIOs is determined by the width of ~ 3962306a36Sopenharmony_ci * .. the registers. ,............```.`.`..`.`.~~~.`.`.`~ 4062306a36Sopenharmony_ci * `.......````.``` 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci#include <linux/init.h> 4462306a36Sopenharmony_ci#include <linux/err.h> 4562306a36Sopenharmony_ci#include <linux/bug.h> 4662306a36Sopenharmony_ci#include <linux/kernel.h> 4762306a36Sopenharmony_ci#include <linux/module.h> 4862306a36Sopenharmony_ci#include <linux/spinlock.h> 4962306a36Sopenharmony_ci#include <linux/compiler.h> 5062306a36Sopenharmony_ci#include <linux/types.h> 5162306a36Sopenharmony_ci#include <linux/errno.h> 5262306a36Sopenharmony_ci#include <linux/log2.h> 5362306a36Sopenharmony_ci#include <linux/ioport.h> 5462306a36Sopenharmony_ci#include <linux/io.h> 5562306a36Sopenharmony_ci#include <linux/gpio/driver.h> 5662306a36Sopenharmony_ci#include <linux/slab.h> 5762306a36Sopenharmony_ci#include <linux/bitops.h> 5862306a36Sopenharmony_ci#include <linux/platform_device.h> 5962306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 6062306a36Sopenharmony_ci#include <linux/of.h> 6162306a36Sopenharmony_ci#include <linux/of_device.h> 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci#include "gpiolib.h" 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic void bgpio_write8(void __iomem *reg, unsigned long data) 6662306a36Sopenharmony_ci{ 6762306a36Sopenharmony_ci writeb(data, reg); 6862306a36Sopenharmony_ci} 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_cistatic unsigned long bgpio_read8(void __iomem *reg) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci return readb(reg); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void bgpio_write16(void __iomem *reg, unsigned long data) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci writew(data, reg); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic unsigned long bgpio_read16(void __iomem *reg) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci return readw(reg); 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistatic void bgpio_write32(void __iomem *reg, unsigned long data) 8662306a36Sopenharmony_ci{ 8762306a36Sopenharmony_ci writel(data, reg); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic unsigned long bgpio_read32(void __iomem *reg) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci return readl(reg); 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#if BITS_PER_LONG >= 64 9662306a36Sopenharmony_cistatic void bgpio_write64(void __iomem *reg, unsigned long data) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci writeq(data, reg); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic unsigned long bgpio_read64(void __iomem *reg) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci return readq(reg); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci#endif /* BITS_PER_LONG >= 64 */ 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistatic void bgpio_write16be(void __iomem *reg, unsigned long data) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci iowrite16be(data, reg); 11062306a36Sopenharmony_ci} 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_cistatic unsigned long bgpio_read16be(void __iomem *reg) 11362306a36Sopenharmony_ci{ 11462306a36Sopenharmony_ci return ioread16be(reg); 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_cistatic void bgpio_write32be(void __iomem *reg, unsigned long data) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci iowrite32be(data, reg); 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic unsigned long bgpio_read32be(void __iomem *reg) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci return ioread32be(reg); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic unsigned long bgpio_line2mask(struct gpio_chip *gc, unsigned int line) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci if (gc->be_bits) 13062306a36Sopenharmony_ci return BIT(gc->bgpio_bits - 1 - line); 13162306a36Sopenharmony_ci return BIT(line); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int bgpio_get_set(struct gpio_chip *gc, unsigned int gpio) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci unsigned long pinmask = bgpio_line2mask(gc, gpio); 13762306a36Sopenharmony_ci bool dir = !!(gc->bgpio_dir & pinmask); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (dir) 14062306a36Sopenharmony_ci return !!(gc->read_reg(gc->reg_set) & pinmask); 14162306a36Sopenharmony_ci else 14262306a36Sopenharmony_ci return !!(gc->read_reg(gc->reg_dat) & pinmask); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * This assumes that the bits in the GPIO register are in native endianness. 14762306a36Sopenharmony_ci * We only assign the function pointer if we have that. 14862306a36Sopenharmony_ci */ 14962306a36Sopenharmony_cistatic int bgpio_get_set_multiple(struct gpio_chip *gc, unsigned long *mask, 15062306a36Sopenharmony_ci unsigned long *bits) 15162306a36Sopenharmony_ci{ 15262306a36Sopenharmony_ci unsigned long get_mask = 0; 15362306a36Sopenharmony_ci unsigned long set_mask = 0; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci /* Make sure we first clear any bits that are zero when we read the register */ 15662306a36Sopenharmony_ci *bits &= ~*mask; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci set_mask = *mask & gc->bgpio_dir; 15962306a36Sopenharmony_ci get_mask = *mask & ~gc->bgpio_dir; 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (set_mask) 16262306a36Sopenharmony_ci *bits |= gc->read_reg(gc->reg_set) & set_mask; 16362306a36Sopenharmony_ci if (get_mask) 16462306a36Sopenharmony_ci *bits |= gc->read_reg(gc->reg_dat) & get_mask; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic int bgpio_get(struct gpio_chip *gc, unsigned int gpio) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci return !!(gc->read_reg(gc->reg_dat) & bgpio_line2mask(gc, gpio)); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci/* 17562306a36Sopenharmony_ci * This only works if the bits in the GPIO register are in native endianness. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic int bgpio_get_multiple(struct gpio_chip *gc, unsigned long *mask, 17862306a36Sopenharmony_ci unsigned long *bits) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci /* Make sure we first clear any bits that are zero when we read the register */ 18162306a36Sopenharmony_ci *bits &= ~*mask; 18262306a36Sopenharmony_ci *bits |= gc->read_reg(gc->reg_dat) & *mask; 18362306a36Sopenharmony_ci return 0; 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * With big endian mirrored bit order it becomes more tedious. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic int bgpio_get_multiple_be(struct gpio_chip *gc, unsigned long *mask, 19062306a36Sopenharmony_ci unsigned long *bits) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci unsigned long readmask = 0; 19362306a36Sopenharmony_ci unsigned long val; 19462306a36Sopenharmony_ci int bit; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* Make sure we first clear any bits that are zero when we read the register */ 19762306a36Sopenharmony_ci *bits &= ~*mask; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci /* Create a mirrored mask */ 20062306a36Sopenharmony_ci for_each_set_bit(bit, mask, gc->ngpio) 20162306a36Sopenharmony_ci readmask |= bgpio_line2mask(gc, bit); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci /* Read the register */ 20462306a36Sopenharmony_ci val = gc->read_reg(gc->reg_dat) & readmask; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* 20762306a36Sopenharmony_ci * Mirror the result into the "bits" result, this will give line 0 20862306a36Sopenharmony_ci * in bit 0 ... line 31 in bit 31 for a 32bit register. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_ci for_each_set_bit(bit, &val, gc->ngpio) 21162306a36Sopenharmony_ci *bits |= bgpio_line2mask(gc, bit); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return 0; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic void bgpio_set_none(struct gpio_chip *gc, unsigned int gpio, int val) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic void bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci unsigned long mask = bgpio_line2mask(gc, gpio); 22362306a36Sopenharmony_ci unsigned long flags; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci raw_spin_lock_irqsave(&gc->bgpio_lock, flags); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (val) 22862306a36Sopenharmony_ci gc->bgpio_data |= mask; 22962306a36Sopenharmony_ci else 23062306a36Sopenharmony_ci gc->bgpio_data &= ~mask; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci gc->write_reg(gc->reg_dat, gc->bgpio_data); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic void bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio, 23862306a36Sopenharmony_ci int val) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci unsigned long mask = bgpio_line2mask(gc, gpio); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci if (val) 24362306a36Sopenharmony_ci gc->write_reg(gc->reg_set, mask); 24462306a36Sopenharmony_ci else 24562306a36Sopenharmony_ci gc->write_reg(gc->reg_clr, mask); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci unsigned long mask = bgpio_line2mask(gc, gpio); 25162306a36Sopenharmony_ci unsigned long flags; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci raw_spin_lock_irqsave(&gc->bgpio_lock, flags); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (val) 25662306a36Sopenharmony_ci gc->bgpio_data |= mask; 25762306a36Sopenharmony_ci else 25862306a36Sopenharmony_ci gc->bgpio_data &= ~mask; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci gc->write_reg(gc->reg_set, gc->bgpio_data); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic void bgpio_multiple_get_masks(struct gpio_chip *gc, 26662306a36Sopenharmony_ci unsigned long *mask, unsigned long *bits, 26762306a36Sopenharmony_ci unsigned long *set_mask, 26862306a36Sopenharmony_ci unsigned long *clear_mask) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci int i; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci *set_mask = 0; 27362306a36Sopenharmony_ci *clear_mask = 0; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci for_each_set_bit(i, mask, gc->bgpio_bits) { 27662306a36Sopenharmony_ci if (test_bit(i, bits)) 27762306a36Sopenharmony_ci *set_mask |= bgpio_line2mask(gc, i); 27862306a36Sopenharmony_ci else 27962306a36Sopenharmony_ci *clear_mask |= bgpio_line2mask(gc, i); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void bgpio_set_multiple_single_reg(struct gpio_chip *gc, 28462306a36Sopenharmony_ci unsigned long *mask, 28562306a36Sopenharmony_ci unsigned long *bits, 28662306a36Sopenharmony_ci void __iomem *reg) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci unsigned long set_mask, clear_mask; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci raw_spin_lock_irqsave(&gc->bgpio_lock, flags); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci gc->bgpio_data |= set_mask; 29662306a36Sopenharmony_ci gc->bgpio_data &= ~clear_mask; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci gc->write_reg(reg, gc->bgpio_data); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask, 30462306a36Sopenharmony_ci unsigned long *bits) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_dat); 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_cistatic void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask, 31062306a36Sopenharmony_ci unsigned long *bits) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci bgpio_set_multiple_single_reg(gc, mask, bits, gc->reg_set); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void bgpio_set_multiple_with_clear(struct gpio_chip *gc, 31662306a36Sopenharmony_ci unsigned long *mask, 31762306a36Sopenharmony_ci unsigned long *bits) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci unsigned long set_mask, clear_mask; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (set_mask) 32462306a36Sopenharmony_ci gc->write_reg(gc->reg_set, set_mask); 32562306a36Sopenharmony_ci if (clear_mask) 32662306a36Sopenharmony_ci gc->write_reg(gc->reg_clr, clear_mask); 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_cistatic int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return 0; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int bgpio_dir_out_err(struct gpio_chip *gc, unsigned int gpio, 33562306a36Sopenharmony_ci int val) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci return -EINVAL; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic int bgpio_simple_dir_out(struct gpio_chip *gc, unsigned int gpio, 34162306a36Sopenharmony_ci int val) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci gc->set(gc, gpio, val); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci return 0; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci unsigned long flags; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci raw_spin_lock_irqsave(&gc->bgpio_lock, flags); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (gc->reg_dir_in) 35762306a36Sopenharmony_ci gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); 35862306a36Sopenharmony_ci if (gc->reg_dir_out) 35962306a36Sopenharmony_ci gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci /* Return 0 if output, 1 if input */ 36962306a36Sopenharmony_ci if (gc->bgpio_dir_unreadable) { 37062306a36Sopenharmony_ci if (gc->bgpio_dir & bgpio_line2mask(gc, gpio)) 37162306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 37262306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci if (gc->reg_dir_out) { 37662306a36Sopenharmony_ci if (gc->read_reg(gc->reg_dir_out) & bgpio_line2mask(gc, gpio)) 37762306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 37862306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (gc->reg_dir_in) 38262306a36Sopenharmony_ci if (!(gc->read_reg(gc->reg_dir_in) & bgpio_line2mask(gc, gpio))) 38362306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) 38962306a36Sopenharmony_ci{ 39062306a36Sopenharmony_ci unsigned long flags; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci raw_spin_lock_irqsave(&gc->bgpio_lock, flags); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci gc->bgpio_dir |= bgpio_line2mask(gc, gpio); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (gc->reg_dir_in) 39762306a36Sopenharmony_ci gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); 39862306a36Sopenharmony_ci if (gc->reg_dir_out) 39962306a36Sopenharmony_ci gc->write_reg(gc->reg_dir_out, gc->bgpio_dir); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio, 40562306a36Sopenharmony_ci int val) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci bgpio_dir_out(gc, gpio, val); 40862306a36Sopenharmony_ci gc->set(gc, gpio, val); 40962306a36Sopenharmony_ci return 0; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio, 41362306a36Sopenharmony_ci int val) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci gc->set(gc, gpio, val); 41662306a36Sopenharmony_ci bgpio_dir_out(gc, gpio, val); 41762306a36Sopenharmony_ci return 0; 41862306a36Sopenharmony_ci} 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cistatic int bgpio_setup_accessors(struct device *dev, 42162306a36Sopenharmony_ci struct gpio_chip *gc, 42262306a36Sopenharmony_ci bool byte_be) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci switch (gc->bgpio_bits) { 42662306a36Sopenharmony_ci case 8: 42762306a36Sopenharmony_ci gc->read_reg = bgpio_read8; 42862306a36Sopenharmony_ci gc->write_reg = bgpio_write8; 42962306a36Sopenharmony_ci break; 43062306a36Sopenharmony_ci case 16: 43162306a36Sopenharmony_ci if (byte_be) { 43262306a36Sopenharmony_ci gc->read_reg = bgpio_read16be; 43362306a36Sopenharmony_ci gc->write_reg = bgpio_write16be; 43462306a36Sopenharmony_ci } else { 43562306a36Sopenharmony_ci gc->read_reg = bgpio_read16; 43662306a36Sopenharmony_ci gc->write_reg = bgpio_write16; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci break; 43962306a36Sopenharmony_ci case 32: 44062306a36Sopenharmony_ci if (byte_be) { 44162306a36Sopenharmony_ci gc->read_reg = bgpio_read32be; 44262306a36Sopenharmony_ci gc->write_reg = bgpio_write32be; 44362306a36Sopenharmony_ci } else { 44462306a36Sopenharmony_ci gc->read_reg = bgpio_read32; 44562306a36Sopenharmony_ci gc->write_reg = bgpio_write32; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci break; 44862306a36Sopenharmony_ci#if BITS_PER_LONG >= 64 44962306a36Sopenharmony_ci case 64: 45062306a36Sopenharmony_ci if (byte_be) { 45162306a36Sopenharmony_ci dev_err(dev, 45262306a36Sopenharmony_ci "64 bit big endian byte order unsupported\n"); 45362306a36Sopenharmony_ci return -EINVAL; 45462306a36Sopenharmony_ci } else { 45562306a36Sopenharmony_ci gc->read_reg = bgpio_read64; 45662306a36Sopenharmony_ci gc->write_reg = bgpio_write64; 45762306a36Sopenharmony_ci } 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci#endif /* BITS_PER_LONG >= 64 */ 46062306a36Sopenharmony_ci default: 46162306a36Sopenharmony_ci dev_err(dev, "unsupported data width %u bits\n", gc->bgpio_bits); 46262306a36Sopenharmony_ci return -EINVAL; 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return 0; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/* 46962306a36Sopenharmony_ci * Create the device and allocate the resources. For setting GPIO's there are 47062306a36Sopenharmony_ci * three supported configurations: 47162306a36Sopenharmony_ci * 47262306a36Sopenharmony_ci * - single input/output register resource (named "dat"). 47362306a36Sopenharmony_ci * - set/clear pair (named "set" and "clr"). 47462306a36Sopenharmony_ci * - single output register resource and single input resource ("set" and 47562306a36Sopenharmony_ci * dat"). 47662306a36Sopenharmony_ci * 47762306a36Sopenharmony_ci * For the single output register, this drives a 1 by setting a bit and a zero 47862306a36Sopenharmony_ci * by clearing a bit. For the set clr pair, this drives a 1 by setting a bit 47962306a36Sopenharmony_ci * in the set register and clears it by setting a bit in the clear register. 48062306a36Sopenharmony_ci * The configuration is detected by which resources are present. 48162306a36Sopenharmony_ci * 48262306a36Sopenharmony_ci * For setting the GPIO direction, there are three supported configurations: 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * - simple bidirection GPIO that requires no configuration. 48562306a36Sopenharmony_ci * - an output direction register (named "dirout") where a 1 bit 48662306a36Sopenharmony_ci * indicates the GPIO is an output. 48762306a36Sopenharmony_ci * - an input direction register (named "dirin") where a 1 bit indicates 48862306a36Sopenharmony_ci * the GPIO is an input. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_cistatic int bgpio_setup_io(struct gpio_chip *gc, 49162306a36Sopenharmony_ci void __iomem *dat, 49262306a36Sopenharmony_ci void __iomem *set, 49362306a36Sopenharmony_ci void __iomem *clr, 49462306a36Sopenharmony_ci unsigned long flags) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci gc->reg_dat = dat; 49862306a36Sopenharmony_ci if (!gc->reg_dat) 49962306a36Sopenharmony_ci return -EINVAL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (set && clr) { 50262306a36Sopenharmony_ci gc->reg_set = set; 50362306a36Sopenharmony_ci gc->reg_clr = clr; 50462306a36Sopenharmony_ci gc->set = bgpio_set_with_clear; 50562306a36Sopenharmony_ci gc->set_multiple = bgpio_set_multiple_with_clear; 50662306a36Sopenharmony_ci } else if (set && !clr) { 50762306a36Sopenharmony_ci gc->reg_set = set; 50862306a36Sopenharmony_ci gc->set = bgpio_set_set; 50962306a36Sopenharmony_ci gc->set_multiple = bgpio_set_multiple_set; 51062306a36Sopenharmony_ci } else if (flags & BGPIOF_NO_OUTPUT) { 51162306a36Sopenharmony_ci gc->set = bgpio_set_none; 51262306a36Sopenharmony_ci gc->set_multiple = NULL; 51362306a36Sopenharmony_ci } else { 51462306a36Sopenharmony_ci gc->set = bgpio_set; 51562306a36Sopenharmony_ci gc->set_multiple = bgpio_set_multiple; 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci if (!(flags & BGPIOF_UNREADABLE_REG_SET) && 51962306a36Sopenharmony_ci (flags & BGPIOF_READ_OUTPUT_REG_SET)) { 52062306a36Sopenharmony_ci gc->get = bgpio_get_set; 52162306a36Sopenharmony_ci if (!gc->be_bits) 52262306a36Sopenharmony_ci gc->get_multiple = bgpio_get_set_multiple; 52362306a36Sopenharmony_ci /* 52462306a36Sopenharmony_ci * We deliberately avoid assigning the ->get_multiple() call 52562306a36Sopenharmony_ci * for big endian mirrored registers which are ALSO reflecting 52662306a36Sopenharmony_ci * their value in the set register when used as output. It is 52762306a36Sopenharmony_ci * simply too much complexity, let the GPIO core fall back to 52862306a36Sopenharmony_ci * reading each line individually in that fringe case. 52962306a36Sopenharmony_ci */ 53062306a36Sopenharmony_ci } else { 53162306a36Sopenharmony_ci gc->get = bgpio_get; 53262306a36Sopenharmony_ci if (gc->be_bits) 53362306a36Sopenharmony_ci gc->get_multiple = bgpio_get_multiple_be; 53462306a36Sopenharmony_ci else 53562306a36Sopenharmony_ci gc->get_multiple = bgpio_get_multiple; 53662306a36Sopenharmony_ci } 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int bgpio_setup_direction(struct gpio_chip *gc, 54262306a36Sopenharmony_ci void __iomem *dirout, 54362306a36Sopenharmony_ci void __iomem *dirin, 54462306a36Sopenharmony_ci unsigned long flags) 54562306a36Sopenharmony_ci{ 54662306a36Sopenharmony_ci if (dirout || dirin) { 54762306a36Sopenharmony_ci gc->reg_dir_out = dirout; 54862306a36Sopenharmony_ci gc->reg_dir_in = dirin; 54962306a36Sopenharmony_ci if (flags & BGPIOF_NO_SET_ON_INPUT) 55062306a36Sopenharmony_ci gc->direction_output = bgpio_dir_out_dir_first; 55162306a36Sopenharmony_ci else 55262306a36Sopenharmony_ci gc->direction_output = bgpio_dir_out_val_first; 55362306a36Sopenharmony_ci gc->direction_input = bgpio_dir_in; 55462306a36Sopenharmony_ci gc->get_direction = bgpio_get_dir; 55562306a36Sopenharmony_ci } else { 55662306a36Sopenharmony_ci if (flags & BGPIOF_NO_OUTPUT) 55762306a36Sopenharmony_ci gc->direction_output = bgpio_dir_out_err; 55862306a36Sopenharmony_ci else 55962306a36Sopenharmony_ci gc->direction_output = bgpio_simple_dir_out; 56062306a36Sopenharmony_ci gc->direction_input = bgpio_simple_dir_in; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic int bgpio_request(struct gpio_chip *chip, unsigned gpio_pin) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci if (gpio_pin < chip->ngpio) 56962306a36Sopenharmony_ci return 0; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci return -EINVAL; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci/** 57562306a36Sopenharmony_ci * bgpio_init() - Initialize generic GPIO accessor functions 57662306a36Sopenharmony_ci * @gc: the GPIO chip to set up 57762306a36Sopenharmony_ci * @dev: the parent device of the new GPIO chip (compulsory) 57862306a36Sopenharmony_ci * @sz: the size (width) of the MMIO registers in bytes, typically 1, 2 or 4 57962306a36Sopenharmony_ci * @dat: MMIO address for the register to READ the value of the GPIO lines, it 58062306a36Sopenharmony_ci * is expected that a 1 in the corresponding bit in this register means the 58162306a36Sopenharmony_ci * line is asserted 58262306a36Sopenharmony_ci * @set: MMIO address for the register to SET the value of the GPIO lines, it is 58362306a36Sopenharmony_ci * expected that we write the line with 1 in this register to drive the GPIO line 58462306a36Sopenharmony_ci * high. 58562306a36Sopenharmony_ci * @clr: MMIO address for the register to CLEAR the value of the GPIO lines, it is 58662306a36Sopenharmony_ci * expected that we write the line with 1 in this register to drive the GPIO line 58762306a36Sopenharmony_ci * low. It is allowed to leave this address as NULL, in that case the SET register 58862306a36Sopenharmony_ci * will be assumed to also clear the GPIO lines, by actively writing the line 58962306a36Sopenharmony_ci * with 0. 59062306a36Sopenharmony_ci * @dirout: MMIO address for the register to set the line as OUTPUT. It is assumed 59162306a36Sopenharmony_ci * that setting a line to 1 in this register will turn that line into an 59262306a36Sopenharmony_ci * output line. Conversely, setting the line to 0 will turn that line into 59362306a36Sopenharmony_ci * an input. 59462306a36Sopenharmony_ci * @dirin: MMIO address for the register to set this line as INPUT. It is assumed 59562306a36Sopenharmony_ci * that setting a line to 1 in this register will turn that line into an 59662306a36Sopenharmony_ci * input line. Conversely, setting the line to 0 will turn that line into 59762306a36Sopenharmony_ci * an output. 59862306a36Sopenharmony_ci * @flags: Different flags that will affect the behaviour of the device, such as 59962306a36Sopenharmony_ci * endianness etc. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ciint bgpio_init(struct gpio_chip *gc, struct device *dev, 60262306a36Sopenharmony_ci unsigned long sz, void __iomem *dat, void __iomem *set, 60362306a36Sopenharmony_ci void __iomem *clr, void __iomem *dirout, void __iomem *dirin, 60462306a36Sopenharmony_ci unsigned long flags) 60562306a36Sopenharmony_ci{ 60662306a36Sopenharmony_ci int ret; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (!is_power_of_2(sz)) 60962306a36Sopenharmony_ci return -EINVAL; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci gc->bgpio_bits = sz * 8; 61262306a36Sopenharmony_ci if (gc->bgpio_bits > BITS_PER_LONG) 61362306a36Sopenharmony_ci return -EINVAL; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci raw_spin_lock_init(&gc->bgpio_lock); 61662306a36Sopenharmony_ci gc->parent = dev; 61762306a36Sopenharmony_ci gc->label = dev_name(dev); 61862306a36Sopenharmony_ci gc->base = -1; 61962306a36Sopenharmony_ci gc->request = bgpio_request; 62062306a36Sopenharmony_ci gc->be_bits = !!(flags & BGPIOF_BIG_ENDIAN); 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ret = gpiochip_get_ngpios(gc, dev); 62362306a36Sopenharmony_ci if (ret) 62462306a36Sopenharmony_ci gc->ngpio = gc->bgpio_bits; 62562306a36Sopenharmony_ci else 62662306a36Sopenharmony_ci gc->bgpio_bits = roundup_pow_of_two(round_up(gc->ngpio, 8)); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci ret = bgpio_setup_io(gc, dat, set, clr, flags); 62962306a36Sopenharmony_ci if (ret) 63062306a36Sopenharmony_ci return ret; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci ret = bgpio_setup_accessors(dev, gc, flags & BGPIOF_BIG_ENDIAN_BYTE_ORDER); 63362306a36Sopenharmony_ci if (ret) 63462306a36Sopenharmony_ci return ret; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci ret = bgpio_setup_direction(gc, dirout, dirin, flags); 63762306a36Sopenharmony_ci if (ret) 63862306a36Sopenharmony_ci return ret; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci gc->bgpio_data = gc->read_reg(gc->reg_dat); 64162306a36Sopenharmony_ci if (gc->set == bgpio_set_set && 64262306a36Sopenharmony_ci !(flags & BGPIOF_UNREADABLE_REG_SET)) 64362306a36Sopenharmony_ci gc->bgpio_data = gc->read_reg(gc->reg_set); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (flags & BGPIOF_UNREADABLE_REG_DIR) 64662306a36Sopenharmony_ci gc->bgpio_dir_unreadable = true; 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * Inspect hardware to find initial direction setting. 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci if ((gc->reg_dir_out || gc->reg_dir_in) && 65262306a36Sopenharmony_ci !(flags & BGPIOF_UNREADABLE_REG_DIR)) { 65362306a36Sopenharmony_ci if (gc->reg_dir_out) 65462306a36Sopenharmony_ci gc->bgpio_dir = gc->read_reg(gc->reg_dir_out); 65562306a36Sopenharmony_ci else if (gc->reg_dir_in) 65662306a36Sopenharmony_ci gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in); 65762306a36Sopenharmony_ci /* 65862306a36Sopenharmony_ci * If we have two direction registers, synchronise 65962306a36Sopenharmony_ci * input setting to output setting, the library 66062306a36Sopenharmony_ci * can not handle a line being input and output at 66162306a36Sopenharmony_ci * the same time. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_ci if (gc->reg_dir_out && gc->reg_dir_in) 66462306a36Sopenharmony_ci gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci return ret; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(bgpio_init); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_GPIO_GENERIC_PLATFORM) 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic void __iomem *bgpio_map(struct platform_device *pdev, 67462306a36Sopenharmony_ci const char *name, 67562306a36Sopenharmony_ci resource_size_t sane_sz) 67662306a36Sopenharmony_ci{ 67762306a36Sopenharmony_ci struct resource *r; 67862306a36Sopenharmony_ci resource_size_t sz; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci r = platform_get_resource_byname(pdev, IORESOURCE_MEM, name); 68162306a36Sopenharmony_ci if (!r) 68262306a36Sopenharmony_ci return NULL; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci sz = resource_size(r); 68562306a36Sopenharmony_ci if (sz != sane_sz) 68662306a36Sopenharmony_ci return IOMEM_ERR_PTR(-EINVAL); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci return devm_ioremap_resource(&pdev->dev, r); 68962306a36Sopenharmony_ci} 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci#ifdef CONFIG_OF 69262306a36Sopenharmony_cistatic const struct of_device_id bgpio_of_match[] = { 69362306a36Sopenharmony_ci { .compatible = "brcm,bcm6345-gpio" }, 69462306a36Sopenharmony_ci { .compatible = "wd,mbl-gpio" }, 69562306a36Sopenharmony_ci { .compatible = "ni,169445-nand-gpio" }, 69662306a36Sopenharmony_ci { } 69762306a36Sopenharmony_ci}; 69862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, bgpio_of_match); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, 70162306a36Sopenharmony_ci unsigned long *flags) 70262306a36Sopenharmony_ci{ 70362306a36Sopenharmony_ci struct bgpio_pdata *pdata; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci if (!of_match_device(bgpio_of_match, &pdev->dev)) 70662306a36Sopenharmony_ci return NULL; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci pdata = devm_kzalloc(&pdev->dev, sizeof(struct bgpio_pdata), 70962306a36Sopenharmony_ci GFP_KERNEL); 71062306a36Sopenharmony_ci if (!pdata) 71162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci pdata->base = -1; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (of_device_is_big_endian(pdev->dev.of_node)) 71662306a36Sopenharmony_ci *flags |= BGPIOF_BIG_ENDIAN_BYTE_ORDER; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (of_property_read_bool(pdev->dev.of_node, "no-output")) 71962306a36Sopenharmony_ci *flags |= BGPIOF_NO_OUTPUT; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci return pdata; 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ci#else 72462306a36Sopenharmony_cistatic struct bgpio_pdata *bgpio_parse_dt(struct platform_device *pdev, 72562306a36Sopenharmony_ci unsigned long *flags) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci return NULL; 72862306a36Sopenharmony_ci} 72962306a36Sopenharmony_ci#endif /* CONFIG_OF */ 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_cistatic int bgpio_pdev_probe(struct platform_device *pdev) 73262306a36Sopenharmony_ci{ 73362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 73462306a36Sopenharmony_ci struct resource *r; 73562306a36Sopenharmony_ci void __iomem *dat; 73662306a36Sopenharmony_ci void __iomem *set; 73762306a36Sopenharmony_ci void __iomem *clr; 73862306a36Sopenharmony_ci void __iomem *dirout; 73962306a36Sopenharmony_ci void __iomem *dirin; 74062306a36Sopenharmony_ci unsigned long sz; 74162306a36Sopenharmony_ci unsigned long flags = 0; 74262306a36Sopenharmony_ci int err; 74362306a36Sopenharmony_ci struct gpio_chip *gc; 74462306a36Sopenharmony_ci struct bgpio_pdata *pdata; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci pdata = bgpio_parse_dt(pdev, &flags); 74762306a36Sopenharmony_ci if (IS_ERR(pdata)) 74862306a36Sopenharmony_ci return PTR_ERR(pdata); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (!pdata) { 75162306a36Sopenharmony_ci pdata = dev_get_platdata(dev); 75262306a36Sopenharmony_ci flags = pdev->id_entry->driver_data; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat"); 75662306a36Sopenharmony_ci if (!r) 75762306a36Sopenharmony_ci return -EINVAL; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci sz = resource_size(r); 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci dat = bgpio_map(pdev, "dat", sz); 76262306a36Sopenharmony_ci if (IS_ERR(dat)) 76362306a36Sopenharmony_ci return PTR_ERR(dat); 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci set = bgpio_map(pdev, "set", sz); 76662306a36Sopenharmony_ci if (IS_ERR(set)) 76762306a36Sopenharmony_ci return PTR_ERR(set); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci clr = bgpio_map(pdev, "clr", sz); 77062306a36Sopenharmony_ci if (IS_ERR(clr)) 77162306a36Sopenharmony_ci return PTR_ERR(clr); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci dirout = bgpio_map(pdev, "dirout", sz); 77462306a36Sopenharmony_ci if (IS_ERR(dirout)) 77562306a36Sopenharmony_ci return PTR_ERR(dirout); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci dirin = bgpio_map(pdev, "dirin", sz); 77862306a36Sopenharmony_ci if (IS_ERR(dirin)) 77962306a36Sopenharmony_ci return PTR_ERR(dirin); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci gc = devm_kzalloc(&pdev->dev, sizeof(*gc), GFP_KERNEL); 78262306a36Sopenharmony_ci if (!gc) 78362306a36Sopenharmony_ci return -ENOMEM; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci err = bgpio_init(gc, dev, sz, dat, set, clr, dirout, dirin, flags); 78662306a36Sopenharmony_ci if (err) 78762306a36Sopenharmony_ci return err; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci if (pdata) { 79062306a36Sopenharmony_ci if (pdata->label) 79162306a36Sopenharmony_ci gc->label = pdata->label; 79262306a36Sopenharmony_ci gc->base = pdata->base; 79362306a36Sopenharmony_ci if (pdata->ngpio > 0) 79462306a36Sopenharmony_ci gc->ngpio = pdata->ngpio; 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci platform_set_drvdata(pdev, gc); 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return devm_gpiochip_add_data(&pdev->dev, gc, NULL); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic const struct platform_device_id bgpio_id_table[] = { 80362306a36Sopenharmony_ci { 80462306a36Sopenharmony_ci .name = "basic-mmio-gpio", 80562306a36Sopenharmony_ci .driver_data = 0, 80662306a36Sopenharmony_ci }, { 80762306a36Sopenharmony_ci .name = "basic-mmio-gpio-be", 80862306a36Sopenharmony_ci .driver_data = BGPIOF_BIG_ENDIAN, 80962306a36Sopenharmony_ci }, 81062306a36Sopenharmony_ci { } 81162306a36Sopenharmony_ci}; 81262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(platform, bgpio_id_table); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic struct platform_driver bgpio_driver = { 81562306a36Sopenharmony_ci .driver = { 81662306a36Sopenharmony_ci .name = "basic-mmio-gpio", 81762306a36Sopenharmony_ci .of_match_table = of_match_ptr(bgpio_of_match), 81862306a36Sopenharmony_ci }, 81962306a36Sopenharmony_ci .id_table = bgpio_id_table, 82062306a36Sopenharmony_ci .probe = bgpio_pdev_probe, 82162306a36Sopenharmony_ci}; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_cimodule_platform_driver(bgpio_driver); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci#endif /* CONFIG_GPIO_GENERIC_PLATFORM */ 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for basic memory-mapped GPIO controllers"); 82862306a36Sopenharmony_ciMODULE_AUTHOR("Anton Vorontsov <cbouatmailru@gmail.com>"); 82962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 830