|
@@ -40,35 +40,42 @@ struct rotary_encoder {
|
|
|
|
|
|
unsigned int pos;
|
|
unsigned int pos;
|
|
|
|
|
|
- struct gpio_desc *gpio_a;
|
|
|
|
- struct gpio_desc *gpio_b;
|
|
|
|
|
|
+ struct gpio_descs *gpios;
|
|
|
|
|
|
- unsigned int irq_a;
|
|
|
|
- unsigned int irq_b;
|
|
|
|
|
|
+ unsigned int *irq;
|
|
|
|
|
|
bool armed;
|
|
bool armed;
|
|
- unsigned char dir; /* 0 - clockwise, 1 - CCW */
|
|
|
|
|
|
+ signed char dir; /* 1 - clockwise, -1 - CCW */
|
|
|
|
|
|
- char last_stable;
|
|
|
|
|
|
+ unsigned last_stable;
|
|
};
|
|
};
|
|
|
|
|
|
-static int rotary_encoder_get_state(struct rotary_encoder *encoder)
|
|
|
|
|
|
+static unsigned rotary_encoder_get_state(struct rotary_encoder *encoder)
|
|
{
|
|
{
|
|
- int a = !!gpiod_get_value_cansleep(encoder->gpio_a);
|
|
|
|
- int b = !!gpiod_get_value_cansleep(encoder->gpio_b);
|
|
|
|
|
|
+ int i;
|
|
|
|
+ unsigned ret = 0;
|
|
|
|
|
|
- return ((a << 1) | b);
|
|
|
|
|
|
+ for (i = 0; i < encoder->gpios->ndescs; ++i) {
|
|
|
|
+ int val = gpiod_get_value_cansleep(encoder->gpios->desc[i]);
|
|
|
|
+ /* convert from gray encoding to normal */
|
|
|
|
+ if (ret & 1)
|
|
|
|
+ val = !val;
|
|
|
|
+
|
|
|
|
+ ret = ret << 1 | val;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return ret & 3;
|
|
}
|
|
}
|
|
|
|
|
|
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
|
|
static void rotary_encoder_report_event(struct rotary_encoder *encoder)
|
|
{
|
|
{
|
|
if (encoder->relative_axis) {
|
|
if (encoder->relative_axis) {
|
|
input_report_rel(encoder->input,
|
|
input_report_rel(encoder->input,
|
|
- encoder->axis, encoder->dir ? -1 : 1);
|
|
|
|
|
|
+ encoder->axis, encoder->dir);
|
|
} else {
|
|
} else {
|
|
unsigned int pos = encoder->pos;
|
|
unsigned int pos = encoder->pos;
|
|
|
|
|
|
- if (encoder->dir) {
|
|
|
|
|
|
+ if (encoder->dir < 0) {
|
|
/* turning counter-clockwise */
|
|
/* turning counter-clockwise */
|
|
if (encoder->rollover)
|
|
if (encoder->rollover)
|
|
pos += encoder->steps;
|
|
pos += encoder->steps;
|
|
@@ -93,7 +100,7 @@ static void rotary_encoder_report_event(struct rotary_encoder *encoder)
|
|
static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
|
static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct rotary_encoder *encoder = dev_id;
|
|
struct rotary_encoder *encoder = dev_id;
|
|
- int state;
|
|
|
|
|
|
+ unsigned state;
|
|
|
|
|
|
mutex_lock(&encoder->access_mutex);
|
|
mutex_lock(&encoder->access_mutex);
|
|
|
|
|
|
@@ -108,12 +115,12 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
|
break;
|
|
break;
|
|
|
|
|
|
case 0x1:
|
|
case 0x1:
|
|
- case 0x2:
|
|
|
|
|
|
+ case 0x3:
|
|
if (encoder->armed)
|
|
if (encoder->armed)
|
|
- encoder->dir = state - 1;
|
|
|
|
|
|
+ encoder->dir = 2 - state;
|
|
break;
|
|
break;
|
|
|
|
|
|
- case 0x3:
|
|
|
|
|
|
+ case 0x2:
|
|
encoder->armed = true;
|
|
encoder->armed = true;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -126,25 +133,19 @@ static irqreturn_t rotary_encoder_irq(int irq, void *dev_id)
|
|
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
|
|
static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct rotary_encoder *encoder = dev_id;
|
|
struct rotary_encoder *encoder = dev_id;
|
|
- int state;
|
|
|
|
|
|
+ unsigned int state;
|
|
|
|
|
|
mutex_lock(&encoder->access_mutex);
|
|
mutex_lock(&encoder->access_mutex);
|
|
|
|
|
|
state = rotary_encoder_get_state(encoder);
|
|
state = rotary_encoder_get_state(encoder);
|
|
|
|
|
|
- switch (state) {
|
|
|
|
- case 0x00:
|
|
|
|
- case 0x03:
|
|
|
|
|
|
+ if (state & 1) {
|
|
|
|
+ encoder->dir = ((encoder->last_stable - state + 1) % 4) - 1;
|
|
|
|
+ } else {
|
|
if (state != encoder->last_stable) {
|
|
if (state != encoder->last_stable) {
|
|
rotary_encoder_report_event(encoder);
|
|
rotary_encoder_report_event(encoder);
|
|
encoder->last_stable = state;
|
|
encoder->last_stable = state;
|
|
}
|
|
}
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 0x01:
|
|
|
|
- case 0x02:
|
|
|
|
- encoder->dir = (encoder->last_stable + state) & 0x01;
|
|
|
|
- break;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
mutex_unlock(&encoder->access_mutex);
|
|
mutex_unlock(&encoder->access_mutex);
|
|
@@ -155,46 +156,18 @@ static irqreturn_t rotary_encoder_half_period_irq(int irq, void *dev_id)
|
|
static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
|
|
static irqreturn_t rotary_encoder_quarter_period_irq(int irq, void *dev_id)
|
|
{
|
|
{
|
|
struct rotary_encoder *encoder = dev_id;
|
|
struct rotary_encoder *encoder = dev_id;
|
|
- unsigned char sum;
|
|
|
|
- int state;
|
|
|
|
|
|
+ unsigned int state;
|
|
|
|
|
|
mutex_lock(&encoder->access_mutex);
|
|
mutex_lock(&encoder->access_mutex);
|
|
|
|
|
|
state = rotary_encoder_get_state(encoder);
|
|
state = rotary_encoder_get_state(encoder);
|
|
|
|
|
|
- /*
|
|
|
|
- * We encode the previous and the current state using a byte.
|
|
|
|
- * The previous state in the MSB nibble, the current state in the LSB
|
|
|
|
- * nibble. Then use a table to decide the direction of the turn.
|
|
|
|
- */
|
|
|
|
- sum = (encoder->last_stable << 4) + state;
|
|
|
|
- switch (sum) {
|
|
|
|
- case 0x31:
|
|
|
|
- case 0x10:
|
|
|
|
- case 0x02:
|
|
|
|
- case 0x23:
|
|
|
|
- encoder->dir = 0; /* clockwise */
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 0x13:
|
|
|
|
- case 0x01:
|
|
|
|
- case 0x20:
|
|
|
|
- case 0x32:
|
|
|
|
- encoder->dir = 1; /* counter-clockwise */
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- default:
|
|
|
|
- /*
|
|
|
|
- * Ignore all other values. This covers the case when the
|
|
|
|
- * state didn't change (a spurious interrupt) and the
|
|
|
|
- * cases where the state changed by two steps, making it
|
|
|
|
- * impossible to tell the direction.
|
|
|
|
- *
|
|
|
|
- * In either case, don't report any event and save the
|
|
|
|
- * state for later.
|
|
|
|
- */
|
|
|
|
|
|
+ if ((encoder->last_stable + 1) % 4 == state)
|
|
|
|
+ encoder->dir = 1;
|
|
|
|
+ else if (encoder->last_stable == (state + 1) % 4)
|
|
|
|
+ encoder->dir = -1;
|
|
|
|
+ else
|
|
goto out;
|
|
goto out;
|
|
- }
|
|
|
|
|
|
|
|
rotary_encoder_report_event(encoder);
|
|
rotary_encoder_report_event(encoder);
|
|
|
|
|
|
@@ -212,6 +185,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
|
|
struct input_dev *input;
|
|
struct input_dev *input;
|
|
irq_handler_t handler;
|
|
irq_handler_t handler;
|
|
u32 steps_per_period;
|
|
u32 steps_per_period;
|
|
|
|
+ unsigned int i;
|
|
int err;
|
|
int err;
|
|
|
|
|
|
encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
|
|
encoder = devm_kzalloc(dev, sizeof(struct rotary_encoder), GFP_KERNEL);
|
|
@@ -243,24 +217,16 @@ static int rotary_encoder_probe(struct platform_device *pdev)
|
|
encoder->relative_axis =
|
|
encoder->relative_axis =
|
|
device_property_read_bool(dev, "rotary-encoder,relative-axis");
|
|
device_property_read_bool(dev, "rotary-encoder,relative-axis");
|
|
|
|
|
|
- encoder->gpio_a = devm_gpiod_get_index(dev, NULL, 0, GPIOD_IN);
|
|
|
|
- if (IS_ERR(encoder->gpio_a)) {
|
|
|
|
- err = PTR_ERR(encoder->gpio_a);
|
|
|
|
- dev_err(dev, "unable to get GPIO at index 0: %d\n", err);
|
|
|
|
- return err;
|
|
|
|
|
|
+ encoder->gpios = devm_gpiod_get_array(dev, NULL, GPIOD_IN);
|
|
|
|
+ if (IS_ERR(encoder->gpios)) {
|
|
|
|
+ dev_err(dev, "unable to get gpios\n");
|
|
|
|
+ return PTR_ERR(encoder->gpios);
|
|
}
|
|
}
|
|
-
|
|
|
|
- encoder->irq_a = gpiod_to_irq(encoder->gpio_a);
|
|
|
|
-
|
|
|
|
- encoder->gpio_b = devm_gpiod_get_index(dev, NULL, 1, GPIOD_IN);
|
|
|
|
- if (IS_ERR(encoder->gpio_b)) {
|
|
|
|
- err = PTR_ERR(encoder->gpio_b);
|
|
|
|
- dev_err(dev, "unable to get GPIO at index 1: %d\n", err);
|
|
|
|
- return err;
|
|
|
|
|
|
+ if (encoder->gpios->ndescs < 2) {
|
|
|
|
+ dev_err(dev, "not enough gpios found\n");
|
|
|
|
+ return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
- encoder->irq_b = gpiod_to_irq(encoder->gpio_b);
|
|
|
|
-
|
|
|
|
input = devm_input_allocate_device(dev);
|
|
input = devm_input_allocate_device(dev);
|
|
if (!input)
|
|
if (!input)
|
|
return -ENOMEM;
|
|
return -ENOMEM;
|
|
@@ -277,7 +243,7 @@ static int rotary_encoder_probe(struct platform_device *pdev)
|
|
input_set_abs_params(input,
|
|
input_set_abs_params(input,
|
|
encoder->axis, 0, encoder->steps, 0, 1);
|
|
encoder->axis, 0, encoder->steps, 0, 1);
|
|
|
|
|
|
- switch (steps_per_period) {
|
|
|
|
|
|
+ switch (steps_per_period >> (encoder->gpios->ndescs - 2)) {
|
|
case 4:
|
|
case 4:
|
|
handler = &rotary_encoder_quarter_period_irq;
|
|
handler = &rotary_encoder_quarter_period_irq;
|
|
encoder->last_stable = rotary_encoder_get_state(encoder);
|
|
encoder->last_stable = rotary_encoder_get_state(encoder);
|
|
@@ -295,22 +261,26 @@ static int rotary_encoder_probe(struct platform_device *pdev)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
|
|
|
|
- err = devm_request_threaded_irq(dev, encoder->irq_a, NULL, handler,
|
|
|
|
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
|
|
|
- IRQF_ONESHOT,
|
|
|
|
- DRV_NAME, encoder);
|
|
|
|
- if (err) {
|
|
|
|
- dev_err(dev, "unable to request IRQ %d\n", encoder->irq_a);
|
|
|
|
- return err;
|
|
|
|
- }
|
|
|
|
|
|
+ encoder->irq =
|
|
|
|
+ devm_kzalloc(dev,
|
|
|
|
+ sizeof(*encoder->irq) * encoder->gpios->ndescs,
|
|
|
|
+ GFP_KERNEL);
|
|
|
|
+ if (!encoder->irq)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
|
|
- err = devm_request_threaded_irq(dev, encoder->irq_b, NULL, handler,
|
|
|
|
|
|
+ for (i = 0; i < encoder->gpios->ndescs; ++i) {
|
|
|
|
+ encoder->irq[i] = gpiod_to_irq(encoder->gpios->desc[i]);
|
|
|
|
+
|
|
|
|
+ err = devm_request_threaded_irq(dev, encoder->irq[i],
|
|
|
|
+ NULL, handler,
|
|
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
|
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
|
|
IRQF_ONESHOT,
|
|
IRQF_ONESHOT,
|
|
DRV_NAME, encoder);
|
|
DRV_NAME, encoder);
|
|
- if (err) {
|
|
|
|
- dev_err(dev, "unable to request IRQ %d\n", encoder->irq_b);
|
|
|
|
- return err;
|
|
|
|
|
|
+ if (err) {
|
|
|
|
+ dev_err(dev, "unable to request IRQ %d (gpio#%d)\n",
|
|
|
|
+ encoder->irq[i], i);
|
|
|
|
+ return err;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
err = input_register_device(input);
|
|
err = input_register_device(input);
|
|
@@ -330,10 +300,11 @@ static int rotary_encoder_probe(struct platform_device *pdev)
|
|
static int __maybe_unused rotary_encoder_suspend(struct device *dev)
|
|
static int __maybe_unused rotary_encoder_suspend(struct device *dev)
|
|
{
|
|
{
|
|
struct rotary_encoder *encoder = dev_get_drvdata(dev);
|
|
struct rotary_encoder *encoder = dev_get_drvdata(dev);
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
if (device_may_wakeup(dev)) {
|
|
if (device_may_wakeup(dev)) {
|
|
- enable_irq_wake(encoder->irq_a);
|
|
|
|
- enable_irq_wake(encoder->irq_b);
|
|
|
|
|
|
+ for (i = 0; i < encoder->gpios->ndescs; ++i)
|
|
|
|
+ enable_irq_wake(encoder->irq[i]);
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -342,10 +313,11 @@ static int __maybe_unused rotary_encoder_suspend(struct device *dev)
|
|
static int __maybe_unused rotary_encoder_resume(struct device *dev)
|
|
static int __maybe_unused rotary_encoder_resume(struct device *dev)
|
|
{
|
|
{
|
|
struct rotary_encoder *encoder = dev_get_drvdata(dev);
|
|
struct rotary_encoder *encoder = dev_get_drvdata(dev);
|
|
|
|
+ unsigned int i;
|
|
|
|
|
|
if (device_may_wakeup(dev)) {
|
|
if (device_may_wakeup(dev)) {
|
|
- disable_irq_wake(encoder->irq_a);
|
|
|
|
- disable_irq_wake(encoder->irq_b);
|
|
|
|
|
|
+ for (i = 0; i < encoder->gpios->ndescs; ++i)
|
|
|
|
+ disable_irq_wake(encoder->irq[i]);
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
return 0;
|