Svyatoslav Ryhel | 16fbab5 | 2024-10-02 12:07:10 +0300 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0+ |
| 2 | /* |
| 3 | * Copyright (c) 2024 Svyatoslav Ryhel <clamor95@gmail.com> |
| 4 | */ |
| 5 | |
| 6 | #define LOG_CATEGORY UCLASS_PANEL_BACKLIGHT |
| 7 | |
| 8 | #include <backlight.h> |
| 9 | #include <dm.h> |
| 10 | #include <i2c.h> |
| 11 | #include <log.h> |
| 12 | #include <linux/err.h> |
| 13 | #include <asm/gpio.h> |
| 14 | #include <power/regulator.h> |
| 15 | |
| 16 | #define AAT2870_BL_MIN_BRIGHTNESS 0x01 |
| 17 | #define AAT2870_BL_DEF_BRIGHTNESS 0x64 |
| 18 | #define AAT2870_BL_MAX_BRIGHTNESS 0xff |
| 19 | |
| 20 | #define AAT2870_BL_CH_EN 0x00 |
| 21 | #define AAT2870_BLM 0x01 |
| 22 | |
| 23 | #define AAT2870_BL_CH_ALL 0xff |
| 24 | |
| 25 | #define AAT2870_CURRENT_MAX 27900000 |
| 26 | #define AAT2870_CURRENT_STEP 900000 |
| 27 | |
| 28 | struct aat2870_backlight_priv { |
| 29 | struct gpio_desc enable_gpio; |
| 30 | |
| 31 | int channels; |
| 32 | int max_current; |
| 33 | }; |
| 34 | |
| 35 | static int aat2870_backlight_enable(struct udevice *dev) |
| 36 | { |
| 37 | struct aat2870_backlight_priv *priv = dev_get_priv(dev); |
| 38 | int ret; |
| 39 | |
| 40 | dm_gpio_set_value(&priv->enable_gpio, 1); |
| 41 | |
| 42 | /* Enable backlight for defined set of channels */ |
| 43 | ret = dm_i2c_reg_write(dev, AAT2870_BL_CH_EN, priv->channels); |
| 44 | if (ret) |
| 45 | return ret; |
| 46 | |
| 47 | return 0; |
| 48 | } |
| 49 | |
| 50 | static int aat2870_backlight_set_brightness(struct udevice *dev, int percent) |
| 51 | { |
| 52 | struct aat2870_backlight_priv *priv = dev_get_priv(dev); |
| 53 | int brightness, ret; |
| 54 | |
| 55 | if (percent == BACKLIGHT_DEFAULT) |
| 56 | percent = AAT2870_BL_DEF_BRIGHTNESS; |
| 57 | |
| 58 | if (percent < AAT2870_BL_MIN_BRIGHTNESS) |
| 59 | percent = AAT2870_BL_MIN_BRIGHTNESS; |
| 60 | |
| 61 | if (percent > AAT2870_BL_MAX_BRIGHTNESS) |
| 62 | percent = AAT2870_BL_MAX_BRIGHTNESS; |
| 63 | |
| 64 | brightness = percent * priv->max_current; |
| 65 | brightness /= AAT2870_BL_MAX_BRIGHTNESS; |
| 66 | |
| 67 | /* Set brightness level */ |
| 68 | ret = dm_i2c_reg_write(dev, AAT2870_BLM, brightness); |
| 69 | if (ret) |
| 70 | return ret; |
| 71 | |
| 72 | return 0; |
| 73 | } |
| 74 | |
| 75 | static int aat2870_backlight_of_to_plat(struct udevice *dev) |
| 76 | { |
| 77 | struct aat2870_backlight_priv *priv = dev_get_priv(dev); |
| 78 | int ret; |
| 79 | |
| 80 | ret = gpio_request_by_name(dev, "enable-gpios", 0, |
| 81 | &priv->enable_gpio, GPIOD_IS_OUT); |
| 82 | if (ret) { |
| 83 | log_err("%s: cannot get enable-gpios (%d)\n", |
| 84 | __func__, ret); |
| 85 | return ret; |
| 86 | } |
| 87 | |
| 88 | /* Backlight is one of children but has no dedicated driver */ |
| 89 | ofnode backlight = ofnode_find_subnode(dev_ofnode(dev), "backlight"); |
| 90 | if (ofnode_valid(backlight) && ofnode_is_enabled(backlight)) { |
| 91 | /* Number of channel is equal to bit number */ |
| 92 | priv->channels = dev_read_u32_default(dev, "channels", AAT2870_BL_CH_ALL); |
| 93 | if (priv->channels != AAT2870_BL_CH_ALL) |
| 94 | priv->channels = BIT(priv->channels); |
| 95 | |
| 96 | /* 450mA - 27900mA range with a 900mA step */ |
| 97 | priv->max_current = dev_read_u32_default(dev, "current-max-microamp", |
| 98 | AAT2870_CURRENT_MAX); |
| 99 | priv->max_current /= AAT2870_CURRENT_STEP; |
| 100 | } |
| 101 | |
| 102 | return 0; |
| 103 | } |
| 104 | |
| 105 | static int aat2870_backlight_probe(struct udevice *dev) |
| 106 | { |
| 107 | if (device_get_uclass_id(dev->parent) != UCLASS_I2C) |
| 108 | return -EPROTONOSUPPORT; |
| 109 | |
| 110 | return 0; |
| 111 | } |
| 112 | |
| 113 | static const struct backlight_ops aat2870_backlight_ops = { |
| 114 | .enable = aat2870_backlight_enable, |
| 115 | .set_brightness = aat2870_backlight_set_brightness, |
| 116 | }; |
| 117 | |
| 118 | static const struct udevice_id aat2870_backlight_ids[] = { |
| 119 | { .compatible = "analogictech,aat2870" }, |
| 120 | { .compatible = "skyworks,aat2870" }, |
| 121 | { } |
| 122 | }; |
| 123 | |
| 124 | U_BOOT_DRIVER(aat2870_backlight) = { |
| 125 | .name = "aat2870_backlight", |
| 126 | .id = UCLASS_PANEL_BACKLIGHT, |
| 127 | .of_match = aat2870_backlight_ids, |
| 128 | .of_to_plat = aat2870_backlight_of_to_plat, |
| 129 | .probe = aat2870_backlight_probe, |
| 130 | .ops = &aat2870_backlight_ops, |
| 131 | .priv_auto = sizeof(struct aat2870_backlight_priv), |
| 132 | }; |