GPIO fixes for the v4.11 series:
- Set the parent on the Altera A10SR driver, also fix high level IRQs. - Fix error path on the mockup driver. - Compilation noise about unused functions fixed. - Fix missed interrupts on the MCP23S08 expander, this is also tagged for stable. - Retire the interrim helpers devm_get_gpiod_from_child() used to smoothen merging in the merge window. -----BEGIN PGP SIGNATURE----- iQIcBAABAgAGBQJY0OCEAAoJEEEQszewGV1zHE8P/jKp3dGg+nfMrDTucBkutyW2 BVs0cnTI3v27LglzDT8S5enoPs1yMvDQtIIk/Ma5Lspt4ewrfjr9C9ycDT9/NNRW bcHG1YyGhNeAPBug5ZoMIqVrEQvz0Ux4P//gkMXnLqHIS5r2Lk9LsQiKSfwh/zTa +rMzB3p6zTGtm1by/csBi8kej/i2HD5UJsNSCoW6zoK/nfwewma+rqjjMsmG8NNJ zwlEk4ee88r97F/DZ65ZlxBXATzJqP0WqOM+idRnrQG6BvyQk2pzoJNuJrtUIJLu Jbj1KqMMx+Z4xcvM0ofd/EJCgZWYZE8phGKLOqJAEnOOVuPHdWDtjc6RSQkKx+B1 Kejo8TQQCvX4r1JIfGcAwXwicur3KYIN2eNQ/9uThCjibJghq6JfSZghVrKRaY2j ew4khCqRtDfTfdnssYV+Jd3rU/wfLsk+uwcNQS2idPj2X8wB4Dj0MuCV6GGLFdMx 3ZlbbjOjnLU5K5lGoxIaHXjedpRkBx+34EaFxUJqeTuv54/Xpj7nZwXv471HWki4 VM9N8ZlKnnP+OiG3jjPPF5j5c9nEcdlzkER5Af3DIXu3s1K+3EoePXBJexvShhEn VEu5ePW0xV2M3xp/4ur7eE8gk3rfLs9gTF9NvIV49g6gpKmngMMfBcejKytbw36B 9mkWcmKDpxNfWak9jAgz =dTnd -----END PGP SIGNATURE----- Merge tag 'gpio-v4.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio Pull GPIO fixes from Linus Walleij: "Here is the first set of GPIO fixes for 4.11. It was delayed a bit beacuse I was chicken when linux-next was not rotating last week. This hits the ST serial driver in drivers/tty/serial and that has an ACK from Greg, he suggested to keep the old GPIO fwnode API around to smoothen things in the merge Windod and those have now served their purpose so we take them out and convert the last driver to the new API. Apart from that it's fixes as usual. Summary: - set the parent on the Altera A10SR driver, also fix high level IRQs. - fix error path on the mockup driver. - compilation noise about unused functions fixed. - fix missed interrupts on the MCP23S08 expander, this is also tagged for stable. - retire the interrim helpers devm_get_gpiod_from_child() used to smoothen merging in the merge window" * tag 'gpio-v4.11-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio: gpio:mcp23s08 Fixed missing interrupts serial: st-asc: Use new GPIOD API to obtain RTS pin gpio: altera: Use handle_level_irq when configured as a level_high gpio: xgene: mark PM functions as __maybe_unused gpio: mockup: return -EFAULT if copy_from_user() fails gpio: altera-a10sr: Set gpio_chip parent property
This commit is contained in:
commit
4719177780
|
@ -96,7 +96,7 @@ static int altr_a10sr_gpio_probe(struct platform_device *pdev)
|
|||
gpio->regmap = a10sr->regmap;
|
||||
|
||||
gpio->gp = altr_a10sr_gc;
|
||||
|
||||
gpio->gp.parent = pdev->dev.parent;
|
||||
gpio->gp.of_node = pdev->dev.of_node;
|
||||
|
||||
ret = devm_gpiochip_add_data(&pdev->dev, &gpio->gp, gpio);
|
||||
|
|
|
@ -90,21 +90,18 @@ static int altera_gpio_irq_set_type(struct irq_data *d,
|
|||
|
||||
altera_gc = gpiochip_get_data(irq_data_get_irq_chip_data(d));
|
||||
|
||||
if (type == IRQ_TYPE_NONE)
|
||||
if (type == IRQ_TYPE_NONE) {
|
||||
irq_set_handler_locked(d, handle_bad_irq);
|
||||
return 0;
|
||||
if (type == IRQ_TYPE_LEVEL_HIGH &&
|
||||
altera_gc->interrupt_trigger == IRQ_TYPE_LEVEL_HIGH)
|
||||
}
|
||||
if (type == altera_gc->interrupt_trigger) {
|
||||
if (type == IRQ_TYPE_LEVEL_HIGH)
|
||||
irq_set_handler_locked(d, handle_level_irq);
|
||||
else
|
||||
irq_set_handler_locked(d, handle_simple_irq);
|
||||
return 0;
|
||||
if (type == IRQ_TYPE_EDGE_RISING &&
|
||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_RISING)
|
||||
return 0;
|
||||
if (type == IRQ_TYPE_EDGE_FALLING &&
|
||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_FALLING)
|
||||
return 0;
|
||||
if (type == IRQ_TYPE_EDGE_BOTH &&
|
||||
altera_gc->interrupt_trigger == IRQ_TYPE_EDGE_BOTH)
|
||||
return 0;
|
||||
|
||||
}
|
||||
irq_set_handler_locked(d, handle_bad_irq);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -230,7 +227,6 @@ static void altera_gpio_irq_edge_handler(struct irq_desc *desc)
|
|||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
|
||||
static void altera_gpio_irq_leveL_high_handler(struct irq_desc *desc)
|
||||
{
|
||||
struct altera_gpio_chip *altera_gc;
|
||||
|
@ -310,7 +306,7 @@ static int altera_gpio_probe(struct platform_device *pdev)
|
|||
altera_gc->interrupt_trigger = reg;
|
||||
|
||||
ret = gpiochip_irqchip_add(&altera_gc->mmchip.gc, &altera_irq_chip, 0,
|
||||
handle_simple_irq, IRQ_TYPE_NONE);
|
||||
handle_bad_irq, IRQ_TYPE_NONE);
|
||||
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "could not add irqchip\n");
|
||||
|
|
|
@ -270,8 +270,10 @@ mcp23s08_direction_output(struct gpio_chip *chip, unsigned offset, int value)
|
|||
static irqreturn_t mcp23s08_irq(int irq, void *data)
|
||||
{
|
||||
struct mcp23s08 *mcp = data;
|
||||
int intcap, intf, i;
|
||||
int intcap, intf, i, gpio, gpio_orig, intcap_mask;
|
||||
unsigned int child_irq;
|
||||
bool intf_set, intcap_changed, gpio_bit_changed,
|
||||
defval_changed, gpio_set;
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
if (mcp_read(mcp, MCP_INTF, &intf) < 0) {
|
||||
|
@ -287,14 +289,67 @@ static irqreturn_t mcp23s08_irq(int irq, void *data)
|
|||
}
|
||||
|
||||
mcp->cache[MCP_INTCAP] = intcap;
|
||||
|
||||
/* This clears the interrupt(configurable on S18) */
|
||||
if (mcp_read(mcp, MCP_GPIO, &gpio) < 0) {
|
||||
mutex_unlock(&mcp->lock);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
gpio_orig = mcp->cache[MCP_GPIO];
|
||||
mcp->cache[MCP_GPIO] = gpio;
|
||||
mutex_unlock(&mcp->lock);
|
||||
|
||||
if (mcp->cache[MCP_INTF] == 0) {
|
||||
/* There is no interrupt pending */
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
dev_dbg(mcp->chip.parent,
|
||||
"intcap 0x%04X intf 0x%04X gpio_orig 0x%04X gpio 0x%04X\n",
|
||||
intcap, intf, gpio_orig, gpio);
|
||||
|
||||
for (i = 0; i < mcp->chip.ngpio; i++) {
|
||||
if ((BIT(i) & mcp->cache[MCP_INTF]) &&
|
||||
((BIT(i) & intcap & mcp->irq_rise) ||
|
||||
(mcp->irq_fall & ~intcap & BIT(i)) ||
|
||||
(BIT(i) & mcp->cache[MCP_INTCON]))) {
|
||||
/* We must check all of the inputs on the chip,
|
||||
* otherwise we may not notice a change on >=2 pins.
|
||||
*
|
||||
* On at least the mcp23s17, INTCAP is only updated
|
||||
* one byte at a time(INTCAPA and INTCAPB are
|
||||
* not written to at the same time - only on a per-bank
|
||||
* basis).
|
||||
*
|
||||
* INTF only contains the single bit that caused the
|
||||
* interrupt per-bank. On the mcp23s17, there is
|
||||
* INTFA and INTFB. If two pins are changed on the A
|
||||
* side at the same time, INTF will only have one bit
|
||||
* set. If one pin on the A side and one pin on the B
|
||||
* side are changed at the same time, INTF will have
|
||||
* two bits set. Thus, INTF can't be the only check
|
||||
* to see if the input has changed.
|
||||
*/
|
||||
|
||||
intf_set = BIT(i) & mcp->cache[MCP_INTF];
|
||||
if (i < 8 && intf_set)
|
||||
intcap_mask = 0x00FF;
|
||||
else if (i >= 8 && intf_set)
|
||||
intcap_mask = 0xFF00;
|
||||
else
|
||||
intcap_mask = 0x00;
|
||||
|
||||
intcap_changed = (intcap_mask &
|
||||
(BIT(i) & mcp->cache[MCP_INTCAP])) !=
|
||||
(intcap_mask & (BIT(i) & gpio_orig));
|
||||
gpio_set = BIT(i) & mcp->cache[MCP_GPIO];
|
||||
gpio_bit_changed = (BIT(i) & gpio_orig) !=
|
||||
(BIT(i) & mcp->cache[MCP_GPIO]);
|
||||
defval_changed = (BIT(i) & mcp->cache[MCP_INTCON]) &&
|
||||
((BIT(i) & mcp->cache[MCP_GPIO]) !=
|
||||
(BIT(i) & mcp->cache[MCP_DEFVAL]));
|
||||
|
||||
if (((gpio_bit_changed || intcap_changed) &&
|
||||
(BIT(i) & mcp->irq_rise) && gpio_set) ||
|
||||
((gpio_bit_changed || intcap_changed) &&
|
||||
(BIT(i) & mcp->irq_fall) && !gpio_set) ||
|
||||
defval_changed) {
|
||||
child_irq = irq_find_mapping(mcp->chip.irqdomain, i);
|
||||
handle_nested_irq(child_irq);
|
||||
}
|
||||
|
|
|
@ -197,7 +197,7 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
|||
struct seq_file *sfile;
|
||||
struct gpio_desc *desc;
|
||||
struct gpio_chip *gc;
|
||||
int status, val;
|
||||
int val;
|
||||
char buf;
|
||||
|
||||
sfile = file->private_data;
|
||||
|
@ -206,9 +206,8 @@ static ssize_t gpio_mockup_event_write(struct file *file,
|
|||
chip = priv->chip;
|
||||
gc = &chip->gc;
|
||||
|
||||
status = copy_from_user(&buf, usr_buf, 1);
|
||||
if (status)
|
||||
return status;
|
||||
if (copy_from_user(&buf, usr_buf, 1))
|
||||
return -EFAULT;
|
||||
|
||||
if (buf == '0')
|
||||
val = 0;
|
||||
|
|
|
@ -42,9 +42,7 @@ struct xgene_gpio {
|
|||
struct gpio_chip chip;
|
||||
void __iomem *base;
|
||||
spinlock_t lock;
|
||||
#ifdef CONFIG_PM
|
||||
u32 set_dr_val[XGENE_MAX_GPIO_BANKS];
|
||||
#endif
|
||||
};
|
||||
|
||||
static int xgene_gpio_get(struct gpio_chip *gc, unsigned int offset)
|
||||
|
@ -138,8 +136,7 @@ static int xgene_gpio_dir_out(struct gpio_chip *gc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int xgene_gpio_suspend(struct device *dev)
|
||||
static __maybe_unused int xgene_gpio_suspend(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
|
@ -152,7 +149,7 @@ static int xgene_gpio_suspend(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int xgene_gpio_resume(struct device *dev)
|
||||
static __maybe_unused int xgene_gpio_resume(struct device *dev)
|
||||
{
|
||||
struct xgene_gpio *gpio = dev_get_drvdata(dev);
|
||||
unsigned long bank_offset;
|
||||
|
@ -166,10 +163,6 @@ static int xgene_gpio_resume(struct device *dev)
|
|||
}
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(xgene_gpio_pm, xgene_gpio_suspend, xgene_gpio_resume);
|
||||
#define XGENE_GPIO_PM_OPS (&xgene_gpio_pm)
|
||||
#else
|
||||
#define XGENE_GPIO_PM_OPS NULL
|
||||
#endif
|
||||
|
||||
static int xgene_gpio_probe(struct platform_device *pdev)
|
||||
{
|
||||
|
@ -241,7 +234,7 @@ static struct platform_driver xgene_gpio_driver = {
|
|||
.name = "xgene-gpio",
|
||||
.of_match_table = xgene_gpio_of_match,
|
||||
.acpi_match_table = ACPI_PTR(xgene_gpio_acpi_match),
|
||||
.pm = XGENE_GPIO_PM_OPS,
|
||||
.pm = &xgene_gpio_pm,
|
||||
},
|
||||
.probe = xgene_gpio_probe,
|
||||
};
|
||||
|
|
|
@ -575,12 +575,13 @@ static void asc_set_termios(struct uart_port *port, struct ktermios *termios,
|
|||
pinctrl_select_state(ascport->pinctrl,
|
||||
ascport->states[NO_HW_FLOWCTRL]);
|
||||
|
||||
gpiod = devm_get_gpiod_from_child(port->dev, "rts",
|
||||
&np->fwnode);
|
||||
if (!IS_ERR(gpiod)) {
|
||||
gpiod_direction_output(gpiod, 0);
|
||||
gpiod = devm_fwnode_get_gpiod_from_child(port->dev,
|
||||
"rts",
|
||||
&np->fwnode,
|
||||
GPIOD_OUT_LOW,
|
||||
np->name);
|
||||
if (!IS_ERR(gpiod))
|
||||
ascport->rts = gpiod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -143,15 +143,6 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
|||
struct fwnode_handle *child,
|
||||
enum gpiod_flags flags,
|
||||
const char *label);
|
||||
/* FIXME: delete this helper when users are switched over */
|
||||
static inline struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
|
||||
const char *con_id, struct fwnode_handle *child)
|
||||
{
|
||||
return devm_fwnode_get_index_gpiod_from_child(dev, con_id,
|
||||
0, child,
|
||||
GPIOD_ASIS,
|
||||
"?");
|
||||
}
|
||||
|
||||
#else /* CONFIG_GPIOLIB */
|
||||
|
||||
|
@ -444,13 +435,6 @@ struct gpio_desc *devm_fwnode_get_index_gpiod_from_child(struct device *dev,
|
|||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
/* FIXME: delete this when all users are switched over */
|
||||
static inline struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
|
||||
const char *con_id, struct fwnode_handle *child)
|
||||
{
|
||||
return ERR_PTR(-ENOSYS);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_GPIOLIB */
|
||||
|
||||
static inline
|
||||
|
|
Loading…
Reference in New Issue