mirror of
https://github.com/raspberrypi/linux.git
synced 2025-12-06 01:49:46 +00:00
gpio_brcmstb: Allow to build for ARCH_BCM2835
gpio-brcmstb: Report the correct bank width
gpio: brcmstb: Use bank address as gpiochip label
If the path to the device node is used as gpiochip label then
gpio-brcmstb instances with multiple banks end up with duplicated
names. Instead, use a combination of the driver name with the physical
address of the bank, which is both unique and helpful for devmem
debugging.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
gpio: mmio: Add DIRECT mode for shared access
The generic MMIO GPIO library uses shadow registers for efficiency,
but this breaks attempts by raspi-gpio to change other GPIOs in the
same bank. Add a DIRECT mode that makes fewer assumptions about the
existing register contents, but note that genuinely simultaneous
accesses are likely to lose updates.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
gpio: brcmstb: Don't always clear interrupt mask
If the GPIO controller is not being used as an interrupt source
leave the interrupt mask register alone. On BCM2712 it might be used
to generate interrupts to the VPU firmware, and on other devices it
doesn't matter since no interrupts will be generated.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
gpio: brcmstb: Use dynamic GPIO base numbers
Forcing a gpiochip to have a fixed base number now leads to a warning
message. Remove the need to do so by calculating hwirq numbers based
on bank numbers.
Signed-off-by: Phil Elwell <phil@raspberrypi.com>
Fixes: 3b0213d56e ("gpio: Add GPIO support for Broadcom STB SoCs")
This commit is contained in:
@@ -632,6 +632,8 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
#if defined(CONFIG_MIPS) && defined(__BIG_ENDIAN)
|
||||
flags = BGPIOF_BIG_ENDIAN_BYTE_ORDER;
|
||||
#endif
|
||||
if (of_property_read_bool(np, "brcm,gpio-direct"))
|
||||
flags |= BGPIOF_REG_DIRECT;
|
||||
|
||||
of_property_for_each_u32(np, "brcm,gpio-bank-widths", bank_width) {
|
||||
struct brcmstb_gpio_bank *bank;
|
||||
@@ -680,7 +682,9 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
gc->owner = THIS_MODULE;
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "%pOF", np);
|
||||
gc->label = devm_kasprintf(dev, GFP_KERNEL, "gpio-brcmstb@%zx",
|
||||
(size_t)res->start +
|
||||
GIO_BANK_OFF(bank->id, 0));
|
||||
if (!gc->label) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
@@ -688,7 +692,7 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
gc->of_gpio_n_cells = 2;
|
||||
gc->of_xlate = brcmstb_gpio_of_xlate;
|
||||
/* not all ngpio lines are valid, will use bank width later */
|
||||
gc->ngpio = MAX_GPIO_PER_BANK;
|
||||
gc->ngpio = bank_width;
|
||||
gc->offset = bank->id * MAX_GPIO_PER_BANK;
|
||||
gc->request = gpiochip_generic_request;
|
||||
gc->free = gpiochip_generic_free;
|
||||
@@ -699,8 +703,10 @@ static int brcmstb_gpio_probe(struct platform_device *pdev)
|
||||
* Mask all interrupts by default, since wakeup interrupts may
|
||||
* be retained from S5 cold boot
|
||||
*/
|
||||
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
|
||||
if (priv->parent_irq > 0) {
|
||||
need_wakeup_event |= !!__brcmstb_gpio_get_active_irqs(bank);
|
||||
gc->write_reg(reg_base + GIO_MASK(bank->id), 0);
|
||||
}
|
||||
|
||||
err = gpiochip_add_data(gc, bank);
|
||||
if (err) {
|
||||
|
||||
@@ -235,6 +235,26 @@ static int bgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_direct(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
{
|
||||
unsigned long mask = bgpio_line2mask(gc, gpio);
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
gc->bgpio_data = gc->read_reg(gc->reg_dat);
|
||||
|
||||
if (val)
|
||||
gc->bgpio_data |= mask;
|
||||
else
|
||||
gc->bgpio_data &= ~mask;
|
||||
|
||||
gc->write_reg(gc->reg_dat, gc->bgpio_data);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_with_clear(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
@@ -337,6 +357,28 @@ static int bgpio_set_multiple_with_clear(struct gpio_chip *gc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_set_multiple_direct(struct gpio_chip *gc,
|
||||
unsigned long *mask,
|
||||
unsigned long *bits)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned long set_mask, clear_mask;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
bgpio_multiple_get_masks(gc, mask, bits, &set_mask, &clear_mask);
|
||||
|
||||
gc->bgpio_data = gc->read_reg(gc->reg_dat);
|
||||
|
||||
gc->bgpio_data |= set_mask;
|
||||
gc->bgpio_data &= ~clear_mask;
|
||||
|
||||
gc->write_reg(gc->reg_dat, gc->bgpio_data);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_dir_return(struct gpio_chip *gc, unsigned int gpio, bool dir_out)
|
||||
{
|
||||
if (!gc->bgpio_pinctrl)
|
||||
@@ -390,6 +432,29 @@ static int bgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
|
||||
return bgpio_dir_return(gc, gpio, false);
|
||||
}
|
||||
|
||||
static int bgpio_dir_in_direct(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
if (gc->reg_dir_in)
|
||||
gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in);
|
||||
if (gc->reg_dir_out)
|
||||
gc->bgpio_dir = gc->read_reg(gc->reg_dir_out);
|
||||
|
||||
gc->bgpio_dir &= ~bgpio_line2mask(gc, gpio);
|
||||
|
||||
if (gc->reg_dir_in)
|
||||
gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
|
||||
if (gc->reg_dir_out)
|
||||
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_get_dir(struct gpio_chip *gc, unsigned int gpio)
|
||||
{
|
||||
/* Return 0 if output, 1 if input */
|
||||
@@ -428,6 +493,28 @@ static void bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
static void bgpio_dir_out_direct(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||
|
||||
if (gc->reg_dir_in)
|
||||
gc->bgpio_dir = ~gc->read_reg(gc->reg_dir_in);
|
||||
if (gc->reg_dir_out)
|
||||
gc->bgpio_dir = gc->read_reg(gc->reg_dir_out);
|
||||
|
||||
gc->bgpio_dir |= bgpio_line2mask(gc, gpio);
|
||||
|
||||
if (gc->reg_dir_in)
|
||||
gc->write_reg(gc->reg_dir_in, ~gc->bgpio_dir);
|
||||
if (gc->reg_dir_out)
|
||||
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||
|
||||
raw_spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_dir_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
int val)
|
||||
{
|
||||
@@ -444,6 +531,22 @@ static int bgpio_dir_out_val_first(struct gpio_chip *gc, unsigned int gpio,
|
||||
return bgpio_dir_return(gc, gpio, true);
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_dir_first_direct(struct gpio_chip *gc,
|
||||
unsigned int gpio, int val)
|
||||
{
|
||||
bgpio_dir_out_direct(gc, gpio, val);
|
||||
gc->set(gc, gpio, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_dir_out_val_first_direct(struct gpio_chip *gc,
|
||||
unsigned int gpio, int val)
|
||||
{
|
||||
gc->set(gc, gpio, val);
|
||||
bgpio_dir_out_direct(gc, gpio, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgpio_setup_accessors(struct device *dev,
|
||||
struct gpio_chip *gc,
|
||||
bool byte_be)
|
||||
@@ -537,6 +640,9 @@ static int bgpio_setup_io(struct gpio_chip *gc,
|
||||
} else if (flags & BGPIOF_NO_OUTPUT) {
|
||||
gc->set = bgpio_set_none;
|
||||
gc->set_multiple = NULL;
|
||||
} else if (flags & BGPIOF_REG_DIRECT) {
|
||||
gc->set = bgpio_set_direct;
|
||||
gc->set_multiple = bgpio_set_multiple_direct;
|
||||
} else {
|
||||
gc->set = bgpio_set;
|
||||
gc->set_multiple = bgpio_set_multiple;
|
||||
@@ -573,11 +679,21 @@ static int bgpio_setup_direction(struct gpio_chip *gc,
|
||||
if (dirout || dirin) {
|
||||
gc->reg_dir_out = dirout;
|
||||
gc->reg_dir_in = dirin;
|
||||
if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
gc->direction_output = bgpio_dir_out_dir_first;
|
||||
else
|
||||
gc->direction_output = bgpio_dir_out_val_first;
|
||||
gc->direction_input = bgpio_dir_in;
|
||||
if (flags & BGPIOF_REG_DIRECT) {
|
||||
if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
gc->direction_output =
|
||||
bgpio_dir_out_dir_first_direct;
|
||||
else
|
||||
gc->direction_output =
|
||||
bgpio_dir_out_val_first_direct;
|
||||
gc->direction_input = bgpio_dir_in_direct;
|
||||
} else {
|
||||
if (flags & BGPIOF_NO_SET_ON_INPUT)
|
||||
gc->direction_output = bgpio_dir_out_dir_first;
|
||||
else
|
||||
gc->direction_output = bgpio_dir_out_val_first;
|
||||
gc->direction_input = bgpio_dir_in;
|
||||
}
|
||||
gc->get_direction = bgpio_get_dir;
|
||||
} else {
|
||||
if (flags & BGPIOF_NO_OUTPUT)
|
||||
|
||||
@@ -737,6 +737,7 @@ int bgpio_init(struct gpio_chip *gc, struct device *dev,
|
||||
#define BGPIOF_NO_SET_ON_INPUT BIT(6)
|
||||
#define BGPIOF_PINCTRL_BACKEND BIT(7) /* Call pinctrl direction setters */
|
||||
#define BGPIOF_NO_INPUT BIT(8) /* only output */
|
||||
#define BGPIOF_REG_DIRECT BIT(15) /* ignore shadow registers */
|
||||
|
||||
#ifdef CONFIG_GPIOLIB_IRQCHIP
|
||||
int gpiochip_irqchip_add_domain(struct gpio_chip *gc,
|
||||
|
||||
Reference in New Issue
Block a user