Commit 2e969d8a authored by Linus Walleij's avatar Linus Walleij

Merge tag 'gpio-fixes-for-v5.9-rc7' of...

Merge tag 'gpio-fixes-for-v5.9-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into fixes

gpio: fixes for v5.9-rc7

- fix uninitialized variable in gpio-pca953x
- enable all 160 lines and fix interrupt configuration in gpio-aspeed-gpio
- fix ast2600 bank properties in gpio-aspeed
parents 53c14e23 3e640b1e
...@@ -20,8 +20,9 @@ Required properties: ...@@ -20,8 +20,9 @@ Required properties:
- gpio-controller : Marks the device node as a GPIO controller - gpio-controller : Marks the device node as a GPIO controller
- interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt - interrupts : Interrupt specifier, see interrupt-controller/interrupts.txt
- interrupt-controller : Mark the GPIO controller as an interrupt-controller - interrupt-controller : Mark the GPIO controller as an interrupt-controller
- ngpios : number of GPIO lines, see gpio.txt - ngpios : number of *hardware* GPIO lines, see gpio.txt. This will expose
(should be multiple of 8, up to 80 pins) 2 software GPIOs per hardware GPIO: one for hardware input, one for hardware
output. Up to 80 pins, must be a multiple of 8.
- clocks : A phandle to the APB clock for SGPM clock division - clocks : A phandle to the APB clock for SGPM clock division
- bus-frequency : SGPM CLK frequency - bus-frequency : SGPM CLK frequency
......
...@@ -17,7 +17,17 @@ ...@@ -17,7 +17,17 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/string.h> #include <linux/string.h>
#define MAX_NR_SGPIO 80 /*
* MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
* slots within the clocked serial GPIO data). Since each HW GPIO is both an
* input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
* device.
*
* We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
* outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
*/
#define MAX_NR_HW_SGPIO 80
#define SGPIO_OUTPUT_OFFSET MAX_NR_HW_SGPIO
#define ASPEED_SGPIO_CTRL 0x54 #define ASPEED_SGPIO_CTRL 0x54
...@@ -30,8 +40,8 @@ struct aspeed_sgpio { ...@@ -30,8 +40,8 @@ struct aspeed_sgpio {
struct clk *pclk; struct clk *pclk;
spinlock_t lock; spinlock_t lock;
void __iomem *base; void __iomem *base;
uint32_t dir_in[3];
int irq; int irq;
int n_sgpio;
}; };
struct aspeed_sgpio_bank { struct aspeed_sgpio_bank {
...@@ -111,31 +121,69 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio, ...@@ -111,31 +121,69 @@ static void __iomem *bank_reg(struct aspeed_sgpio *gpio,
} }
} }
#define GPIO_BANK(x) ((x) >> 5) #define GPIO_BANK(x) ((x % SGPIO_OUTPUT_OFFSET) >> 5)
#define GPIO_OFFSET(x) ((x) & 0x1f) #define GPIO_OFFSET(x) ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
#define GPIO_BIT(x) BIT(GPIO_OFFSET(x)) #define GPIO_BIT(x) BIT(GPIO_OFFSET(x))
static const struct aspeed_sgpio_bank *to_bank(unsigned int offset) static const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
{ {
unsigned int bank = GPIO_BANK(offset); unsigned int bank;
bank = GPIO_BANK(offset);
WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks)); WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
return &aspeed_sgpio_banks[bank]; return &aspeed_sgpio_banks[bank];
} }
static int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned int ngpios)
{
struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
int n = sgpio->n_sgpio;
int c = SGPIO_OUTPUT_OFFSET - n;
WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
/* input GPIOs in the lower range */
bitmap_set(valid_mask, 0, n);
bitmap_clear(valid_mask, n, c);
/* output GPIOS above SGPIO_OUTPUT_OFFSET */
bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
return 0;
}
static void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
unsigned long *valid_mask, unsigned int ngpios)
{
struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
int n = sgpio->n_sgpio;
WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
/* input GPIOs in the lower range */
bitmap_set(valid_mask, 0, n);
bitmap_clear(valid_mask, n, ngpios - n);
}
static bool aspeed_sgpio_is_input(unsigned int offset)
{
return offset < SGPIO_OUTPUT_OFFSET;
}
static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
{ {
struct aspeed_sgpio *gpio = gpiochip_get_data(gc); struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
const struct aspeed_sgpio_bank *bank = to_bank(offset); const struct aspeed_sgpio_bank *bank = to_bank(offset);
unsigned long flags; unsigned long flags;
enum aspeed_sgpio_reg reg; enum aspeed_sgpio_reg reg;
bool is_input;
int rc = 0; int rc = 0;
spin_lock_irqsave(&gpio->lock, flags); spin_lock_irqsave(&gpio->lock, flags);
is_input = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset); reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
reg = is_input ? reg_val : reg_rdata;
rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset)); rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
spin_unlock_irqrestore(&gpio->lock, flags); spin_unlock_irqrestore(&gpio->lock, flags);
...@@ -143,22 +191,31 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset) ...@@ -143,22 +191,31 @@ static int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
return rc; return rc;
} }
static void sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val) static int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
{ {
struct aspeed_sgpio *gpio = gpiochip_get_data(gc); struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
const struct aspeed_sgpio_bank *bank = to_bank(offset); const struct aspeed_sgpio_bank *bank = to_bank(offset);
void __iomem *addr; void __iomem *addr_r, *addr_w;
u32 reg = 0; u32 reg = 0;
addr = bank_reg(gpio, bank, reg_val); if (aspeed_sgpio_is_input(offset))
reg = ioread32(addr); return -EINVAL;
/* Since this is an output, read the cached value from rdata, then
* update val. */
addr_r = bank_reg(gpio, bank, reg_rdata);
addr_w = bank_reg(gpio, bank, reg_val);
reg = ioread32(addr_r);
if (val) if (val)
reg |= GPIO_BIT(offset); reg |= GPIO_BIT(offset);
else else
reg &= ~GPIO_BIT(offset); reg &= ~GPIO_BIT(offset);
iowrite32(reg, addr); iowrite32(reg, addr_w);
return 0;
} }
static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
...@@ -175,43 +232,28 @@ static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val) ...@@ -175,43 +232,28 @@ static void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset) static int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
{ {
struct aspeed_sgpio *gpio = gpiochip_get_data(gc); return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
unsigned long flags;
spin_lock_irqsave(&gpio->lock, flags);
gpio->dir_in[GPIO_BANK(offset)] |= GPIO_BIT(offset);
spin_unlock_irqrestore(&gpio->lock, flags);
return 0;
} }
static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val) static int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
{ {
struct aspeed_sgpio *gpio = gpiochip_get_data(gc); struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
unsigned long flags; unsigned long flags;
int rc;
spin_lock_irqsave(&gpio->lock, flags); /* No special action is required for setting the direction; we'll
* error-out in sgpio_set_value if this isn't an output GPIO */
gpio->dir_in[GPIO_BANK(offset)] &= ~GPIO_BIT(offset);
sgpio_set_value(gc, offset, val);
spin_lock_irqsave(&gpio->lock, flags);
rc = sgpio_set_value(gc, offset, val);
spin_unlock_irqrestore(&gpio->lock, flags); spin_unlock_irqrestore(&gpio->lock, flags);
return 0; return rc;
} }
static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset) static int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{ {
int dir_status; return !!aspeed_sgpio_is_input(offset);
struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
unsigned long flags;
spin_lock_irqsave(&gpio->lock, flags);
dir_status = gpio->dir_in[GPIO_BANK(offset)] & GPIO_BIT(offset);
spin_unlock_irqrestore(&gpio->lock, flags);
return dir_status;
} }
static void irqd_to_aspeed_sgpio_data(struct irq_data *d, static void irqd_to_aspeed_sgpio_data(struct irq_data *d,
...@@ -402,6 +444,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, ...@@ -402,6 +444,7 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
irq = &gpio->chip.irq; irq = &gpio->chip.irq;
irq->chip = &aspeed_sgpio_irqchip; irq->chip = &aspeed_sgpio_irqchip;
irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
irq->handler = handle_bad_irq; irq->handler = handle_bad_irq;
irq->default_type = IRQ_TYPE_NONE; irq->default_type = IRQ_TYPE_NONE;
irq->parent_handler = aspeed_sgpio_irq_handler; irq->parent_handler = aspeed_sgpio_irq_handler;
...@@ -409,17 +452,15 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio, ...@@ -409,17 +452,15 @@ static int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
irq->parents = &gpio->irq; irq->parents = &gpio->irq;
irq->num_parents = 1; irq->num_parents = 1;
/* set IRQ settings and Enable Interrupt */ /* Apply default IRQ settings */
for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) { for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
bank = &aspeed_sgpio_banks[i]; bank = &aspeed_sgpio_banks[i];
/* set falling or level-low irq */ /* set falling or level-low irq */
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0)); iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
/* trigger type is edge */ /* trigger type is edge */
iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1)); iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
/* dual edge trigger mode. */ /* single edge trigger */
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_type2)); iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
/* enable irq */
iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_enable));
} }
return 0; return 0;
...@@ -452,11 +493,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) ...@@ -452,11 +493,12 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
if (rc < 0) { if (rc < 0) {
dev_err(&pdev->dev, "Could not read ngpios property\n"); dev_err(&pdev->dev, "Could not read ngpios property\n");
return -EINVAL; return -EINVAL;
} else if (nr_gpios > MAX_NR_SGPIO) { } else if (nr_gpios > MAX_NR_HW_SGPIO) {
dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n", dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
MAX_NR_SGPIO, nr_gpios); MAX_NR_HW_SGPIO, nr_gpios);
return -EINVAL; return -EINVAL;
} }
gpio->n_sgpio = nr_gpios;
rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq); rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
if (rc < 0) { if (rc < 0) {
...@@ -497,7 +539,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) ...@@ -497,7 +539,8 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
spin_lock_init(&gpio->lock); spin_lock_init(&gpio->lock);
gpio->chip.parent = &pdev->dev; gpio->chip.parent = &pdev->dev;
gpio->chip.ngpio = nr_gpios; gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
gpio->chip.direction_input = aspeed_sgpio_dir_in; gpio->chip.direction_input = aspeed_sgpio_dir_in;
gpio->chip.direction_output = aspeed_sgpio_dir_out; gpio->chip.direction_output = aspeed_sgpio_dir_out;
gpio->chip.get_direction = aspeed_sgpio_get_direction; gpio->chip.get_direction = aspeed_sgpio_get_direction;
...@@ -509,9 +552,6 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev) ...@@ -509,9 +552,6 @@ static int __init aspeed_sgpio_probe(struct platform_device *pdev)
gpio->chip.label = dev_name(&pdev->dev); gpio->chip.label = dev_name(&pdev->dev);
gpio->chip.base = -1; gpio->chip.base = -1;
/* set all SGPIO pins as input (1). */
memset(gpio->dir_in, 0xff, sizeof(gpio->dir_in));
aspeed_sgpio_setup_irqs(gpio, pdev); aspeed_sgpio_setup_irqs(gpio, pdev);
rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
......
...@@ -1114,8 +1114,8 @@ static const struct aspeed_gpio_config ast2500_config = ...@@ -1114,8 +1114,8 @@ static const struct aspeed_gpio_config ast2500_config =
static const struct aspeed_bank_props ast2600_bank_props[] = { static const struct aspeed_bank_props ast2600_bank_props[] = {
/* input output */ /* input output */
{5, 0xffffffff, 0x0000ffff}, /* U/V/W/X */ {5, 0xffffffff, 0xffffff00}, /* U/V/W/X */
{6, 0xffff0000, 0x0fff0000}, /* Y/Z */ {6, 0x0000ffff, 0x0000ffff}, /* Y/Z */
{ }, { },
}; };
......
...@@ -814,7 +814,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid) ...@@ -814,7 +814,7 @@ static irqreturn_t pca953x_irq_handler(int irq, void *devid)
{ {
struct pca953x_chip *chip = devid; struct pca953x_chip *chip = devid;
struct gpio_chip *gc = &chip->gpio_chip; struct gpio_chip *gc = &chip->gpio_chip;
DECLARE_BITMAP(pending, MAX_LINE); DECLARE_BITMAP(pending, MAX_LINE) = {};
int level; int level;
bool ret; bool ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment