-
Notifications
You must be signed in to change notification settings - Fork 911
Add support for MAX16150/MAX16169 #2672
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
base: main
Are you sure you want to change the base?
Conversation
fc933bb to
55c3ff9
Compare
nunojsa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm stopping the review for now. Note that you pretty much copied the driver from one subsystem to another without any integration with the input subsystem. Not what was meant.
Please do not rush into opening PRs or having things done. Really try to understand what was asked and seek help if needed 😉
| brcm,function = <0>; | ||
| brcm,pull = <0>; | ||
| }; | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks to be very rpi dependent... Typically not needed in bindings AFAIK. But you're definetly missing input properties. Where do you define the key code?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the key code is typically used to detect button presses. However, with MAX16150, it sends interrupt signals when certain amount of time the button is pressed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment. The above is not needed in the example....
I think the key code is typically used to detect button presses. However, with MAX16150, it sends interrupt signals when certain amount of time the button is pressed.
And button presses are also signaled (most of the times) via interrupts. Typically one IRQ for press and one for release. Is this not the same with this button?
| adi,variant = "A"; | ||
|
|
||
| gpio-pb_in = <&gpio 17 1>; | ||
| gpio-out = <&gpio 18 0>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm also not convinced we need the above...
drivers/input/misc/max16150.c
Outdated
|
|
||
| hrtimer_cancel(&data->debounce_timer); | ||
| hrtimer_cancel(&data->shutdown_timer); | ||
| return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be done in a devm_action... Also not sure if we really need hrtimers for this
drivers/input/misc/max16150.c
Outdated
| } else { | ||
| dev_err(&pdev->dev, "Unknown device type: %s\n", type); | ||
| return -EINVAL; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use proper chip info structure for subtleties in the chips... The above does not scale at al.
drivers/input/misc/max16150.c
Outdated
| return -EINVAL; | ||
| } | ||
|
|
||
| ret = device_property_read_string(&pdev->dev, "adi,variant", &variant); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not in the bindings and I dunno you need a property for this... You already have compatibles and you can different info structure per compatible.
kister-jimenez
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You might want to check out existing input device drivers for reference.
drivers/input/misc/max16150.c
Outdated
|
|
||
| if (data->variant == MAX161X_A && data->out_asserted) { | ||
| dev_info(data->dev, "Shutdown time exceeded. Deasserting OUT."); | ||
| gpiod_set_value(data->gpio_clr, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use the input subsystem like input_report_key and input_sync to report the key and the value to the input subsystem and to sync input events.
drivers/input/misc/max16150.c
Outdated
| case 'A': | ||
| data->variant = MAX161X_A; | ||
| data->debounce_time = ktime_set(0, 50 * NSEC_PER_MSEC); | ||
| data->shutdown_time = (data->type == MAX16150) ? ktime_set(8, | ||
| 0) : ktime_set(16, 0); | ||
| break; | ||
| case 'B': | ||
| data->variant = MAX161X_B; | ||
| data->debounce_time = (data->type == MAX16150) ? ktime_set(2, | ||
| 0) : ktime_set(50, 0); | ||
| data->shutdown_time = ktime_set(16, 0); | ||
| break; | ||
| case 'C': | ||
| data->variant = MAX161X_C; | ||
| data->debounce_time = ktime_set(0, 50 * NSEC_PER_MSEC); | ||
| data->shutdown_time = ktime_set(16, 0); | ||
| break; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure why you need the debounce time and shutdown time.
Debounce time is for the push button input which should be connected to a push button not the processor system.
Shutdown period is how long the button is pressed before the chip deasserts (in some variant) and pull down the interrupt pin. This is also related to the button side.
drivers/input/misc/max16150.c
Outdated
| dev_info(&pdev->dev, "Detected %s variant %s\n", | ||
| (data->type == MAX16150) ? "MAX16150" : "MAX16169", variant); | ||
|
|
||
| data->gpio_pb_in = devm_gpiod_get(&pdev->dev, "pb_in", GPIOD_IN); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pb_in is not an input to the MPU and is not connected to the MPU. This is connected to the push button.
drivers/input/misc/max16150.c
Outdated
| if (IS_ERR(data->gpio_pb_in)) | ||
| return PTR_ERR(data->gpio_pb_in); | ||
|
|
||
| data->gpio_out = devm_gpiod_get(&pdev->dev, "out", GPIOD_OUT_LOW); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Out pin of the device is typically used to control a switch or to gate the power to the device. You don't need this.
drivers/input/misc/max16150.c
Outdated
| if (IS_ERR(data->gpio_clr)) | ||
| return PTR_ERR(data->gpio_clr); | ||
|
|
||
| data->gpio_int = devm_gpiod_get(&pdev->dev, "int", GPIOD_IN); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just use an irq.
drivers/input/misc/max16150.c
Outdated
| enum max161x_variant { | ||
| MAX161X_A, | ||
| MAX161X_B, | ||
| MAX161X_C, | ||
| }; | ||
|
|
||
| enum max161x_type { | ||
| MAX16150, | ||
| MAX16169, | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't you just combine these? I think the variant is part of the ordering options for customers to select different timing options?
drivers/input/misc/max16150.c
Outdated
| if (gpiod_get_value(data->gpio_pb_in)) { | ||
| /* Button pressed */ | ||
| hrtimer_start(&data->debounce_timer, data->debounce_time, | ||
| HRTIMER_MODE_REL); | ||
| } else { | ||
| /* Button released */ | ||
| if (data->variant == MAX161X_A && data->out_asserted) { | ||
| dev_info(data->dev, "Cancelling shutdown timer."); | ||
| hrtimer_cancel(&data->shutdown_timer); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should use the input subsystem like input_report_key and input_sync to report the key and the value to the input subsystem and to sync input events.
I think what you want is to know the interval between the last irq if you want to distinguish the long press and the short momentary press.
drivers/input/misc/max16150.c
Outdated
| hrtimer_init(&data->shutdown_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); | ||
| data->shutdown_timer.function = max161x_shutdown_timer_cb; | ||
|
|
||
| ret = devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_pb_in), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The irq pin is the int pin not the pb_in pin.
7aebbf1 to
e96094d
Compare
|
Changelogs V2:
|
drivers/input/misc/max16150.c
Outdated
| #define GPIO_INT 17 | ||
| #define GPIO_CLR 27 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get this from the device tree overlay.
024c7d7 to
adcc142
Compare
|
Changelogs V4 Short and Long Press Detection
Input Subsystem Enhancements
Bug Fixes & Optimizations IRQ Duration Calculation Moved
Removed Redundant Logging
General Code Cleanup
I still think that the gpio clr can be declared outside the driver. |
| properties: | ||
| compatible: | ||
| description: | | ||
| Specifies the supported device variants. The MAX16150 and MAX16169 are supported. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think the text needs to be formatted... This means you can drop '|'
| interrupts: | ||
| maxItems: 1 | ||
|
|
||
| linux,code: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you need to $ref the proper input.yaml file to get this property
| #include <linux/platform_device.h> | ||
| #include <linux/ktime.h> | ||
| #include <linux/of.h> | ||
| #include <linux/mod_devicetable.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not in alphabetical order and you still have of.h
drivers/input/misc/max16150.c
Outdated
|
|
||
| #define SHORT_PRESS_MIN_MS 32 | ||
| #define SHORT_PRESS_MAX_MS 127 | ||
| #define LONG_PRESS_MIN_MS 128 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typically one uses the driver name as prefix... Example: MAX16150_SHORT_PRESS_MIN_MS
drivers/input/misc/max16150.c
Outdated
| return err; | ||
| } | ||
|
|
||
| platform_set_drvdata(pdev, data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed...
drivers/input/misc/max16150.c
Outdated
|
|
||
| data->bttn = bttn; | ||
| if (of_property_read_u32(np, "key-event", &data->key_event)) | ||
| data->key_event = KEY_POWER; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use device property API. Fairly sure I already asked for it...
| power-button { | ||
| compatible = "adi,max16150"; | ||
| interrupt-parent = <&gpio>; | ||
| interrupts = <17 IRQ_TYPE_EDGE_BOTH>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I doubt the driver works if DT is like this... Did you tested it?
drivers/input/misc/max16150.c
Outdated
| err = devm_request_threaded_irq(&pdev->dev, fall_irq, NULL, | ||
| max16150_fall_irq, | ||
| IRQF_TRIGGER_FALLING | IRQF_ONESHOT, | ||
| "max16150_falling", data); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thinking about this? Did you actually tested this? How did you described this in your DT? You would need to connect the interrupt signal into two different inputs in the processor. So this hack could be useful to know if you are in a rising or falling edge but it's not coherent with the bindings.
drivers/input/misc/max16150.c
Outdated
| bttn->phys = "max16150/input0"; | ||
| bttn->id.bustype = BUS_HOST; | ||
| input_set_capability(bttn, EV_KEY, data->key_event); | ||
| input_set_capability(bttn, EV_MSC, MSC_SCAN); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need the above?
drivers/input/misc/max16150.c
Outdated
|
|
||
| data->irq_falling_time = ktime_get(); | ||
| irq_duration = ktime_sub(data->irq_falling_time, data->irq_rising_time); | ||
| duration_ms = ktime_to_ms(irq_duration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, can you actually ensure that the rising edge already happened? I think you can still have a race during probe. So you could have requested the interrupt while your signal is already high and at that point, I do not think your max16150_rise_irq will trigger. Hence data->irq_rising_time will be 0 and you could wrongly detect a long press.
I think you could simple check data->irq_rising_time for 0 and ignore this interrupt in that case as there's no way to properly get the press duration.
But this hack requesting two interrupts is very questionable... I'll ask this again: Did you tried my suggestion with this API?
https://elixir.bootlin.com/linux/v6.6.65/source/include/linux/interrupt.h#L504
If it works, you could properly do:
err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
max16150_irq,
IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"max16150_irq", data);
adcc142 to
2e8b4a3
Compare
2e8b4a3 to
e0a2997
Compare
|
V5:
|
e0a2997 to
4959b0b
Compare
|
Changelogs V6:
|
nunojsa
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, I would say to take my last inputs and send this upstream
| "clr GPIO undefined, clr pin will not be asserted\n"); | ||
| } else { | ||
| gpiod_set_value(max16150->clr_gpiod, 0); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are using the clr gpio to reset the device, this is what we have implemented. I think the gpio should be high on boot since it will only go low if we want to reset or deassert the output.
Ahh, I get it know... But now that I thin about this, we should do this in another way because as we have it know, we will never use this pin for chips where has_clr_gpio = false. Sure, for those devices, it's not a mandatory pin but we should still be able to use it if we want too right? So, I would suggest something like:
max16150->clr_gpiod = devm_gpiod_get_optional(dev, "clr", GPIOD_OUT_HIGH);
if (IS_ERR(max16150->clr_gpiod))
return dev_err_probe(dev, PTR_ERR(max16150->clr_gpiod),
"Failed to get clr GPIO\n");
if (!max16150->clr_gpiod && chip_info->needs_clr_gpio)
return dev_err_probe(dev, ...); //clr gpio is mandatory for latching out the output
if (max16150->clr_gpiod) {
...
}
Makes sense?
|
Changelogs: Removed if() statement on probe for setting gpio, now directly handled by the gpio subsystem. Thanks!!! |
drivers/input/misc/max16150.c
Outdated
|
|
||
| if (!max16150->clr_gpiod && chip_info->has_clr_gpio) | ||
| return (dev_err_probe(dev, -ENODEV, | ||
| "clr GPIO is mandatory\n")); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove extra parenthesis... Also this was not what I suggested. The condition also does not make sense since you have the outer if (chip_info->has_clr_gpio)
|
|
||
| gpiod_set_value(max16150->clr_gpiod, 1); | ||
|
|
||
| input_report_key(max16150->input, max16150->keycode, 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be making some confusion but does this not mean power off? I guess it should be input_report_key(max16150->input, max16150->keycode, 0);?
I would also expect to see a call to input_report_key(max16150->input, max16150->keycode, 1); to signal power up?
So long press != short press in terms of the key value right?
b3ee62c to
b453125
Compare
|
Hi, I'm just checking in on the status of this pull request. Is there anything I can do to help move it forward? |
f02e52e to
b453125
Compare
Add documentation for device tree bindings for MAX16150/MAX16169 Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
MAX16150/MAX16169 nanoPower Pushbutton On/Off Controller Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
Add entry for the MAX16150/MAX16169 driver. Signed-off-by: Marc Paolo Sosa <marcpaolo.sosa@analog.com>
b453125 to
6850913
Compare
PR Description
necessary to understand them. List any dependencies required for this change.
any space), or simply check them after publishing the PR.
description and try to push all related PRs simultaneously.
PR Type
PR Checklist