-
Notifications
You must be signed in to change notification settings - Fork 916
Add Support for LTC3208 #3022
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?
Add Support for LTC3208 #3022
Conversation
47e5181 to
d2fada2
Compare
edelweiseescala
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.
Hello, just sharing what I've learned so far
d2fada2 to
57ca070
Compare
|
Changelog V2:
|
57ca070 to
999b8f4
Compare
999b8f4 to
20cc126
Compare
|
Changelog V3:
|
| if (ret) { | ||
| dev_err(&client->dev, "Error Writing brightness to register %u\n", reg); | ||
| return ret; | ||
| } |
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.
Again, I would just return regmap()
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 is exposed to user space by brightness set and is not used in the probe function, if so should I still remove this dev_err?
Add Documentation for LTC3208 Multidisplay LED Driver. Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
20cc126 to
e3af1f6
Compare
|
Changelog V4:
leds-ltc3208.c
|
e3af1f6 to
5d8624c
Compare
Kernel driver implementation for LTC3208 Multidisplay LED Driver Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
Add entry to Kconfig for LTC3208 driver Signed-off-by: Jan Carlo Roleda <jancarlo.roleda@analog.com>
5d8624c to
6e8165c
Compare
|
Changelog V4.1:
|
machschmitt
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.
Hello @jcroleda,
Some additional comments. Take these with a grain of salt (specially the one about led_trigger) as I'm not experienced with the LEDs subsystem.
Besides those, I suggest to drop the "LTC3208:" part of the
"dt-bindings: leds: LTC3208: Document LTC3208 Multidisplay LED Driver"
commit title. LTC3208 has not been added to the kernel yet.
| adi,select-rgb-sub-en: | ||
| type: boolean | ||
| description: | ||
| Selects whether the ENRGBS pin controls the SUB channel's output pins if set, | ||
| or RGB channel's output pins if unset. |
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 don't think this accurately describes ENRGBS pin behavior based on the details provided on data sheet page 12.
IIUC, ENRGBS works like a toggle button for the RGB leds (if register REGG bit G1 is set to 0) or like a toggle button for the SUB display (if register REGG bit G1 is set to 1). My feeling is that we should have a GPIO to control ENRGBS and/or, maybe, a GPIO hog.
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 is the configuration setup for REGG G1, not the control itself of ENRGBS. I'll change the name and description for clarity.
| struct ltc3208_chip_data { | ||
| struct ltc3208_led *leds; | ||
| }; |
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.
Do we really need this chip_data struct? I think the code would become simpler and easier to read if the array of leds became part of the ltc3208_dev struct.
| current_level |= LTC3208_SET_HIGH_BYTE_DATA( | ||
| dev->chip_data.leds[LTC3208_CHAN_AUX].cdev.brightness); |
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.
Hmm, can the brightness (from enum led_brightness) be LED_FULL == 255? In that case, the current_level would not get updated because 0xFF ORed with anything would continue to be 0xFF. Is this missing
current_level &= ~GENMASK(7, 4);?
or, alternatively
FIELD_MODIFY(GENMASK(7, 4), ¤t_level, dev->leds[LTC3208_CHAN_AUX].cdev.brightness);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 LED subsystem performs clamping internally to the input brightness before being passed into this set_brightness function, so it should not overlap with the existing brightness of the other channel if the target channel's max brightness is only 4-bit (0xF)
| ret = regmap_write(map, reg, current_level); | ||
| if (ret) { | ||
| dev_err(&client->dev, | ||
| "Error Writing brightness to register %u\n", reg); | ||
| return ret; |
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.
An alternative way of having these is to return on each case. E.g.
case LTC3208_CHAN_RED:
current_level |= LTC3208_SET_HIGH_BYTE_DATA(
dev->chip_data.leds[LTC3208_CHAN_GREEN].cdev.brightness);
return regmap_write(map, LTC3208_REG_A_GNRD, current_level);maybe that was what @nunojsa wanted to suggest?
| val |= FIELD_PREP(LTC3208_OPT_EN_RGBS, is_sub); | ||
| val |= FIELD_PREP(LTC3208_OPT_DIS_CAMHILO, is_cam_hi); | ||
| val |= FIELD_PREP(LTC3208_OPT_DIS_RGBDROP, is_rgb_drop); | ||
| val |= FIELD_PREP(LTC3208_OPT_CPO_MASK, cpo_mode); |
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.
Are these also potentially missing val &= ~MASK?
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 believe my initialization u8 val = 0; serves the same purpose here
| return dev_err_probe(&client->dev, -ENOMEM, | ||
| "No memory for device data\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.
return -ENOMEM is what is usually done when memory allocation fails.
| leds = devm_kcalloc(&client->dev, LTC3208_NUM_LED_GRPS, | ||
| sizeof(struct ltc3208_led), GFP_KERNEL); |
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 checking potential errors? I mean,
if (!leds)
return -ENOMEM;?
| current_level |= LTC3208_SET_HIGH_BYTE_DATA( | ||
| dev->chip_data.leds[LTC3208_CHAN_AUX].cdev.brightness); |
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.
Hmm, can the brightness (from enum led_brightness) be LED_FULL == 255? In that case, the current_level would not get updated because 0xFF ored with anything would continue to be 0xFF. Is this missing
current_level &= ~GENMASK(7, 4);?
or, alternatively
FIELD_MODIFY(GENMASK(7, 4), ¤t_level, dev->leds[LTC3208_CHAN_AUX].cdev.brightness);| ret = ltc3208_update_options(data, en_rgbs, dis_camhl, | ||
| dropdis_rgb_aux4, cpo_mode); |
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 not familiar with the LED subsystem. Though, I wonder if we can have the ENRGBS pin functionality better supported as a led_trigger. Main idea is, we add/register a struct led_trigger, setting its name, activate/deactivate callbacks, and any other required fields. With the proper configuration, we should be able to get /sys/class/leds/<led>/shot provided to user space (see Documentation/ABI/testing/sysfs-class-led-trigger-oneshot and Documentation/ABI/testing/sysfs-class-led). There could be one trigger for RGB toggle and one for SUB toggle. The trigger activate/deactive handlers would write the proper REGG bit G1, then pulse the connected GPIO (see the comment about the dt property).
Not sure how much of the above actually makes sense so you might look for somebody more experienced with the LED subsystem if things don't fit well.
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.
Or, if this gets too complicated or time consuming, it might be reasonable to assume ENRGBS is always high and not mess around with that on the initial support for LTC3208.
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 having seperate oneshot triggers for each channel might introduce specific conflicts on the use of the pin (ex. Sub trigger -> RGB trigger before oneshot period is over, will override the Sub trigger as it will switch control of ENRGBS).
However, we could add a general GPIO pin support to provide sysfs access of the pin, and possibly support the same for the CAMHL pin as it serves a similar toggle function.
| adi,force-cpo-level: | ||
| $ref: /schemas/types.yaml#/definitions/string | ||
| description: Forces the Charge Pump Output to a specified multiplier | ||
| enum: | ||
| - "1" # none; device CPO multiplier acts on dropout signals | ||
| - "1.5" | ||
| - "2" | ||
| default: | ||
| - "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.
Have a look at 1 and check out if the charge pump properties can have the same name.
PR Description
PR Type
PR Checklist