// SPDX-License-Identifier: GPL-2.0-only /* * leds-tca6507 * * The TCA6507 is a programmable LED controller that can drive 7 * separate lines either by holding them low, or by pulsing them * with modulated width. * The modulation can be varied in a simple pattern to produce a * blink or double-blink. * * This driver can configure each line either as a 'GPIO' which is * out-only (pull-up resistor required) or as an LED with variable * brightness and hardware-assisted blinking. * * Apart from OFF and ON there are three programmable brightness * levels which can be programmed from 0 to 15 and indicate how many * 500usec intervals in each 8msec that the led is 'on'. The levels * are named MASTER, BANK0 and BANK1. * * There are two different blink rates that can be programmed, each * with separate time for rise, on, fall, off and second-off. Thus if * 3 or more different non-trivial rates are required, software must * be used for the extra rates. The two different blink rates must * align with the two levels BANK0 and BANK1. This driver does not * support double-blink so 'second-off' always matches 'off'. * * Only 16 different times can be programmed in a roughly logarithmic * scale from 64ms to 16320ms. To be precise the possible times are: * 0, 64, 128, 192, 256, 384, 512, 768, * 1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320 * * Times that cannot be closely matched with these must be handled in * software. This driver allows 12.5% error in matching. * * This driver does not allow rise/fall rates to be set explicitly. * When trying to match a given 'on' or 'off' period, an appropriate * pair of 'change' and 'hold' times are chosen to get a close match. * If the target delay is even, the 'change' number will be the * smaller; if odd, the 'hold' number will be the smaller. * Choosing pairs of delays with 12.5% errors allows us to match * delays in the ranges: 56-72, 112-144, 168-216, 224-27504, * 28560-36720. * 26% of the achievable sums can be matched by multiple pairings. * For example 1536 == 1536+0, 1024+512, or 768+768. * This driver will always choose the pairing with the least * maximum - 768+768 in this case. Other pairings are not available. * * Access to the 3 levels and 2 blinks are on a first-come, * first-served basis. Access can be shared by multiple leds if they * have the same level and either same blink rates, or some don't * blink. When a led changes, it relinquishes access and tries again, * so it might lose access to hardware blink. * * If a blink engine cannot be allocated, software blink is used. If * the desired brightness cannot be allocated, the closest available * non-zero brightness is used. As 'full' is always available, the * worst case would be to have two different blink rates at '1', with * Max at '2', then other leds will have to choose between '2' and * '16'. Hopefully this is not likely. * * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the * brightness and LEDs using the blink. It can only be reprogrammed * when the appropriate counter is zero. The MASTER level has a * single usage count. * * Each LED has programmable 'on' and 'off' time as milliseconds. * With each there is a flag saying if it was explicitly requested or * defaulted. Similarly the banks know if each time was explicit or a * default. Defaults are permitted to be changed freely - they are * not recognised when matching. */ #include <linux/module.h> #include <linux/slab.h> #include <linux/leds.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/gpio/driver.h> #include <linux/property.h> #include <linux/workqueue.h> /* LED select registers determine the source that drives LED outputs */ #define TCA6507_LS_LED_OFF … #define TCA6507_LS_LED_OFF1 … #define TCA6507_LS_LED_PWM0 … #define TCA6507_LS_LED_PWM1 … #define TCA6507_LS_LED_ON … #define TCA6507_LS_LED_MIR … #define TCA6507_LS_BLINK0 … #define TCA6507_LS_BLINK1 … struct tca6507_platform_data { … }; #define TCA6507_MAKE_GPIO … enum { … }; static int bank_source[3] = …; static int blink_source[2] = …; /* PWM registers */ #define TCA6507_REG_CNT … /* * 0x00, 0x01, 0x02 encode the TCA6507_LS_* values, each output * owns one bit in each register */ #define TCA6507_FADE_ON … #define TCA6507_FULL_ON … #define TCA6507_FADE_OFF … #define TCA6507_FIRST_OFF … #define TCA6507_SECOND_OFF … #define TCA6507_MAX_INTENSITY … #define TCA6507_MASTER_INTENSITY … #define TCA6507_INITIALIZE … #define INIT_CODE … #define TIMECODES … static int time_codes[TIMECODES] = …; /* Convert an led.brightness level (0..255) to a TCA6507 level (0..15) */ static inline int TO_LEVEL(int brightness) { … } /* ...and convert back */ static inline int TO_BRIGHT(int level) { … } #define NUM_LEDS … struct tca6507_chip { … }; static const struct i2c_device_id tca6507_id[] = …; MODULE_DEVICE_TABLE(i2c, tca6507_id); static int choose_times(int msec, int *c1p, int *c2p) { … } /* * Update the register file with the appropriate 3-bit state for the * given led. */ static void set_select(struct tca6507_chip *tca, int led, int val) { … } /* Update the register file with the appropriate 4-bit code for one * bank or other. This can be used for timers, for levels, or for * initialization. */ static void set_code(struct tca6507_chip *tca, int reg, int bank, int new) { … } /* Update brightness level. */ static void set_level(struct tca6507_chip *tca, int bank, int level) { … } /* Record all relevant time codes for a given bank */ static void set_times(struct tca6507_chip *tca, int bank) { … } /* Write all needed register of tca6507 */ static void tca6507_work(struct work_struct *work) { … } static void led_release(struct tca6507_led *led) { … } static int led_prepare(struct tca6507_led *led) { … } static int led_assign(struct tca6507_led *led) { … } static void tca6507_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { … } static int tca6507_blink_set(struct led_classdev *led_cdev, unsigned long *delay_on, unsigned long *delay_off) { … } #ifdef CONFIG_GPIOLIB static void tca6507_gpio_set_value(struct gpio_chip *gc, unsigned offset, int val) { … } static int tca6507_gpio_direction_output(struct gpio_chip *gc, unsigned offset, int val) { … } static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { … } #else /* CONFIG_GPIOLIB */ static int tca6507_probe_gpios(struct device *dev, struct tca6507_chip *tca, struct tca6507_platform_data *pdata) { return 0; } #endif /* CONFIG_GPIOLIB */ static struct tca6507_platform_data * tca6507_led_dt_init(struct device *dev) { … } static const struct of_device_id __maybe_unused of_tca6507_leds_match[] = …; MODULE_DEVICE_TABLE(of, of_tca6507_leds_match); static int tca6507_probe(struct i2c_client *client) { … } static void tca6507_remove(struct i2c_client *client) { … } static struct i2c_driver tca6507_driver = …; module_i2c_driver(…) …; MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;