Skip to content

Add support for Amlogic GPIO IRQs to various drivers #5

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: Nougat
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Documentation/devicetree/bindings/input/rotary-encoder.txt
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ Rotary encoder DT bindings
Required properties:
- gpios: a spec for two GPIOs to be used

Properties required if Amlogic GPIOs are used:
- interrupts: a list of 4 specifiers for the interrupts to be used

Optional properties:
- linux,axis: the input subsystem axis to map to this rotary encoder.
Defaults to 0 (ABS_X / REL_X)
59 changes: 55 additions & 4 deletions drivers/gpio/gpio-pca953x.c
Original file line number Diff line number Diff line change
@@ -14,6 +14,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
@@ -84,6 +85,7 @@ struct pca953x_chip {
struct mutex i2c_lock;

#ifdef CONFIG_GPIO_PCA953X_IRQ
int irq_gpio;
struct mutex irq_lock;
u8 irq_mask[MAX_BANK];
u8 irq_stat[MAX_BANK];
@@ -578,22 +580,51 @@ static int pca953x_irq_setup(struct pca953x_chip *chip,
if (!chip->domain)
return -ENODEV;

if (gpio_is_valid(chip->irq_gpio)) {
ret = gpio_request_one(chip->irq_gpio, GPIOF_IN,
dev_name(&client->dev));
if (ret) {
dev_err(&client->dev,
"unable to request GPIO %d\n",
chip->irq_gpio);
return ret;
}

ret = gpio_for_irq(chip->irq_gpio,
AML_GPIO_IRQ(client->irq,
FILTER_NUM0, GPIO_IRQ_LOW));
if (ret) {
dev_err(&client->dev,
"unable to set GPIO for IRQ %d\n",
client->irq);
goto exit_free_irq_gpio;
}
}

ret = devm_request_threaded_irq(&client->dev,
client->irq,
NULL,
pca953x_irq_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
(gpio_is_valid(chip->irq_gpio) ?
IRQF_TRIGGER_HIGH :
IRQF_TRIGGER_FALLING) | IRQF_ONESHOT,
dev_name(&client->dev), chip);
if (ret) {
dev_err(&client->dev, "failed to request irq %d\n",
client->irq);
return ret;
goto exit_free_irq_gpio;
}

chip->gpio_chip.to_irq = pca953x_gpio_to_irq;
}

return 0;

exit_free_irq_gpio:
if (gpio_is_valid(chip->irq_gpio))
gpio_free(chip->irq_gpio);

return ret;
}

#else /* CONFIG_GPIO_PCA953X_IRQ */
@@ -710,6 +741,7 @@ static int pca953x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct pca953x_platform_data *pdata;
struct device_node *node;
struct pca953x_chip *chip;
int irq_base = 0;
int ret;
@@ -721,6 +753,9 @@ static int pca953x_probe(struct i2c_client *client,
return -ENOMEM;

pdata = dev_get_platdata(&client->dev);
#ifdef CONFIG_GPIO_PCA953X_IRQ
chip->irq_gpio = -1;
#endif
if (pdata) {
irq_base = pdata->irq_base;
chip->gpio_start = pdata->gpio_base;
@@ -729,9 +764,15 @@ static int pca953x_probe(struct i2c_client *client,
} else {
pca953x_get_alt_pdata(client, &chip->gpio_start, &invert);
#ifdef CONFIG_OF_GPIO
node = client->dev.of_node;
/* If I2C node has no interrupts property, disable GPIO interrupts */
if (of_find_property(client->dev.of_node, "interrupts", NULL) == NULL)
if (of_find_property(node, "interrupts", NULL) == NULL)
irq_base = -1;
#ifdef CONFIG_GPIO_PCA953X_IRQ
else if (client->irq)
chip->irq_gpio = of_get_named_gpio_flags(node,
"irq-gpios", 0, NULL);
#endif
#endif
}

@@ -758,8 +799,13 @@ static int pca953x_probe(struct i2c_client *client,
return ret;

ret = gpiochip_add(&chip->gpio_chip);
if (ret)
if (ret) {
#ifdef CONFIG_GPIO_PCA953X_IRQ
if (gpio_is_valid(chip->irq_gpio))
gpio_free(chip->irq_gpio);
#endif
return ret;
}

if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
@@ -795,6 +841,11 @@ static int pca953x_remove(struct i2c_client *client)
return ret;
}

#ifdef CONFIG_GPIO_PCA953X_IRQ
if (gpio_is_valid(chip->irq_gpio))
gpio_free(chip->irq_gpio);
#endif

return 0;
}

13 changes: 11 additions & 2 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
@@ -250,6 +250,17 @@ static int i2c_device_probe(struct device *dev)
if (!client)
return 0;

if (!client->irq && dev->of_node) {
int irq = of_irq_get(dev->of_node, 0);

if (irq == -EPROBE_DEFER)
return irq;
if (irq < 0)
irq = 0;

client->irq = irq;
}

driver = to_i2c_driver(dev->driver);
if (!driver->probe || !driver->id_table)
return -ENODEV;
@@ -1021,7 +1032,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
continue;
}

info.irq = irq_of_parse_and_map(node, 0);
info.of_node = of_node_get(node);
info.archdata = &dev_ad;

@@ -1035,7 +1045,6 @@ static void of_i2c_register_devices(struct i2c_adapter *adap)
dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
node->full_name);
of_node_put(node);
irq_dispose_mapping(info.irq);
continue;
}
}
117 changes: 94 additions & 23 deletions drivers/input/misc/rotary_encoder.c
Original file line number Diff line number Diff line change
@@ -21,10 +21,12 @@
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/amlogic/aml_gpio_consumer.h>
#include <linux/rotary_encoder.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>

#define DRV_NAME "rotary-encoder"
@@ -156,6 +158,7 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
struct device_node *np = dev->of_node;
struct rotary_encoder_platform_data *pdata;
enum of_gpio_flags flags;
int i;

if (!of_id || !np)
return NULL;
@@ -174,6 +177,15 @@ static struct rotary_encoder_platform_data *rotary_encoder_parse_dt(struct devic
pdata->gpio_b = of_get_gpio_flags(np, 1, &flags);
pdata->inverted_b = flags & OF_GPIO_ACTIVE_LOW;

for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++) {
pdata->irqs[i] = irq_of_parse_and_map(np, i);
if (!pdata->irqs[i]) {
while (i)
pdata->irqs[--i] = 0;
break;
}
}

pdata->relative_axis = !!of_get_property(np,
"rotary-encoder,relative-axis", NULL);
pdata->rollover = !!of_get_property(np,
@@ -198,7 +210,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
struct rotary_encoder *encoder;
struct input_dev *input;
irq_handler_t handler;
int err;
int i, err;

if (!pdata) {
pdata = rotary_encoder_parse_dt(dev);
@@ -247,9 +259,6 @@ static int rotary_encoder_probe(struct platform_device *pdev)
goto exit_free_gpio_a;
}

encoder->irq_a = gpio_to_irq(pdata->gpio_a);
encoder->irq_b = gpio_to_irq(pdata->gpio_b);

/* request the IRQs */
if (pdata->half_period) {
handler = &rotary_encoder_half_period_irq;
@@ -258,36 +267,92 @@ static int rotary_encoder_probe(struct platform_device *pdev)
handler = &rotary_encoder_irq;
}

err = request_irq(encoder->irq_a, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
goto exit_free_gpio_b;
}
if (pdata->irqs[0]) {
err = gpio_for_irq(pdata->gpio_a, AML_GPIO_IRQ(pdata->irqs[0],
FILTER_NUM0, GPIO_IRQ_RISING));
if (err) {
dev_err(dev, "unable to set GPIO for IRQ %d\n",
pdata->irqs[0]);
goto exit_free_gpio_b;
}

err = request_irq(encoder->irq_b, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
goto exit_free_irq_a;
err = gpio_for_irq(pdata->gpio_a, AML_GPIO_IRQ(pdata->irqs[1],
FILTER_NUM0, GPIO_IRQ_FALLING));
if (err) {
dev_err(dev, "unable to set GPIO for IRQ %d\n",
pdata->irqs[1]);
goto exit_free_gpio_b;
}

err = gpio_for_irq(pdata->gpio_b, AML_GPIO_IRQ(pdata->irqs[2],
FILTER_NUM0, GPIO_IRQ_RISING));
if (err) {
dev_err(dev, "unable to set GPIO for IRQ %d\n",
pdata->irqs[2]);
goto exit_free_gpio_b;
}

err = gpio_for_irq(pdata->gpio_b, AML_GPIO_IRQ(pdata->irqs[3],
FILTER_NUM0, GPIO_IRQ_FALLING));
if (err) {
dev_err(dev, "unable to set GPIO for IRQ %d\n",
pdata->irqs[3]);
goto exit_free_gpio_b;
}

for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++) {
err = request_irq(pdata->irqs[i], handler,
IRQF_TRIGGER_RISING, DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n",
pdata->irqs[i]);
goto exit_free_rem_irqs;
}
}
} else {
encoder->irq_a = gpio_to_irq(pdata->gpio_a);
encoder->irq_b = gpio_to_irq(pdata->gpio_b);

err = request_irq(encoder->irq_a, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n",
encoder->irq_a);
goto exit_free_gpio_b;
}

err = request_irq(encoder->irq_b, handler,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
DRV_NAME, encoder);
if (err) {
dev_err(dev, "unable to request IRQ %d\n",
encoder->irq_b);
goto exit_free_irq_a;
}
}

err = input_register_device(input);
if (err) {
dev_err(dev, "failed to register input device\n");
goto exit_free_irq_b;
goto exit_free_irqs;
}

platform_set_drvdata(pdev, encoder);

return 0;

exit_free_irq_b:
free_irq(encoder->irq_b, encoder);
exit_free_irqs:
if (pdata->irqs[0]) {
i = ARRAY_SIZE(pdata->irqs);
exit_free_rem_irqs:
while (i)
free_irq(pdata->irqs[--i], encoder);
} else {
free_irq(encoder->irq_b, encoder);
exit_free_irq_a:
free_irq(encoder->irq_a, encoder);
free_irq(encoder->irq_a, encoder);
}
exit_free_gpio_b:
gpio_free(pdata->gpio_b);
exit_free_gpio_a:
@@ -305,9 +370,15 @@ static int rotary_encoder_remove(struct platform_device *pdev)
{
struct rotary_encoder *encoder = platform_get_drvdata(pdev);
const struct rotary_encoder_platform_data *pdata = encoder->pdata;
int i;

free_irq(encoder->irq_a, encoder);
free_irq(encoder->irq_b, encoder);
if (pdata->irqs[0]) {
for (i = 0; i < ARRAY_SIZE(pdata->irqs); i++)
free_irq(pdata->irqs[i], encoder);
} else {
free_irq(encoder->irq_a, encoder);
free_irq(encoder->irq_b, encoder);
}
gpio_free(pdata->gpio_a);
gpio_free(pdata->gpio_b);

1 change: 1 addition & 0 deletions include/linux/rotary_encoder.h
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ struct rotary_encoder_platform_data {
unsigned int gpio_b;
unsigned int inverted_a;
unsigned int inverted_b;
unsigned int irqs[4];
bool relative_axis;
bool rollover;
bool half_period;