Skip to content
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

Add support for Amlogic GPIO IRQs to various drivers #5

Open
wants to merge 4 commits into
base: Nougat
Choose a base branch
from
Open
Show file tree
Hide file tree
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
Expand Up @@ -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)
Expand Down
59 changes: 55 additions & 4 deletions drivers/gpio/gpio-pca953x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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
}

Expand All @@ -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,
Expand Down Expand Up @@ -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;
}

Expand Down
13 changes: 11 additions & 2 deletions drivers/i2c/i2c-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
}
}
Expand Down
117 changes: 94 additions & 23 deletions drivers/input/misc/rotary_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;
Expand All @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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:
Expand All @@ -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);

Expand Down
1 change: 1 addition & 0 deletions include/linux/rotary_encoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down