| 1 | // SPDX-License-Identifier: GPL-2.0 |
| 2 | // Copyright 2015 Texas Instruments |
| 3 | // Copyright 2018 Sebastian Reichel |
| 4 | // Copyright 2018 Pavel Machek <pavel@ucw.cz> |
| 5 | // TI LMU LED common framework, based on previous work from |
| 6 | // Milo Kim <milo.kim@ti.com> |
| 7 | |
| 8 | #include <linux/bitops.h> |
| 9 | #include <linux/err.h> |
| 10 | #include <linux/of_device.h> |
| 11 | |
| 12 | #include <linux/leds-ti-lmu-common.h> |
| 13 | |
| 14 | static const unsigned int ramp_table[16] = {2048, 262000, 524000, 1049000, |
| 15 | 2090000, 4194000, 8389000, 16780000, 33550000, |
| 16 | 41940000, 50330000, 58720000, 67110000, |
| 17 | 83880000, 100660000, 117440000}; |
| 18 | |
| 19 | static int ti_lmu_common_update_brightness(struct ti_lmu_bank *lmu_bank, |
| 20 | int brightness) |
| 21 | { |
| 22 | struct regmap *regmap = lmu_bank->regmap; |
| 23 | u8 reg, val; |
| 24 | int ret; |
| 25 | |
| 26 | /* |
| 27 | * Brightness register update |
| 28 | * |
| 29 | * 11 bit dimming: update LSB bits and write MSB byte. |
| 30 | * MSB brightness should be shifted. |
| 31 | * 8 bit dimming: write MSB byte. |
| 32 | */ |
| 33 | if (lmu_bank->max_brightness == MAX_BRIGHTNESS_11BIT) { |
| 34 | reg = lmu_bank->lsb_brightness_reg; |
| 35 | ret = regmap_update_bits(regmap, reg, |
| 36 | LMU_11BIT_LSB_MASK, |
| 37 | brightness); |
| 38 | if (ret) |
| 39 | return ret; |
| 40 | |
| 41 | val = brightness >> LMU_11BIT_MSB_SHIFT; |
| 42 | } else { |
| 43 | val = brightness; |
| 44 | } |
| 45 | |
| 46 | reg = lmu_bank->msb_brightness_reg; |
| 47 | |
| 48 | return regmap_write(regmap, reg, val); |
| 49 | } |
| 50 | |
| 51 | int ti_lmu_common_set_brightness(struct ti_lmu_bank *lmu_bank, int brightness) |
| 52 | { |
| 53 | return ti_lmu_common_update_brightness(lmu_bank, brightness); |
| 54 | } |
| 55 | EXPORT_SYMBOL(ti_lmu_common_set_brightness); |
| 56 | |
| 57 | static unsigned int ti_lmu_common_convert_ramp_to_index(unsigned int usec) |
| 58 | { |
| 59 | int size = ARRAY_SIZE(ramp_table); |
| 60 | int i; |
| 61 | |
| 62 | if (usec <= ramp_table[0]) |
| 63 | return 0; |
| 64 | |
| 65 | if (usec > ramp_table[size - 1]) |
| 66 | return size - 1; |
| 67 | |
| 68 | for (i = 1; i < size; i++) { |
| 69 | if (usec == ramp_table[i]) |
| 70 | return i; |
| 71 | |
| 72 | /* Find an approximate index by looking up the table */ |
| 73 | if (usec > ramp_table[i - 1] && usec < ramp_table[i]) { |
| 74 | if (usec - ramp_table[i - 1] < ramp_table[i] - usec) |
| 75 | return i - 1; |
| 76 | else |
| 77 | return i; |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | return 0; |
| 82 | } |
| 83 | |
| 84 | int ti_lmu_common_set_ramp(struct ti_lmu_bank *lmu_bank) |
| 85 | { |
| 86 | struct regmap *regmap = lmu_bank->regmap; |
| 87 | u8 ramp, ramp_up, ramp_down; |
| 88 | |
| 89 | if (lmu_bank->ramp_up_usec == 0 && lmu_bank->ramp_down_usec == 0) { |
| 90 | ramp_up = 0; |
| 91 | ramp_down = 0; |
| 92 | } else { |
| 93 | ramp_up = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_up_usec); |
| 94 | ramp_down = ti_lmu_common_convert_ramp_to_index(lmu_bank->ramp_down_usec); |
| 95 | } |
| 96 | |
| 97 | ramp = (ramp_up << 4) | ramp_down; |
| 98 | |
| 99 | return regmap_write(regmap, lmu_bank->runtime_ramp_reg, ramp); |
| 100 | |
| 101 | } |
| 102 | EXPORT_SYMBOL(ti_lmu_common_set_ramp); |
| 103 | |
| 104 | int ti_lmu_common_get_ramp_params(struct device *dev, |
| 105 | struct fwnode_handle *child, |
| 106 | struct ti_lmu_bank *lmu_data) |
| 107 | { |
| 108 | int ret; |
| 109 | |
| 110 | ret = fwnode_property_read_u32(child, "ramp-up-us", |
| 111 | &lmu_data->ramp_up_usec); |
| 112 | if (ret) |
| 113 | dev_warn(dev, "ramp-up-us property missing\n"); |
| 114 | |
| 115 | |
| 116 | ret = fwnode_property_read_u32(child, "ramp-down-us", |
| 117 | &lmu_data->ramp_down_usec); |
| 118 | if (ret) |
| 119 | dev_warn(dev, "ramp-down-us property missing\n"); |
| 120 | |
| 121 | return 0; |
| 122 | } |
| 123 | EXPORT_SYMBOL(ti_lmu_common_get_ramp_params); |
| 124 | |
| 125 | int ti_lmu_common_get_brt_res(struct device *dev, struct fwnode_handle *child, |
| 126 | struct ti_lmu_bank *lmu_data) |
| 127 | { |
| 128 | int ret; |
| 129 | |
| 130 | ret = device_property_read_u32(dev, "ti,brightness-resolution", |
| 131 | &lmu_data->max_brightness); |
| 132 | if (ret) |
| 133 | ret = fwnode_property_read_u32(child, |
| 134 | "ti,brightness-resolution", |
| 135 | &lmu_data->max_brightness); |
| 136 | if (lmu_data->max_brightness <= 0) { |
| 137 | lmu_data->max_brightness = MAX_BRIGHTNESS_8BIT; |
| 138 | return ret; |
| 139 | } |
| 140 | |
| 141 | if (lmu_data->max_brightness > MAX_BRIGHTNESS_11BIT) |
| 142 | lmu_data->max_brightness = MAX_BRIGHTNESS_11BIT; |
| 143 | |
| 144 | |
| 145 | return 0; |
| 146 | } |
| 147 | EXPORT_SYMBOL(ti_lmu_common_get_brt_res); |
| 148 | |
| 149 | MODULE_DESCRIPTION("TI LMU common LED framework"); |
| 150 | MODULE_AUTHOR("Sebastian Reichel"); |
| 151 | MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>"); |
| 152 | MODULE_LICENSE("GPL v2"); |
| 153 | MODULE_ALIAS("ti-lmu-led-common"); |