kernel_samsung_a34x-permissive/drivers/leds/leds-sm5714-fled.c

784 lines
22 KiB
C
Raw Normal View History

/*
* leds-sm5714-fled.c - SM5714 Flash-LEDs device driver
*
* Copyright (C) 2017 Samsung Electronics Co.Ltd
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mfd/sm/sm5714/sm5714.h>
#include <linux/mfd/sm/sm5714/sm5714-private.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/platform_device.h>
static struct sm5714_fled_data *g_sm5714_fled;
extern struct class *camera_class; /*sys/class/camera*/
#ifdef CONFIG_CHARGER_SM5714
extern void sm5714_request_default_power_src(void);
extern int muic_request_disable_afc_state(void);
extern int sm5714_muic_get_vbus_voltage(void);
extern int muic_check_fled_state(int enable, int mode); /* mode:1 = FLED_MODE_TORCH, mode:2 = FLED_MODE_FLASH */
extern int sm5714_usbpd_check_fled_state(bool enable, u8 mode);
#endif
static bool fd_use;
#ifdef CONFIG_CHARGER_SM5714
static void fled_set_enable_push_event(int event_type)
{
int current_op_status = sm5714_charger_oper_get_current_status();
if ((current_op_status & 0x20) || (current_op_status & 0x10)) {
sm5714_charger_oper_push_event(event_type, 1);
usleep_range(2000, 2001);
} else {
pr_info("sm5714-fled: %s : Set otg mode before flash_boost mode Control\n", __func__);
sm5714_charger_oper_push_event(SM5714_CHARGER_OP_EVENT_USB_OTG, 1);
usleep_range(2000, 2001);
sm5714_charger_oper_push_event(event_type, 1);
sm5714_charger_oper_push_event(SM5714_CHARGER_OP_EVENT_USB_OTG, 0);
}
}
static void fled_set_disable_push_event(int event_type)
{
sm5714_charger_oper_push_event(event_type, 0);
}
#endif
static void sm5714_fled_test_read(struct sm5714_fled_data *fled)
{
u8 data;
char str[1016] = {0,};
struct i2c_client *i2c = fled->i2c;
//open-led and short-led protection interrupt/mask/status registers
sm5714_read_reg(i2c, SM5714_CHG_REG_INT5, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_INT5, data);
sm5714_read_reg(i2c, SM5714_CHG_REG_INTMSK5, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_INTMSK5, data);
sm5714_read_reg(i2c, SM5714_CHG_REG_STATUS5, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_STATUS5, data);
//boostpok status register
sm5714_read_reg(i2c, SM5714_CHG_REG_STATUS4, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_STATUS4, data);
//boost enable/disable register
sm5714_read_reg(i2c, SM5714_CHG_REG_CNTL2, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_CNTL2, data);
//fled cntl 1 - timing/mode
sm5714_read_reg(i2c, SM5714_CHG_REG_FLEDCNTL1, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_FLEDCNTL1, data);
//fled cntl 2 - current torch/flash
sm5714_read_reg(i2c, SM5714_CHG_REG_FLEDCNTL2, &data);
sprintf(str+strlen(str), "0x%02x:0x%02x, ", SM5714_CHG_REG_FLEDCNTL2, data);
pr_info("sm5714-fled: %s: %s\n", __func__, str);
}
static void fled_set_mode(struct sm5714_fled_data *fled, u8 mode)
{
sm5714_update_reg(fled->i2c, SM5714_CHG_REG_FLEDCNTL1, (mode << 0), (0x3 << 0));
sm5714_fled_test_read(fled);
}
static void fled_set_fled_current(struct sm5714_fled_data *fled, u8 offset)
{
sm5714_update_reg(fled->i2c, SM5714_CHG_REG_FLEDCNTL2, (offset << 0), (0xf << 0));
sm5714_fled_test_read(fled);
}
static void fled_set_mled_current(struct sm5714_fled_data *fled, u8 offset)
{
sm5714_update_reg(fled->i2c, SM5714_CHG_REG_FLEDCNTL2, (offset << 4), (0x7 << 4));
sm5714_fled_test_read(fled);
pr_info("[%s][D/D] torch current: %d mA\n", __func__, 25*offset + 50);
}
#ifdef CONFIG_CHARGER_SM5714
static int sm5714_fled_check_vbus(struct sm5714_fled_data *fled)
{
fled->vbus_voltage = sm5714_muic_get_vbus_voltage();
pr_info("sm5714-fled: %s: voltage = %d", __func__, fled->vbus_voltage);
if (fled->vbus_voltage > 5500) {
muic_request_disable_afc_state();
sm5714_request_default_power_src();
}
return 0;
}
#endif
static int sm5714_fled_control(u8 fled_mode)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
int ret = 0;
if (g_sm5714_fled == NULL) {
pr_err("sm5714-fled: %s: not probe fled yet\n", __func__);
return -ENXIO;
}
if (fled_mode == FLED_MODE_FLASH) {
ret = gpio_request(fled->pdata->led.fen_pin, "sm5714_fled");
if (ret < 0) {
dev_err(fled->dev, "%s: failed request fen-gpio(%d)", __func__, ret);
fled_set_mode(fled, fled_mode);
fled->pdata->led.used_gpio_ctrl = false;
} else {
gpio_direction_output(fled->pdata->led.fen_pin, 0);
fled_set_mode(fled, FLED_MODE_EXTERNAL);
gpio_set_value(fled->pdata->led.fen_pin, 1);
gpio_set_value(fled->pdata->led.men_pin, 0);
fled->pdata->led.used_gpio_ctrl = true;
}
pr_info("sm5714-fled: %s: Flash mode & used gpio(%d).\n", __func__, fled->pdata->led.used_gpio_ctrl);
fd_use = true;
} else if (fled_mode == FLED_MODE_TORCH) {
ret = gpio_request(fled->pdata->led.men_pin, "sm5714_fled");
if (ret < 0) {
dev_err(fled->dev, "%s: failed request men-gpio(%d)", __func__, ret);
fled_set_mode(fled, fled_mode);
fled->pdata->led.used_gpio_ctrl = false;
} else {
gpio_direction_output(fled->pdata->led.men_pin, 0);
fled_set_mode(fled, FLED_MODE_EXTERNAL);
gpio_set_value(fled->pdata->led.men_pin, 1);
gpio_set_value(fled->pdata->led.fen_pin, 0);
fled->pdata->led.used_gpio_ctrl = true;
}
pr_info("sm5714-fled: %s: Torch mode & used gpio(%d).\n", __func__, fled->pdata->led.used_gpio_ctrl);
fd_use = true;
} else if (fled_mode == FLED_MODE_OFF) {
pr_info("sm5714-fled: %s: off mode & used gpio = %d.\n", __func__, fled->pdata->led.used_gpio_ctrl);
fled_set_mode(fled, fled_mode);
if (fled->pdata->led.used_gpio_ctrl == true) {
gpio_set_value(fled->pdata->led.men_pin, 0);
gpio_set_value(fled->pdata->led.fen_pin, 0);
gpio_free(fled->pdata->led.men_pin);
gpio_free(fled->pdata->led.fen_pin);
fled->pdata->led.used_gpio_ctrl = false;
}
if (fled->pdata->led.en_mled == true) {
fled->torch_on_cnt--;
#ifdef CONFIG_CHARGER_SM5714
if (fled->torch_on_cnt == 0) {
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_TORCH);
if (fled->flash_prepare_cnt == 0) {
muic_check_fled_state(0, FLED_MODE_TORCH);
sm5714_usbpd_check_fled_state(0, FLED_MODE_TORCH);
}
}
#endif
fled->pdata->led.en_mled = false;
}
if (fled->pdata->led.en_fled == true) {
fled->flash_on_cnt--;
#ifdef CONFIG_CHARGER_SM5714
if (fled->flash_on_cnt == 0) {
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_FLASH);
/* flash case, only vbus control, in prepare_flash & close_flash function */
if (fled->flash_prepare_cnt == 0) {
muic_check_fled_state(0, FLED_MODE_FLASH);
sm5714_usbpd_check_fled_state(0, FLED_MODE_FLASH);
}
}
#endif
fled->pdata->led.en_fled = false;
}
fd_use = false;
} else {
pr_err("sm5714-fled: %s: fen_pin : %d, men_pin : %d, FLED_MODE = %d\n"
, __func__, fled->pdata->led.fen_pin, fled->pdata->led.men_pin, fled_mode);
return -EINVAL;
}
return 0;
}
static int sm5714_fled_torch_on(u8 brightness)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
pr_info("sm5714-fled: %s: start.\n", __func__);
if (g_sm5714_fled == NULL) {
pr_err("sm5714-fled: %s: not probe fled yet\n", __func__);
return -ENXIO;
}
mutex_lock(&fled->fled_mutex);
fled_set_mled_current(fled, brightness);
if (fled->pdata->led.en_mled == false) {
#ifdef CONFIG_CHARGER_SM5714
if (fled->torch_on_cnt == 0)
fled_set_enable_push_event(SM5714_CHARGER_OP_EVENT_TORCH);
#endif
fled->pdata->led.en_mled = true;
fled->torch_on_cnt++;
}
sm5714_fled_control(FLED_MODE_TORCH);
mutex_unlock(&fled->fled_mutex);
pr_info("sm5714-fled: %s: done.\n", __func__);
return 0;
}
static int sm5714_fled_flash_on(u8 brightness)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
pr_info("sm5714-fled: %s: start.\n", __func__);
if (g_sm5714_fled == NULL) {
pr_err("sm5714-fled: %s: not probe fled yet\n", __func__);
return -ENXIO;
}
mutex_lock(&fled->fled_mutex);
fled_set_fled_current(fled, brightness);
if (fled->pdata->led.en_fled == false) {
#ifdef CONFIG_CHARGER_SM5714
if (fled->flash_on_cnt == 0)
fled_set_enable_push_event(SM5714_CHARGER_OP_EVENT_FLASH);
#endif
fled->pdata->led.en_fled = true;
fled->flash_on_cnt++;
}
sm5714_fled_control(FLED_MODE_FLASH);
mutex_unlock(&fled->fled_mutex);
pr_info("sm5714-fled: %s: done.\n", __func__);
return 0;
}
static int sm5714_fled_prepare_flash(void)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
pr_info("sm5714-fled: %s: start.\n", __func__);
if (fled == NULL) {
pr_err("sm5714-fled: %s: not probe fled yet\n", __func__);
return -ENXIO;
}
if (fled->pdata->led.pre_fled == true) {
pr_info("sm5714-fled: %s: already prepared\n", __func__);
return 0;
}
mutex_lock(&fled->fled_mutex);
#ifdef CONFIG_CHARGER_SM5714
if (fled->flash_prepare_cnt == 0) {
sm5714_fled_check_vbus(fled);
muic_check_fled_state(1, FLED_MODE_FLASH);
sm5714_usbpd_check_fled_state(1, FLED_MODE_FLASH);
}
#endif
fled_set_fled_current(fled, fled->pdata->led.flash_brightness);
fled_set_mled_current(fled, fled->pdata->led.torch_brightness);
fled->flash_prepare_cnt++;
fled->pdata->led.pre_fled = true;
mutex_unlock(&fled->fled_mutex);
pr_info("sm5714-fled: %s: done.\n", __func__);
return 0;
}
static int sm5714_fled_close_flash(void)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
pr_info("sm5714-fled: %s: start.\n", __func__);
if (fled == NULL) {
pr_err("sm5714-fled: %s: not probe fled yet\n", __func__);
return -ENXIO;
}
if (fled->pdata->led.pre_fled == false) {
pr_info("sm5714-fled: %s: already closed\n", __func__);
return 0;
}
mutex_lock(&fled->fled_mutex);
fled_set_mode(fled, FLED_MODE_OFF);
fled->flash_prepare_cnt--;
#ifdef CONFIG_CHARGER_SM5714
if (fled->flash_prepare_cnt == 0) {
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_TORCH);
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_FLASH);
muic_check_fled_state(0, FLED_MODE_FLASH);
sm5714_usbpd_check_fled_state(0, FLED_MODE_FLASH);
}
#endif
fled->pdata->led.pre_fled = false;
mutex_unlock(&fled->fled_mutex);
pr_info("sm5714-fled: %s: done.\n", __func__);
return 0;
}
/**
* For export Camera flash control support
*
*/
int32_t sm5714_fled_mode_ctrl(int state, uint32_t brightness)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
int ret = 0;
u8 iq_cur = 0;
if (g_sm5714_fled == NULL) {
pr_err("sm5714_fled: %s: g_sm5714_fled is not initialized.\n", __func__);
return -EFAULT;
}
if (brightness > 0 && (state == SM5714_FLED_MODE_TORCH_FLASH || state == SM5714_FLED_MODE_PRE_FLASH)) {
if (brightness < 50)
iq_cur = 0x0;
else if (brightness > 225)
iq_cur = 0x7;
else
iq_cur = (brightness - 50) / 25;
} else if (brightness > 0 && state == SM5714_FLED_MODE_MAIN_FLASH) {
if (brightness < 700)
iq_cur = 0x0;
else if (brightness < 800)
iq_cur = 0x1;
else if (brightness < 900)
iq_cur = 0x2;
else
iq_cur = 3 + (brightness - 900) / 50;
}
pr_info("sm5714-fled: %s: iq_cur=0x%x brightness=%u\n", __func__, iq_cur, brightness);
switch (state) {
case SM5714_FLED_MODE_OFF:
/* FlashLight Mode OFF */
ret = sm5714_fled_control(FLED_MODE_OFF);
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_OFF(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_OFF(%d) done\n", __func__, state);
break;
case SM5714_FLED_MODE_MAIN_FLASH:
/* FlashLight Mode Flash */
if (brightness > 0)
ret = sm5714_fled_flash_on(iq_cur);
else
ret = sm5714_fled_flash_on(fled->pdata->led.flash_brightness);
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_MAIN_FLASH(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_MAIN_FLASH(%d) done\n", __func__, state);
break;
case SM5714_FLED_MODE_TORCH_FLASH: /* TORCH FLASH */
/* FlashLight Mode TORCH */
if (brightness > 0)
ret = sm5714_fled_torch_on(iq_cur);
else
ret = sm5714_fled_torch_on(fled->pdata->led.torch_brightness);
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_TORCH_FLASH(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_TORCH_FLASH(%d) done\n", __func__, state);
break;
case SM5714_FLED_MODE_PRE_FLASH: /* TORCH FLASH */
/* FlashLight Mode TORCH */
if (brightness > 0)
ret = sm5714_fled_torch_on(iq_cur);
else
ret = sm5714_fled_torch_on(fled->pdata->led.preflash_brightness);
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_PRE_FLASH(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_PRE_FLASH(%d) done\n", __func__, state);
break;
case SM5714_FLED_MODE_PREPARE_FLASH:
/* 9V -> 5V VBUS change */
ret = sm5714_fled_prepare_flash();
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_PREPARE_FLASH(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_PREPARE_FLASH(%d) done\n", __func__, state);
break;
case SM5714_FLED_MODE_CLOSE_FLASH:
/* 5V -> 9V VBUS change */
ret = sm5714_fled_close_flash();
if (ret < 0)
pr_err("sm5714-fled: %s: SM5714_FLED_MODE_CLOSE_FLASH(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: SM5714_FLED_MODE_CLOSE_FLASH(%d) done\n", __func__, state);
break;
default:
/* FlashLight Mode OFF */
ret = sm5714_fled_control(FLED_MODE_OFF);
if (ret < 0)
pr_err("sm5714-fled: %s: FLED_MODE_OFF(%d) failed\n", __func__, state);
else
pr_info("sm5714-fled: %s: FLED_MODE_OFF(%d) done\n", __func__, state);
break;
}
return ret;
}
EXPORT_SYMBOL_GPL(sm5714_fled_mode_ctrl);
/**
* For camera_class device file control (Torch-LED)
*/
static ssize_t sm5714_rear_flash_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
u32 store_value;
int ret;
struct sm5714_fled_data *fled = g_sm5714_fled;
if (g_sm5714_fled == NULL) {
pr_err("sm5714-fled: %s: g_sm5714_fled NULL\n", __func__);
return -ENODEV;
}
if ((buf == NULL) || kstrtouint(buf, 10, &store_value))
return -ENXIO;
fled->pdata->led.sysfs_input_data = store_value;
dev_info(fled->dev, "%s: value=%d\n", __func__, store_value);
mutex_lock(&fled->fled_mutex);
if (store_value == 0) { /* 0: Torch or Flash OFF */
if (fled->pdata->led.en_mled == false && fled->pdata->led.en_fled == false)
goto out_skip;
sm5714_fled_control(FLED_MODE_OFF);
dev_info(fled->dev, "%s: en_fled=%d flash_on_cnt=%d\n", __func__, fled->pdata->led.en_fled, fled->flash_on_cnt);
#ifdef CONFIG_CHARGER_SM5714
if (fled->pdata->led.en_fled == true && fled->flash_on_cnt == 0) {
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_TORCH);
fled_set_disable_push_event(SM5714_CHARGER_OP_EVENT_FLASH);
muic_check_fled_state(0, FLED_MODE_FLASH);
sm5714_usbpd_check_fled_state(0, FLED_MODE_FLASH);
}
#endif
} else if (store_value == 200) { /* 200 : Flash ON */
fled_set_fled_current(fled, fled->pdata->led.factory_current); /* Set fled = 300mA */
if (fled->pdata->led.en_fled == true)
goto out_skip;
#ifdef CONFIG_CHARGER_SM5714
if (fled->flash_on_cnt == 0) {
sm5714_fled_check_vbus(fled);
muic_check_fled_state(1, FLED_MODE_FLASH);
sm5714_usbpd_check_fled_state(1, FLED_MODE_FLASH);
fled_set_enable_push_event(SM5714_CHARGER_OP_EVENT_FLASH);
}
#endif
sm5714_fled_control(FLED_MODE_FLASH);
fled->pdata->led.en_fled = true;
fled->flash_on_cnt++;
} else { /* 1, 100, 1001~1010, : Torch ON */
/* Main Torch on */
if (store_value == 1) {
fled_set_mled_current(fled, 0x1); /* Set mled = 75mA(0x1) */
/* Factory Torch on */
} else if (store_value == 100) {
fled_set_mled_current(fled, 0x7); /* Set mled=225mA */
} else if (store_value >= 1001 && store_value <= 1010) {
/* Torch on (Normal) */
if (store_value-1001 > 7)
fled_set_mled_current(fled, 0x07); /* Max 225mA(0x7) */
else {
fled_set_mled_current(fled, (store_value-1001));
/* 50mA(0x0) ~ 225mA(0x7) at 25mA step */
}
} else {
dev_err(fled->dev, "%s: failed store cmd\n", __func__);
ret = -EINVAL;
goto out_p;
}
dev_info(fled->dev, "%s: en_mled=%d, torch_on_cnt = %d\n"
, __func__, fled->pdata->led.en_mled, fled->torch_on_cnt);
if (fled->pdata->led.en_mled == true)
goto out_skip;
#ifdef CONFIG_CHARGER_SM5714
if (fled->torch_on_cnt == 0) {
sm5714_fled_check_vbus(fled);
muic_check_fled_state(1, FLED_MODE_TORCH);
sm5714_usbpd_check_fled_state(1, FLED_MODE_TORCH);
fled_set_enable_push_event(SM5714_CHARGER_OP_EVENT_TORCH);
}
#endif
sm5714_fled_control(FLED_MODE_TORCH);
fled->pdata->led.en_mled = true;
fled->torch_on_cnt++;
}
out_skip:
ret = count;
out_p:
mutex_unlock(&fled->fled_mutex);
return count;
}
static ssize_t sm5714_rear_flash_show(struct device *dev, struct device_attribute *attr, char *buf)
{
struct sm5714_fled_data *fled = g_sm5714_fled;
if (g_sm5714_fled == NULL) {
pr_err("sm5714-fled: %s: g_sm5714_fled is NULL\n", __func__);
return -ENODEV;
}
return sprintf(buf, "%d\n", fled->pdata->led.sysfs_input_data);
}
static DEVICE_ATTR(rear_flash, 0664, sm5714_rear_flash_show, sm5714_rear_flash_store);
bool sm5714_is_fd_in_use(void)
{
return fd_use;
}
EXPORT_SYMBOL(sm5714_is_fd_in_use);
static int sm5714_fled_parse_dt(struct device *dev, struct sm5714_fled_platform_data *pdata)
{
struct device_node *np;
u32 temp;
int ret;
dev_info(dev, "%s: parse from dtsi file\n", __func__);
np = of_find_node_by_name(NULL, "sm5714-fled");
if (!np) {
dev_err(dev, "%s: can't find sm5714-fled np\n", __func__);
return -EINVAL;
}
of_property_read_u32(np, "flash-brightness", &temp);
pdata->led.flash_brightness = (temp & 0xff);
of_property_read_u32(np, "preflash-brightness", &temp);
pdata->led.preflash_brightness = (temp & 0xff);
of_property_read_u32(np, "torch-brightness", &temp);
pdata->led.torch_brightness = (temp & 0xff);
of_property_read_u32(np, "timeout", &temp);
pdata->led.timeout = (temp & 0xff);
of_property_read_u8(np, "factory_current", &pdata->led.factory_current);
ret = pdata->led.fen_pin = of_get_named_gpio(np, "flash-en-gpio", 0);
if (ret < 0) {
pr_err("%s : can't get flash-en-gpio\n", __func__);
return ret;
}
ret = pdata->led.men_pin = of_get_named_gpio(np, "torch-en-gpio", 0);
if (ret < 0) {
pr_err("%s : can't get torch-en-gpio\n", __func__);
return ret;
}
dev_info(dev, "%s: f_cur=0x%x, pre_cur=0x%x, t_cur=0x%x, tout=%d, gpio=%d:%d\n",
__func__, pdata->led.flash_brightness, pdata->led.preflash_brightness,
pdata->led.torch_brightness, pdata->led.timeout, pdata->led.fen_pin, pdata->led.men_pin);
dev_info(dev, "%s: parse dt done.\n", __func__);
return 0;
}
static void sm5714_fled_init(struct sm5714_fled_data *fled)
{
fled_set_mode(fled, FLED_MODE_OFF);
fled->pdata->led.en_mled = 0;
fled->pdata->led.en_fled = 0;
fled->pdata->led.pre_fled = 0;
fled->pdata->led.used_gpio_ctrl = 0;
fled->torch_on_cnt = 0;
fled->flash_on_cnt = 0;
fled->flash_prepare_cnt = 0;
mutex_init(&fled->fled_mutex);
fd_use = false;
sm5714_fled_test_read(fled);
dev_info(fled->dev, "%s: flash init done\n", __func__);
}
static int sm5714_fled_probe(struct platform_device *pdev)
{
struct sm5714_dev *sm5714 = dev_get_drvdata(pdev->dev.parent);
struct sm5714_fled_data *fled;
int ret = 0;
dev_info(&pdev->dev, "sm5714 fled probe start (rev=%d) pdev=%p\n", sm5714->pmic_rev, pdev);
fled = devm_kzalloc(&pdev->dev, sizeof(struct sm5714_fled_data), GFP_KERNEL);
if (unlikely(!fled)) {
dev_err(&pdev->dev, "%s: fail to alloc_devm\n", __func__);
return -ENOMEM;
}
fled->dev = &pdev->dev;
fled->i2c = sm5714->charger;
fled->pdata = devm_kzalloc(&pdev->dev, sizeof(struct sm5714_fled_platform_data), GFP_KERNEL);
if (unlikely(!fled->pdata)) {
dev_err(fled->dev, "%s: fail to alloc_pdata\n", __func__);
ret = -ENOMEM;
goto free_dev;
}
ret = sm5714_fled_parse_dt(fled->dev, fled->pdata);
if (ret < 0)
goto free_pdata;
sm5714_fled_init(fled);
g_sm5714_fled = fled;
if (camera_class == NULL)
camera_class = class_create(THIS_MODULE, "camera");
if (IS_ERR_OR_NULL(camera_class)) {
dev_err(fled->dev, "%s: can't find camera_class sysfs object", __func__);
dev_err(fled->dev, ", didn't used rear_flash attribute\n");
goto free_pdata;
}
fled->rear_fled_dev = device_create(camera_class, NULL, 0, NULL, "flash");
if (IS_ERR(fled->rear_fled_dev)) {
dev_err(fled->dev, "%s failed create device for rear_flash\n", __func__);
goto free_pdata;
}
fled->rear_fled_dev->parent = fled->dev;
ret = device_create_file(fled->rear_fled_dev, &dev_attr_rear_flash);
if (IS_ERR_VALUE((unsigned long)ret)) {
dev_err(fled->dev, "%s failed create device file for rear_flash\n", __func__);
goto free_device;
}
dev_info(&pdev->dev, "sm5714 fled probe done.\n");
return 0;
free_device:
device_destroy(camera_class, fled->rear_fled_dev->devt);
free_pdata:
devm_kfree(&pdev->dev, fled->pdata);
free_dev:
devm_kfree(&pdev->dev, fled);
return ret;
}
static int sm5714_fled_remove(struct platform_device *pdev)
{
struct sm5714_fled_data *fled = platform_get_drvdata(pdev);
device_remove_file(fled->rear_fled_dev, &dev_attr_rear_flash);
device_destroy(camera_class, fled->rear_fled_dev->devt);
fled_set_mode(fled, FLED_MODE_OFF);
platform_set_drvdata(pdev, NULL);
devm_kfree(&pdev->dev, fled->pdata);
devm_kfree(&pdev->dev, fled);
return 0;
}
static const struct of_device_id sm5714_fled_match_table[] = {
{ .compatible = "siliconmitus,sm5714-fled",},
{},
};
static const struct platform_device_id sm5714_fled_id[] = {
{"sm5714-fled", 0},
{},
};
static struct platform_driver sm5714_led_driver = {
.driver = {
.name = "sm5714-fled",
.owner = THIS_MODULE,
.of_match_table = sm5714_fled_match_table,
},
.probe = sm5714_fled_probe,
.remove = sm5714_fled_remove,
.id_table = sm5714_fled_id,
};
static int __init sm5714_led_driver_init(void)
{
return platform_driver_register(&sm5714_led_driver);
}
late_initcall(sm5714_led_driver_init);
static void __exit sm5714_led_driver_exit(void)
{
platform_driver_unregister(&sm5714_led_driver);
}
module_exit(sm5714_led_driver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Samsung Electronics");
MODULE_DESCRIPTION("Flash-LED device driver for SM5714");