^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * LED driver for Mediatek MT6323 PMIC
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/leds.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/mfd/mt6323/registers.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/mfd/mt6397/core.h>
^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/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * Register field for MT6323_TOP_CKPDN0 to enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * 32K clock common for LED device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #define MT6323_RG_DRV_32K_CK_PDN BIT(11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #define MT6323_RG_DRV_32K_CK_PDN_MASK BIT(11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) * Register field for MT6323_TOP_CKPDN2 to enable
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) * individual clock for LED device.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MT6323_RG_ISINK_CK_PDN(i) BIT(i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define MT6323_RG_ISINK_CK_PDN_MASK(i) BIT(i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) * Register field for MT6323_TOP_CKCON1 to select
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) * clock source.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #define MT6323_RG_ISINK_CK_SEL_MASK(i) (BIT(10) << (i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) * Register for MT6323_ISINK_CON0 to setup the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) * duty cycle of the blink.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) #define MT6323_ISINK_CON0(i) (MT6323_ISINK0_CON0 + 0x8 * (i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) #define MT6323_ISINK_DIM_DUTY_MASK (0x1f << 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) #define MT6323_ISINK_DIM_DUTY(i) (((i) << 8) & \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) MT6323_ISINK_DIM_DUTY_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* Register to setup the period of the blink. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) #define MT6323_ISINK_CON1(i) (MT6323_ISINK0_CON1 + 0x8 * (i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) #define MT6323_ISINK_DIM_FSEL_MASK (0xffff)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) #define MT6323_ISINK_DIM_FSEL(i) ((i) & MT6323_ISINK_DIM_FSEL_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) /* Register to control the brightness. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) #define MT6323_ISINK_CON2(i) (MT6323_ISINK0_CON2 + 0x8 * (i))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) #define MT6323_ISINK_CH_STEP_SHIFT 12
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) #define MT6323_ISINK_CH_STEP_MASK (0x7 << 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) #define MT6323_ISINK_CH_STEP(i) (((i) << 12) & \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) MT6323_ISINK_CH_STEP_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) #define MT6323_ISINK_SFSTR0_TC_MASK (0x3 << 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) #define MT6323_ISINK_SFSTR0_TC(i) (((i) << 1) & \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) MT6323_ISINK_SFSTR0_TC_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) #define MT6323_ISINK_SFSTR0_EN_MASK BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) #define MT6323_ISINK_SFSTR0_EN BIT(0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* Register to LED channel enablement. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) #define MT6323_ISINK_CH_EN_MASK(i) BIT(i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) #define MT6323_ISINK_CH_EN(i) BIT(i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) #define MT6323_MAX_PERIOD 10000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) #define MT6323_MAX_LEDS 4
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) #define MT6323_MAX_BRIGHTNESS 6
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) #define MT6323_UNIT_DUTY 3125
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) #define MT6323_CAL_HW_DUTY(o, p) DIV_ROUND_CLOSEST((o) * 100000ul,\
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) (p) * MT6323_UNIT_DUTY)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct mt6323_leds;
^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) * struct mt6323_led - state container for the LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * @id: the identifier in MT6323 LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * @parent: the pointer to MT6323 LED controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) * @cdev: LED class device for this LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * @current_brightness: current state of the LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct mt6323_led {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) int id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) struct mt6323_leds *parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) struct led_classdev cdev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) enum led_brightness current_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * struct mt6323_leds - state container for holding LED controller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * of the driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * @dev: the device pointer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * @hw: the underlying hardware providing shared
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * bus for the register operations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * @lock: the lock among process context
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) * @led: the array that contains the state of individual
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) * LED device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) struct mt6323_leds {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) struct device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) struct mt6397_chip *hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /* protect among process context */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) struct mutex lock;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) struct mt6323_led *led[MT6323_MAX_LEDS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) static int mt6323_led_hw_brightness(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) struct regmap *regmap = leds->hw->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) u32 con2_mask = 0, con2_val = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * Setup current output for the corresponding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * brightness level.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) con2_mask |= MT6323_ISINK_CH_STEP_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) MT6323_ISINK_SFSTR0_TC_MASK |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) MT6323_ISINK_SFSTR0_EN_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) con2_val |= MT6323_ISINK_CH_STEP(brightness - 1) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) MT6323_ISINK_SFSTR0_TC(2) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) MT6323_ISINK_SFSTR0_EN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) ret = regmap_update_bits(regmap, MT6323_ISINK_CON2(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) con2_mask, con2_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return ret;
^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 int mt6323_led_hw_off(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) struct regmap *regmap = leds->hw->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) status = MT6323_ISINK_CH_EN(led->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) MT6323_ISINK_CH_EN_MASK(led->id), ~status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) usleep_range(100, 300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) MT6323_RG_ISINK_CK_PDN_MASK(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) MT6323_RG_ISINK_CK_PDN(led->id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return 0;
^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) static enum led_brightness
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) mt6323_get_led_hw_brightness(struct led_classdev *cdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) struct regmap *regmap = leds->hw->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) ret = regmap_read(regmap, MT6323_TOP_CKPDN2, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (status & MT6323_RG_ISINK_CK_PDN_MASK(led->id))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) ret = regmap_read(regmap, MT6323_ISINK_EN_CTRL, &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) if (!(status & MT6323_ISINK_CH_EN(led->id)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) ret = regmap_read(regmap, MT6323_ISINK_CON2(led->id), &status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) return ((status & MT6323_ISINK_CH_STEP_MASK)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) >> MT6323_ISINK_CH_STEP_SHIFT) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) static int mt6323_led_hw_on(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) struct regmap *regmap = leds->hw->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int ret;
^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) * Setup required clock source, enable the corresponding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) * clock and channel and let work with continuous blink as
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) * the default.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) ret = regmap_update_bits(regmap, MT6323_TOP_CKCON1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) MT6323_RG_ISINK_CK_SEL_MASK(led->id), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) status = MT6323_RG_ISINK_CK_PDN(led->id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) ret = regmap_update_bits(regmap, MT6323_TOP_CKPDN2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) MT6323_RG_ISINK_CK_PDN_MASK(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) ~status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) usleep_range(100, 300);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) ret = regmap_update_bits(regmap, MT6323_ISINK_EN_CTRL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) MT6323_ISINK_CH_EN_MASK(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) MT6323_ISINK_CH_EN(led->id));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) ret = mt6323_led_hw_brightness(cdev, brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) MT6323_ISINK_DIM_DUTY_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) MT6323_ISINK_DIM_DUTY(31));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) MT6323_ISINK_DIM_FSEL_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) MT6323_ISINK_DIM_FSEL(1000));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) static int mt6323_led_set_blink(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) unsigned long *delay_on,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) unsigned long *delay_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) struct regmap *regmap = leds->hw->regmap;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) unsigned long period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) u8 duty_hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) * LED subsystem requires a default user
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) * friendly blink pattern for the LED so using
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) * 1Hz duty cycle 50% here if without specific
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) * value delay_on and delay off being assigned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) if (!*delay_on && !*delay_off) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) *delay_on = 500;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) *delay_off = 500;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * Units are in ms, if over the hardware able
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) * to support, fallback into software blink
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) period = *delay_on + *delay_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) if (period > MT6323_MAX_PERIOD)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) * Calculate duty_hw based on the percentage of period during
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) * which the led is ON.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) duty_hw = MT6323_CAL_HW_DUTY(*delay_on, period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) /* hardware doesn't support zero duty cycle. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (!duty_hw)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) mutex_lock(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) * Set max_brightness as the software blink behavior
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) * when no blink brightness.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (!led->current_brightness) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) ret = mt6323_led_hw_on(cdev, cdev->max_brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) led->current_brightness = cdev->max_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) ret = regmap_update_bits(regmap, MT6323_ISINK_CON0(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) MT6323_ISINK_DIM_DUTY_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) MT6323_ISINK_DIM_DUTY(duty_hw - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) ret = regmap_update_bits(regmap, MT6323_ISINK_CON1(led->id),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) MT6323_ISINK_DIM_FSEL_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) MT6323_ISINK_DIM_FSEL(period - 1));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) mutex_unlock(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int mt6323_led_set_brightness(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) enum led_brightness brightness)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) struct mt6323_leds *leds = led->parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) mutex_lock(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (!led->current_brightness && brightness) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) ret = mt6323_led_hw_on(cdev, brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) } else if (brightness) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) ret = mt6323_led_hw_brightness(cdev, brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) ret = mt6323_led_hw_off(cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) led->current_brightness = brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) mutex_unlock(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) static int mt6323_led_set_dt_default(struct led_classdev *cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) struct device_node *np)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) struct mt6323_led *led = container_of(cdev, struct mt6323_led, cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) const char *state;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) state = of_get_property(np, "default-state", NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (state) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) if (!strcmp(state, "keep")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) ret = mt6323_get_led_hw_brightness(cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) led->current_brightness = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) } else if (!strcmp(state, "on")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) ret =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) mt6323_led_set_brightness(cdev, cdev->max_brightness);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) ret = mt6323_led_set_brightness(cdev, LED_OFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) static int mt6323_led_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) struct device *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) struct device_node *np = dev_of_node(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct device_node *child;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) struct mt6397_chip *hw = dev_get_drvdata(dev->parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) struct mt6323_leds *leds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) struct mt6323_led *led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) unsigned int status;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) u32 reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) if (!leds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) platform_set_drvdata(pdev, leds);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) leds->dev = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) * leds->hw points to the underlying bus for the register
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) * controlled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) leds->hw = hw;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) mutex_init(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390) status = MT6323_RG_DRV_32K_CK_PDN;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) ret = regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) MT6323_RG_DRV_32K_CK_PDN_MASK, ~status);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) dev_err(leds->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) "Failed to update MT6323_TOP_CKPDN0 Register\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) for_each_available_child_of_node(np, child) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct led_init_data init_data = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) ret = of_property_read_u32(child, "reg", ®);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) dev_err(dev, "Failed to read led 'reg' property\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) if (reg >= MT6323_MAX_LEDS || leds->led[reg]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) dev_err(dev, "Invalid led reg %u\n", reg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) if (!led) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) leds->led[reg] = led;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) leds->led[reg]->id = reg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) leds->led[reg]->cdev.max_brightness = MT6323_MAX_BRIGHTNESS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) leds->led[reg]->cdev.brightness_set_blocking =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) mt6323_led_set_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) leds->led[reg]->cdev.blink_set = mt6323_led_set_blink;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) leds->led[reg]->cdev.brightness_get =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) mt6323_get_led_hw_brightness;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) leds->led[reg]->parent = leds;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) ret = mt6323_led_set_dt_default(&leds->led[reg]->cdev, child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) dev_err(leds->dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) "Failed to LED set default from devicetree\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) init_data.fwnode = of_fwnode_handle(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) ret = devm_led_classdev_register_ext(dev, &leds->led[reg]->cdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) &init_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) dev_err(dev, "Failed to register LED: %d\n", ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) goto put_child_node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) put_child_node:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) of_node_put(child);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) static int mt6323_led_remove(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) struct mt6323_leds *leds = platform_get_drvdata(pdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) /* Turn the LEDs off on driver removal. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) for (i = 0 ; leds->led[i] ; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) mt6323_led_hw_off(&leds->led[i]->cdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) regmap_update_bits(leds->hw->regmap, MT6323_TOP_CKPDN0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) MT6323_RG_DRV_32K_CK_PDN_MASK,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) MT6323_RG_DRV_32K_CK_PDN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) mutex_destroy(&leds->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) return 0;
^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) static const struct of_device_id mt6323_led_dt_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) { .compatible = "mediatek,mt6323-led" },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) MODULE_DEVICE_TABLE(of, mt6323_led_dt_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) static struct platform_driver mt6323_led_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) .probe = mt6323_led_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) .remove = mt6323_led_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) .name = "mt6323-led",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) .of_match_table = mt6323_led_dt_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) module_platform_driver(mt6323_led_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) MODULE_DESCRIPTION("LED driver for Mediatek MT6323 PMIC");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) MODULE_LICENSE("GPL");