^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * leds-bd2802.c - RGB LED Driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2009 Samsung Electronics
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Kim Kyuwon <q1.kim@samsung.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Datasheet: http://www.rohm.com/products/databook/driver/pdf/bd2802gu-e.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/gpio/consumer.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/leds-bd2802.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define LED_CTL(rgb2en, rgb1en) ((rgb2en) << 4 | ((rgb1en) << 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define BD2802_LED_OFFSET 0xa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define BD2802_COLOR_OFFSET 0x3
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define BD2802_REG_CLKSETUP 0x00
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define BD2802_REG_CONTROL 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define BD2802_REG_HOURSETUP 0x02
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define BD2802_REG_CURRENT1SETUP 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define BD2802_REG_CURRENT2SETUP 0x04
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define BD2802_REG_WAVEPATTERN 0x05
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define BD2802_CURRENT_032 0x10 /* 3.2mA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) #define BD2802_CURRENT_000 0x00 /* 0.0mA */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #define BD2802_PATTERN_FULL 0x07
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #define BD2802_PATTERN_HALF 0x03
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) enum led_ids {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) LED1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) LED2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) LED_NUM,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) enum led_colors {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) RED,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) GREEN,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) BLUE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) enum led_bits {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) BD2802_OFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) BD2802_BLINK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) BD2802_ON,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * State '0' : 'off'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * State '1' : 'blink'
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * State '2' : 'on'.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) struct led_state {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) unsigned r:2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned g:2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) unsigned b:2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct bd2802_led {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct bd2802_led_platform_data *pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct gpio_desc *reset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) struct rw_semaphore rwsem;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct led_state led[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Making led_classdev as array is not recommended, because array
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * members prevent using 'container_of' macro. So repetitive works
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * are needed.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) struct led_classdev cdev_led1r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) struct led_classdev cdev_led1g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct led_classdev cdev_led1b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct led_classdev cdev_led2r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct led_classdev cdev_led2g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct led_classdev cdev_led2b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) * Advanced Configuration Function(ADF) mode:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) * In ADF mode, user can set registers of BD2802GU directly,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * therefore BD2802GU doesn't enter reset state.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int adf_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) enum led_ids led_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) enum led_colors color;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) enum led_bits state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) /* General attributes of RGB LEDs */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) int wave_pattern;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) int rgb_current;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) /*--------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) /* BD2802GU helper functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /*--------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static inline int bd2802_is_rgb_off(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) enum led_colors color)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) switch (color) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) case RED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) return !led->led[id].r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) case GREEN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return !led->led[id].g;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) case BLUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return !led->led[id].b;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) dev_err(&led->client->dev, "%s: Invalid color\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static inline int bd2802_is_led_off(struct bd2802_led *led, enum led_ids id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (led->led[id].r || led->led[id].g || led->led[id].b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static inline int bd2802_is_all_off(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) for (i = 0; i < LED_NUM; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (!bd2802_is_led_off(led, i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) static inline u8 bd2802_get_base_offset(enum led_ids id, enum led_colors color)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) return id * BD2802_LED_OFFSET + color * BD2802_COLOR_OFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static inline u8 bd2802_get_reg_addr(enum led_ids id, enum led_colors color,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) u8 reg_offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return reg_offset + bd2802_get_base_offset(id, color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) /*--------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) /* BD2802GU core functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) /*--------------------------------------------------------------*/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) static int bd2802_write_byte(struct i2c_client *client, u8 reg, u8 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) int ret = i2c_smbus_write_byte_data(client, reg, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) if (ret >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) dev_err(&client->dev, "%s: reg 0x%x, val 0x%x, err %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) __func__, reg, val, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) static void bd2802_update_state(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) enum led_colors color, enum led_bits led_bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) u8 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) for (i = 0; i < LED_NUM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (i == id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) switch (color) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) case RED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) led->led[i].r = led_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) case GREEN:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) led->led[i].g = led_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) case BLUE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) led->led[i].b = led_bit;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) dev_err(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "%s: Invalid color\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) if (led_bit == BD2802_BLINK || led_bit == BD2802_ON)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (!bd2802_is_led_off(led, id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (bd2802_is_all_off(led) && !led->adf_on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) gpiod_set_value(led->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) * In this case, other led is turned on, and current led is turned
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) * off. So set RGB LED Control register to stop the current RGB LED
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) value = (id == LED1) ? LED_CTL(1, 0) : LED_CTL(0, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static void bd2802_configure(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) struct bd2802_led_platform_data *pdata = led->pdata;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) reg = bd2802_get_reg_addr(LED1, RED, BD2802_REG_HOURSETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) bd2802_write_byte(led->client, reg, pdata->rgb_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) reg = bd2802_get_reg_addr(LED2, RED, BD2802_REG_HOURSETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) bd2802_write_byte(led->client, reg, pdata->rgb_time);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static void bd2802_reset_cancel(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) gpiod_set_value(led->reset, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) udelay(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) bd2802_configure(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) static void bd2802_enable(struct bd2802_led *led, enum led_ids id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) enum led_ids other_led = (id == LED1) ? LED2 : LED1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) u8 value, other_led_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) other_led_on = !bd2802_is_led_off(led, other_led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) if (id == LED1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) value = LED_CTL(other_led_on, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) value = LED_CTL(1 , other_led_on);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) bd2802_write_byte(led->client, BD2802_REG_CONTROL, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) static void bd2802_set_on(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) enum led_colors color)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (bd2802_is_all_off(led) && !led->adf_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) bd2802_reset_cancel(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) bd2802_write_byte(led->client, reg, led->rgb_current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) bd2802_write_byte(led->client, reg, BD2802_PATTERN_FULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) bd2802_enable(led, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) bd2802_update_state(led, id, color, BD2802_ON);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) static void bd2802_set_blink(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) enum led_colors color)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) if (bd2802_is_all_off(led) && !led->adf_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) bd2802_reset_cancel(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) bd2802_write_byte(led->client, reg, led->rgb_current);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) reg = bd2802_get_reg_addr(id, color, BD2802_REG_WAVEPATTERN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) bd2802_write_byte(led->client, reg, led->wave_pattern);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) bd2802_enable(led, id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) bd2802_update_state(led, id, color, BD2802_BLINK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) static void bd2802_turn_on(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) enum led_colors color, enum led_bits led_bit)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (led_bit == BD2802_OFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) dev_err(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) "Only 'blink' and 'on' are allowed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (led_bit == BD2802_BLINK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) bd2802_set_blink(led, id, color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) bd2802_set_on(led, id, color);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) static void bd2802_turn_off(struct bd2802_led *led, enum led_ids id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) enum led_colors color)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) u8 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) if (bd2802_is_rgb_off(led, id, color))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT1SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) reg = bd2802_get_reg_addr(id, color, BD2802_REG_CURRENT2SETUP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) bd2802_write_byte(led->client, reg, BD2802_CURRENT_000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) bd2802_update_state(led, id, color, BD2802_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) #define BD2802_SET_REGISTER(reg_addr, reg_name) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) static ssize_t bd2802_store_reg##reg_addr(struct device *dev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) struct device_attribute *attr, const char *buf, size_t count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) unsigned long val; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) int ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) if (!count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) ret = kstrtoul(buf, 16, &val); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) if (ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) return ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) down_write(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) bd2802_write_byte(led->client, reg_addr, (u8) val); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) up_write(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) return count; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static struct device_attribute bd2802_reg##reg_addr##_attr = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) .attr = {.name = reg_name, .mode = 0644}, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) .store = bd2802_store_reg##reg_addr, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) BD2802_SET_REGISTER(0x00, "0x00");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) BD2802_SET_REGISTER(0x01, "0x01");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) BD2802_SET_REGISTER(0x02, "0x02");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) BD2802_SET_REGISTER(0x03, "0x03");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) BD2802_SET_REGISTER(0x04, "0x04");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) BD2802_SET_REGISTER(0x05, "0x05");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) BD2802_SET_REGISTER(0x06, "0x06");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) BD2802_SET_REGISTER(0x07, "0x07");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) BD2802_SET_REGISTER(0x08, "0x08");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) BD2802_SET_REGISTER(0x09, "0x09");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) BD2802_SET_REGISTER(0x0a, "0x0a");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) BD2802_SET_REGISTER(0x0b, "0x0b");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) BD2802_SET_REGISTER(0x0c, "0x0c");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) BD2802_SET_REGISTER(0x0d, "0x0d");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) BD2802_SET_REGISTER(0x0e, "0x0e");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) BD2802_SET_REGISTER(0x0f, "0x0f");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) BD2802_SET_REGISTER(0x10, "0x10");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) BD2802_SET_REGISTER(0x11, "0x11");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) BD2802_SET_REGISTER(0x12, "0x12");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) BD2802_SET_REGISTER(0x13, "0x13");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) BD2802_SET_REGISTER(0x14, "0x14");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) BD2802_SET_REGISTER(0x15, "0x15");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static struct device_attribute *bd2802_addr_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) &bd2802_reg0x00_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) &bd2802_reg0x01_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) &bd2802_reg0x02_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) &bd2802_reg0x03_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) &bd2802_reg0x04_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) &bd2802_reg0x05_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) &bd2802_reg0x06_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) &bd2802_reg0x07_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) &bd2802_reg0x08_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) &bd2802_reg0x09_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) &bd2802_reg0x0a_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) &bd2802_reg0x0b_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) &bd2802_reg0x0c_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) &bd2802_reg0x0d_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) &bd2802_reg0x0e_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) &bd2802_reg0x0f_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) &bd2802_reg0x10_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) &bd2802_reg0x11_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) &bd2802_reg0x12_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) &bd2802_reg0x13_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) &bd2802_reg0x14_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) &bd2802_reg0x15_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) static void bd2802_enable_adv_conf(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) int i, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) ret = device_create_file(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) bd2802_addr_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) dev_err(&led->client->dev, "failed: sysfs file %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) bd2802_addr_attributes[i]->attr.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) goto failed_remove_files;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (bd2802_is_all_off(led))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) bd2802_reset_cancel(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) led->adf_on = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) failed_remove_files:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) for (i--; i >= 0; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) device_remove_file(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) bd2802_addr_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) static void bd2802_disable_adv_conf(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) for (i = 0; i < ARRAY_SIZE(bd2802_addr_attributes); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) device_remove_file(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) bd2802_addr_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) if (bd2802_is_all_off(led))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) gpiod_set_value(led->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) led->adf_on = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) static ssize_t bd2802_show_adv_conf(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) ssize_t ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) down_read(&led->rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) if (led->adf_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) ret = sprintf(buf, "on\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) ret = sprintf(buf, "off\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) up_read(&led->rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) static ssize_t bd2802_store_adv_conf(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) struct device_attribute *attr, const char *buf, size_t count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) if (!count)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) down_write(&led->rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) if (!led->adf_on && !strncmp(buf, "on", 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) bd2802_enable_adv_conf(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) else if (led->adf_on && !strncmp(buf, "off", 3))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) bd2802_disable_adv_conf(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) up_write(&led->rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) static struct device_attribute bd2802_adv_conf_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) .attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) .name = "advanced_configuration",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) .mode = 0644,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) .show = bd2802_show_adv_conf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) .store = bd2802_store_adv_conf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) #define BD2802_CONTROL_ATTR(attr_name, name_str) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) static ssize_t bd2802_show_##attr_name(struct device *dev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) struct device_attribute *attr, char *buf) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) ssize_t ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) down_read(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) ret = sprintf(buf, "0x%02x\n", led->attr_name); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) up_read(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) return ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) static ssize_t bd2802_store_##attr_name(struct device *dev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) struct device_attribute *attr, const char *buf, size_t count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) struct bd2802_led *led = i2c_get_clientdata(to_i2c_client(dev));\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) unsigned long val; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) int ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) if (!count) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) ret = kstrtoul(buf, 16, &val); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) if (ret) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) return ret; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) down_write(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) led->attr_name = val; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) up_write(&led->rwsem); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) return count; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) static struct device_attribute bd2802_##attr_name##_attr = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) .attr = { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) .name = name_str, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) .mode = 0644, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) }, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) .show = bd2802_show_##attr_name, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) .store = bd2802_store_##attr_name, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) BD2802_CONTROL_ATTR(wave_pattern, "wave_pattern");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) BD2802_CONTROL_ATTR(rgb_current, "rgb_current");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) static struct device_attribute *bd2802_attributes[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) &bd2802_adv_conf_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) &bd2802_wave_pattern_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) &bd2802_rgb_current_attr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) #define BD2802_CONTROL_RGBS(name, id, clr) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) static int bd2802_set_##name##_brightness(struct led_classdev *led_cdev,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) enum led_brightness value) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct bd2802_led *led = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) container_of(led_cdev, struct bd2802_led, cdev_##name); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) led->led_id = id; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) led->color = clr; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) if (value == LED_OFF) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) led->state = BD2802_OFF; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) bd2802_turn_off(led, led->led_id, led->color); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) } else { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) led->state = BD2802_ON; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) bd2802_turn_on(led, led->led_id, led->color, BD2802_ON);\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) } \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) static int bd2802_set_##name##_blink(struct led_classdev *led_cdev, \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) unsigned long *delay_on, unsigned long *delay_off) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) { \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) struct bd2802_led *led = \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) container_of(led_cdev, struct bd2802_led, cdev_##name); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) if (*delay_on == 0 || *delay_off == 0) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) return -EINVAL; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) led->led_id = id; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) led->color = clr; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) led->state = BD2802_BLINK; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) bd2802_turn_on(led, led->led_id, led->color, BD2802_BLINK); \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) return 0; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) BD2802_CONTROL_RGBS(led1r, LED1, RED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) BD2802_CONTROL_RGBS(led1g, LED1, GREEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) BD2802_CONTROL_RGBS(led1b, LED1, BLUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) BD2802_CONTROL_RGBS(led2r, LED2, RED);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552) BD2802_CONTROL_RGBS(led2g, LED2, GREEN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) BD2802_CONTROL_RGBS(led2b, LED2, BLUE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) static int bd2802_register_led_classdev(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) led->cdev_led1r.name = "led1_R";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) led->cdev_led1r.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) led->cdev_led1r.brightness_set_blocking = bd2802_set_led1r_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) led->cdev_led1r.blink_set = bd2802_set_led1r_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) ret = led_classdev_register(&led->client->dev, &led->cdev_led1r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) led->cdev_led1r.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) goto failed_unregister_led1_R;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) led->cdev_led1g.name = "led1_G";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) led->cdev_led1g.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) led->cdev_led1g.brightness_set_blocking = bd2802_set_led1g_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) led->cdev_led1g.blink_set = bd2802_set_led1g_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) ret = led_classdev_register(&led->client->dev, &led->cdev_led1g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) led->cdev_led1g.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) goto failed_unregister_led1_G;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) led->cdev_led1b.name = "led1_B";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) led->cdev_led1b.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) led->cdev_led1b.brightness_set_blocking = bd2802_set_led1b_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) led->cdev_led1b.blink_set = bd2802_set_led1b_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) ret = led_classdev_register(&led->client->dev, &led->cdev_led1b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) led->cdev_led1b.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) goto failed_unregister_led1_B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) led->cdev_led2r.name = "led2_R";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) led->cdev_led2r.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) led->cdev_led2r.brightness_set_blocking = bd2802_set_led2r_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) led->cdev_led2r.blink_set = bd2802_set_led2r_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) ret = led_classdev_register(&led->client->dev, &led->cdev_led2r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) led->cdev_led2r.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) goto failed_unregister_led2_R;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) led->cdev_led2g.name = "led2_G";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) led->cdev_led2g.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) led->cdev_led2g.brightness_set_blocking = bd2802_set_led2g_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) led->cdev_led2g.blink_set = bd2802_set_led2g_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) ret = led_classdev_register(&led->client->dev, &led->cdev_led2g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) led->cdev_led2g.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) goto failed_unregister_led2_G;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) led->cdev_led2b.name = "led2_B";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) led->cdev_led2b.brightness = LED_OFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) led->cdev_led2b.brightness_set_blocking = bd2802_set_led2b_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) led->cdev_led2b.blink_set = bd2802_set_led2b_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) led->cdev_led2b.flags |= LED_CORE_SUSPENDRESUME;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) ret = led_classdev_register(&led->client->dev, &led->cdev_led2b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) dev_err(&led->client->dev, "couldn't register LED %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) led->cdev_led2b.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) goto failed_unregister_led2_B;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) failed_unregister_led2_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) led_classdev_unregister(&led->cdev_led2g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) failed_unregister_led2_G:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) led_classdev_unregister(&led->cdev_led2r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) failed_unregister_led2_R:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) led_classdev_unregister(&led->cdev_led1b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) failed_unregister_led1_B:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) led_classdev_unregister(&led->cdev_led1g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) failed_unregister_led1_G:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643) led_classdev_unregister(&led->cdev_led1r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) failed_unregister_led1_R:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) static void bd2802_unregister_led_classdev(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) led_classdev_unregister(&led->cdev_led2b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) led_classdev_unregister(&led->cdev_led2g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) led_classdev_unregister(&led->cdev_led2r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) led_classdev_unregister(&led->cdev_led1b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) led_classdev_unregister(&led->cdev_led1g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) led_classdev_unregister(&led->cdev_led1r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) static int bd2802_probe(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) const struct i2c_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) struct bd2802_led *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) led = devm_kzalloc(&client->dev, sizeof(struct bd2802_led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) if (!led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) led->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) i2c_set_clientdata(client, led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) * Configure RESET GPIO (L: RESET, H: RESET cancel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) * We request the reset GPIO as OUT_LOW which means de-asserted,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) * board files specifying this GPIO line in a machine descriptor
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) * table should take care to specify GPIO_ACTIVE_LOW for this line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) led->reset = devm_gpiod_get(&client->dev, "reset", GPIOD_OUT_LOW);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) if (IS_ERR(led->reset))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) return PTR_ERR(led->reset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) /* Tacss = min 0.1ms */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) udelay(100);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) /* Detect BD2802GU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687) ret = bd2802_write_byte(client, BD2802_REG_CLKSETUP, 0x00);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) dev_err(&client->dev, "failed to detect device\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) dev_info(&client->dev, "return 0x%02x\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) /* To save the power, reset BD2802 after detecting */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) gpiod_set_value(led->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) /* Default attributes */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) led->wave_pattern = BD2802_PATTERN_HALF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) led->rgb_current = BD2802_CURRENT_032;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) init_rwsem(&led->rwsem);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) ret = device_create_file(&led->client->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) bd2802_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) dev_err(&led->client->dev, "failed: sysfs file %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) bd2802_attributes[i]->attr.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) goto failed_unregister_dev_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) ret = bd2802_register_led_classdev(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) goto failed_unregister_dev_file;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) failed_unregister_dev_file:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) for (i--; i >= 0; i--)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) device_remove_file(&led->client->dev, bd2802_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) static int bd2802_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) struct bd2802_led *led = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) gpiod_set_value(led->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) bd2802_unregister_led_classdev(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) if (led->adf_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) bd2802_disable_adv_conf(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) for (i = 0; i < ARRAY_SIZE(bd2802_attributes); i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) device_remove_file(&led->client->dev, bd2802_attributes[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) #ifdef CONFIG_PM_SLEEP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) static void bd2802_restore_state(struct bd2802_led *led)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) for (i = 0; i < LED_NUM; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) if (led->led[i].r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) bd2802_turn_on(led, i, RED, led->led[i].r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) if (led->led[i].g)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) bd2802_turn_on(led, i, GREEN, led->led[i].g);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) if (led->led[i].b)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) bd2802_turn_on(led, i, BLUE, led->led[i].b);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) static int bd2802_suspend(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) struct bd2802_led *led = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) gpiod_set_value(led->reset, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) static int bd2802_resume(struct device *dev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) struct i2c_client *client = to_i2c_client(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) struct bd2802_led *led = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) if (!bd2802_is_all_off(led) || led->adf_on) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) bd2802_reset_cancel(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) bd2802_restore_state(led);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) static SIMPLE_DEV_PM_OPS(bd2802_pm, bd2802_suspend, bd2802_resume);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) static const struct i2c_device_id bd2802_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) { "BD2802", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) { }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) MODULE_DEVICE_TABLE(i2c, bd2802_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) static struct i2c_driver bd2802_i2c_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) .name = "BD2802",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) .pm = &bd2802_pm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) .probe = bd2802_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) .remove = bd2802_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) .id_table = bd2802_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) module_i2c_driver(bd2802_i2c_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) MODULE_AUTHOR("Kim Kyuwon <q1.kim@samsung.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) MODULE_DESCRIPTION("BD2802 LED driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) MODULE_LICENSE("GPL v2");