Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

arm64: dts: qcom: msm8916-samsung-j3/j5: Upstreaming #364

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions drivers/leds/flash/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ config LEDS_AS3645A
config LEDS_KTD2692
tristate "LED support for Kinetic KTD2692 flash LED controller"
depends on OF
depends on GPIOLIB
select LEDS_EXPRESSWIRE
depends on GPIOLIB || COMPILE_TEST
help
This option enables support for Kinetic KTD2692 LED flash connected
through ExpressWire interface.
Expand Down
116 changes: 89 additions & 27 deletions drivers/leds/flash/leds-ktd2692.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
* Ingi Kim <ingi2.kim@samsung.com>
*/

#include <linux/delay.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/leds-expresswire.h>
#include <linux/led-class-flash.h>
#include <linux/module.h>
#include <linux/mutex.h>
Expand Down Expand Up @@ -37,9 +37,22 @@
#define KTD2692_REG_FLASH_CURRENT_BASE 0x80
#define KTD2692_REG_MODE_BASE 0xA0

/* Set bit coding time for expresswire interface */
#define KTD2692_TIME_RESET_US 700
#define KTD2692_TIME_DATA_START_TIME_US 10
#define KTD2692_TIME_HIGH_END_OF_DATA_US 350
#define KTD2692_TIME_LOW_END_OF_DATA_US 10
#define KTD2692_TIME_SHORT_BITSET_US 4
#define KTD2692_TIME_LONG_BITSET_US 12

/* KTD2692 default length of name */
#define KTD2692_NAME_LENGTH 20

enum ktd2692_bitset {
KTD2692_LOW = 0,
KTD2692_HIGH,
};

/* Movie / Flash Mode Control */
enum ktd2692_led_mode {
KTD2692_MODE_DISABLE = 0, /* default */
Expand All @@ -58,19 +71,7 @@ struct ktd2692_led_config_data {
enum led_brightness max_brightness;
};

const struct expresswire_timing ktd2692_timing = {
.poweroff_us = 700,
.data_start_us = 10,
.end_of_data_low_us = 10,
.end_of_data_high_us = 350,
.short_bitset_us = 4,
.long_bitset_us = 12
};

struct ktd2692_context {
/* Common ExpressWire properties (ctrl GPIO and timing) */
struct expresswire_common_props props;

/* Related LED Flash class device */
struct led_classdev_flash fled_cdev;

Expand All @@ -79,6 +80,7 @@ struct ktd2692_context {
struct regulator *regulator;

struct gpio_desc *aux_gpio;
struct gpio_desc *ctrl_gpio;

enum ktd2692_led_mode mode;
enum led_brightness torch_brightness;
Expand All @@ -90,6 +92,67 @@ static struct ktd2692_context *fled_cdev_to_led(
return container_of(fled_cdev, struct ktd2692_context, fled_cdev);
}

static void ktd2692_expresswire_start(struct ktd2692_context *led)
{
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
udelay(KTD2692_TIME_DATA_START_TIME_US);
}

static void ktd2692_expresswire_reset(struct ktd2692_context *led)
{
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
udelay(KTD2692_TIME_RESET_US);
}

static void ktd2692_expresswire_end(struct ktd2692_context *led)
{
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
udelay(KTD2692_TIME_LOW_END_OF_DATA_US);
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
udelay(KTD2692_TIME_HIGH_END_OF_DATA_US);
}

static void ktd2692_expresswire_set_bit(struct ktd2692_context *led, bool bit)
{
/*
* The Low Bit(0) and High Bit(1) is based on a time detection
* algorithm between time low and time high
* Time_(L_LB) : Low time of the Low Bit(0)
* Time_(H_LB) : High time of the LOW Bit(0)
* Time_(L_HB) : Low time of the High Bit(1)
* Time_(H_HB) : High time of the High Bit(1)
*
* It can be simplified to:
* Low Bit(0) : 2 * Time_(H_LB) < Time_(L_LB)
* High Bit(1) : 2 * Time_(L_HB) < Time_(H_HB)
* HIGH ___ ____ _.. _________ ___
* |_________| |_.. |____| |__|
* LOW <L_LB> <H_LB> <L_HB> <H_HB>
* [ Low Bit (0) ] [ High Bit(1) ]
*/
if (bit) {
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
udelay(KTD2692_TIME_SHORT_BITSET_US);
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
udelay(KTD2692_TIME_LONG_BITSET_US);
} else {
gpiod_direction_output(led->ctrl_gpio, KTD2692_LOW);
udelay(KTD2692_TIME_LONG_BITSET_US);
gpiod_direction_output(led->ctrl_gpio, KTD2692_HIGH);
udelay(KTD2692_TIME_SHORT_BITSET_US);
}
}

static void ktd2692_expresswire_write(struct ktd2692_context *led, u8 value)
{
int i;

ktd2692_expresswire_start(led);
for (i = 7; i >= 0; i--)
ktd2692_expresswire_set_bit(led, value & BIT(i));
ktd2692_expresswire_end(led);
}

static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
Expand All @@ -100,14 +163,14 @@ static int ktd2692_led_brightness_set(struct led_classdev *led_cdev,

if (brightness == LED_OFF) {
led->mode = KTD2692_MODE_DISABLE;
gpiod_direction_output(led->aux_gpio, 0);
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
} else {
expresswire_write_u8(&led->props, brightness |
ktd2692_expresswire_write(led, brightness |
KTD2692_REG_MOVIE_CURRENT_BASE);
led->mode = KTD2692_MODE_MOVIE;
}

expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE);
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);
mutex_unlock(&led->lock);

return 0;
Expand All @@ -124,17 +187,17 @@ static int ktd2692_led_flash_strobe_set(struct led_classdev_flash *fled_cdev,

if (state) {
flash_tm_reg = GET_TIMEOUT_OFFSET(timeout->val, timeout->step);
expresswire_write_u8(&led->props, flash_tm_reg
ktd2692_expresswire_write(led, flash_tm_reg
| KTD2692_REG_FLASH_TIMEOUT_BASE);

led->mode = KTD2692_MODE_FLASH;
gpiod_direction_output(led->aux_gpio, 1);
gpiod_direction_output(led->aux_gpio, KTD2692_HIGH);
} else {
led->mode = KTD2692_MODE_DISABLE;
gpiod_direction_output(led->aux_gpio, 0);
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);
}

expresswire_write_u8(&led->props, led->mode | KTD2692_REG_MODE_BASE);
ktd2692_expresswire_write(led, led->mode | KTD2692_REG_MODE_BASE);

fled_cdev->led_cdev.brightness = LED_OFF;
led->mode = KTD2692_MODE_DISABLE;
Expand Down Expand Up @@ -184,12 +247,12 @@ static void ktd2692_init_flash_timeout(struct led_classdev_flash *fled_cdev,
static void ktd2692_setup(struct ktd2692_context *led)
{
led->mode = KTD2692_MODE_DISABLE;
expresswire_power_off(&led->props);
gpiod_direction_output(led->aux_gpio, 0);
ktd2692_expresswire_reset(led);
gpiod_direction_output(led->aux_gpio, KTD2692_LOW);

expresswire_write_u8(&led->props, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
ktd2692_expresswire_write(led, (KTD2692_MM_MIN_CURR_THRESHOLD_SCALE - 1)
| KTD2692_REG_MM_MIN_CURR_THRESHOLD_BASE);
expresswire_write_u8(&led->props, KTD2692_FLASH_MODE_CURR_PERCENT(45)
ktd2692_expresswire_write(led, KTD2692_FLASH_MODE_CURR_PERCENT(45)
| KTD2692_REG_FLASH_CURRENT_BASE);
}

Expand All @@ -214,8 +277,8 @@ static int ktd2692_parse_dt(struct ktd2692_context *led, struct device *dev,
if (!np)
return -ENXIO;

led->props.ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(led->props.ctrl_gpio);
led->ctrl_gpio = devm_gpiod_get(dev, "ctrl", GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(led->ctrl_gpio);
if (ret)
return dev_err_probe(dev, ret, "cannot get ctrl-gpios\n");

Expand Down Expand Up @@ -349,7 +412,6 @@ static struct platform_driver ktd2692_driver = {

module_platform_driver(ktd2692_driver);

MODULE_IMPORT_NS(EXPRESSWIRE);
MODULE_AUTHOR("Ingi Kim <ingi2.kim@samsung.com>");
MODULE_DESCRIPTION("Kinetic KTD2692 LED driver");
MODULE_LICENSE("GPL v2");
Loading