831 lines
22 KiB
C
831 lines
22 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* Copyright (c) 2021 MediaTek Inc.
|
|
*/
|
|
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/of.h>
|
|
#include <linux/delay.h>
|
|
#include "../../flashlight/richtek/rtfled.h"
|
|
|
|
#include "inc/mt6370_pmu.h"
|
|
#include "inc/mt6370_pmu_fled.h"
|
|
#include "inc/mt6370_pmu_charger.h"
|
|
|
|
#define MT6370_PMU_FLED_DRV_VERSION "1.0.3_MTK"
|
|
|
|
static DEFINE_MUTEX(fled_lock);
|
|
|
|
static u8 mt6370_fled_inited;
|
|
static u8 mt6370_global_mode = FLASHLIGHT_MODE_OFF;
|
|
|
|
static u8 mt6370_fled_on;
|
|
|
|
enum {
|
|
MT6370_FLED1 = 0,
|
|
MT6370_FLED2 = 1,
|
|
};
|
|
|
|
struct mt6370_pmu_fled_data {
|
|
struct rt_fled_dev base;
|
|
struct mt6370_pmu_chip *chip;
|
|
struct device *dev;
|
|
struct platform_device *mt_flash_dev;
|
|
int id;
|
|
unsigned char suspend:1;
|
|
unsigned char fled_ctrl:2; /* fled1, fled2, both */
|
|
unsigned char fled_ctrl_reg;
|
|
unsigned char fled_tor_cur_reg;
|
|
unsigned char fled_strb_cur_reg;
|
|
unsigned char fled_strb_to_reg;
|
|
unsigned char fled_cs_mask;
|
|
};
|
|
|
|
static const char *flashlight_mode_str[FLASHLIGHT_MODE_MAX] = {
|
|
"off", "torch", "flash", "mixed",
|
|
"dual flash", "dual torch", "dual off",
|
|
};
|
|
|
|
static irqreturn_t mt6370_pmu_fled_strbpin_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled_torpin_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled_tx_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled_lvf_irq_handler(int irq, void *data)
|
|
{
|
|
struct mt6370_pmu_fled_data *info = data;
|
|
|
|
dev_notice(info->dev, "%s\n", __func__);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled2_short_irq_handler(int irq, void *data)
|
|
{
|
|
struct mt6370_pmu_fled_data *info = data;
|
|
|
|
dev_notice(info->dev, "%s\n", __func__);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled1_short_irq_handler(int irq, void *data)
|
|
{
|
|
struct mt6370_pmu_fled_data *info = data;
|
|
|
|
dev_notice(info->dev, "%s\n", __func__);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled2_strb_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled1_strb_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled2_strb_to_irq_handler(int irq, void *data)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)data;
|
|
|
|
dev_info(fi->dev, "%s occurred\n", __func__);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled1_strb_to_irq_handler(int irq, void *data)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)data;
|
|
|
|
dev_info(fi->dev, "%s occurred\n", __func__);
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled2_tor_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static irqreturn_t mt6370_pmu_fled1_tor_irq_handler(int irq, void *data)
|
|
{
|
|
return IRQ_HANDLED;
|
|
}
|
|
|
|
static struct mt6370_pmu_irq_desc mt6370_fled_irq_desc[] = {
|
|
MT6370_PMU_IRQDESC(fled_strbpin),
|
|
MT6370_PMU_IRQDESC(fled_torpin),
|
|
MT6370_PMU_IRQDESC(fled_tx),
|
|
MT6370_PMU_IRQDESC(fled_lvf),
|
|
MT6370_PMU_IRQDESC(fled2_short),
|
|
MT6370_PMU_IRQDESC(fled1_short),
|
|
MT6370_PMU_IRQDESC(fled2_strb),
|
|
MT6370_PMU_IRQDESC(fled1_strb),
|
|
MT6370_PMU_IRQDESC(fled2_strb_to),
|
|
MT6370_PMU_IRQDESC(fled1_strb_to),
|
|
MT6370_PMU_IRQDESC(fled2_tor),
|
|
MT6370_PMU_IRQDESC(fled1_tor),
|
|
};
|
|
|
|
static void mt6370_pmu_fled_irq_register(struct platform_device *pdev)
|
|
{
|
|
struct resource *res;
|
|
int i, ret = 0;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mt6370_fled_irq_desc); i++) {
|
|
if (!mt6370_fled_irq_desc[i].name)
|
|
continue;
|
|
res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
|
|
mt6370_fled_irq_desc[i].name);
|
|
if (!res)
|
|
continue;
|
|
ret = devm_request_threaded_irq(&pdev->dev, res->start, NULL,
|
|
mt6370_fled_irq_desc[i].irq_handler,
|
|
IRQF_TRIGGER_FALLING,
|
|
mt6370_fled_irq_desc[i].name,
|
|
platform_get_drvdata(pdev));
|
|
if (ret < 0) {
|
|
dev_err(&pdev->dev, "request %s irq fail\n", res->name);
|
|
continue;
|
|
}
|
|
mt6370_fled_irq_desc[i].irq = res->start;
|
|
}
|
|
}
|
|
|
|
static inline int mt6370_fled_parse_dt(struct device *dev,
|
|
struct mt6370_pmu_fled_data *fi)
|
|
{
|
|
struct device_node *np = dev->of_node;
|
|
int ret = 0;
|
|
u32 val = 0;
|
|
unsigned char regval;
|
|
|
|
pr_info("%s start\n", __func__);
|
|
if (!np) {
|
|
pr_err("%s cannot mt6370 fled dts node\n", __func__);
|
|
return -ENODEV;
|
|
}
|
|
|
|
#if 0
|
|
ret = of_property_read_u32(np, "fled_enable", &val);
|
|
if (ret < 0) {
|
|
pr_err("%s default enable fled%d\n", __func__, fi->id+1);
|
|
} else {
|
|
if (val) {
|
|
pr_info("%s enable fled%d\n", __func__, fi->id+1);
|
|
mt6370_pmu_reg_set_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, fi->fled_cs_mask);
|
|
} else {
|
|
pr_info("%s disable fled%d\n", __func__, fi->id+1);
|
|
mt6370_pmu_reg_clr_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, fi->fled_cs_mask);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
ret = of_property_read_u32(np, "torch_cur", &val);
|
|
if (ret < 0)
|
|
pr_err("%s use default torch cur\n", __func__);
|
|
else {
|
|
pr_info("%s use torch cur %d\n", __func__, val);
|
|
regval = (val > 400000) ? 30 : (val - 25000)/12500;
|
|
mt6370_pmu_reg_update_bits(fi->chip,
|
|
fi->fled_tor_cur_reg,
|
|
MT6370_FLED_TORCHCUR_MASK,
|
|
regval << MT6370_FLED_TORCHCUR_SHIFT);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "strobe_cur", &val);
|
|
if (ret < 0)
|
|
pr_err("%s use default strobe cur\n", __func__);
|
|
else {
|
|
pr_info("%s use strobe cur %d\n", __func__, val);
|
|
regval = (val > 1500000) ? 112 : (val - 100000)/12500;
|
|
mt6370_pmu_reg_update_bits(fi->chip,
|
|
fi->fled_strb_cur_reg,
|
|
MT6370_FLED_STROBECUR_MASK,
|
|
regval << MT6370_FLED_STROBECUR_SHIFT);
|
|
}
|
|
|
|
ret = of_property_read_u32(np, "strobe_timeout", &val);
|
|
if (ret < 0)
|
|
pr_err("%s use default strobe timeout\n", __func__);
|
|
else {
|
|
pr_info("%s use strobe timeout %d\n", __func__, val);
|
|
regval = (val > 2432) ? 74 : (val - 64)/32;
|
|
mt6370_pmu_reg_update_bits(fi->chip,
|
|
MT6370_PMU_REG_FLEDSTRBCTRL,
|
|
MT6370_FLED_STROBE_TIMEOUT_MASK,
|
|
regval << MT6370_FLED_STROBE_TIMEOUT_SHIFT);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static struct flashlight_properties mt6370_fled_props = {
|
|
.type = FLASHLIGHT_TYPE_LED,
|
|
.torch_brightness = 0,
|
|
.torch_max_brightness = 30, /* 00000 ~ 11110 */
|
|
.strobe_brightness = 0,
|
|
.strobe_max_brightness = 255, /* 0000000 ~ 1111111 */
|
|
.strobe_delay = 0,
|
|
.strobe_timeout = 0,
|
|
.alias_name = "mt6370-fled",
|
|
};
|
|
|
|
static int mt6370_fled_reg_init(struct mt6370_pmu_fled_data *info)
|
|
{
|
|
/* TBD */
|
|
return 0;
|
|
}
|
|
|
|
static int mt6370_fled_init(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
ret = mt6370_fled_reg_init(fi);
|
|
if (ret < 0)
|
|
dev_err(fi->dev, "init mt6370 fled register fail\n");
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_suspend(struct rt_fled_dev *info, pm_message_t state)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
|
|
fi->suspend = 1;
|
|
return 0;
|
|
}
|
|
|
|
static int mt6370_fled_resume(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
|
|
fi->suspend = 0;
|
|
return 0;
|
|
}
|
|
|
|
static int mt6370_fled_set_mode(struct rt_fled_dev *info,
|
|
enum flashlight_mode mode)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
u8 val, mask;
|
|
bool hz_en = false, cfo_en = true;
|
|
|
|
switch (mode) {
|
|
case FLASHLIGHT_MODE_FLASH:
|
|
case FLASHLIGHT_MODE_DUAL_FLASH:
|
|
ret = mt6370_pmu_reg_test_bit(fi->chip, MT6370_PMU_REG_CHGCTRL1,
|
|
MT6370_SHIFT_HZ_EN, &hz_en);
|
|
if (ret >= 0 && hz_en) {
|
|
dev_err(fi->dev, "%s WARNING\n", __func__);
|
|
dev_err(fi->dev, "%s set %s mode with HZ=1\n",
|
|
__func__, flashlight_mode_str[mode]);
|
|
}
|
|
|
|
ret = mt6370_pmu_reg_test_bit(fi->chip, MT6370_PMU_REG_CHGCTRL2,
|
|
MT6370_SHIFT_CFO_EN, &cfo_en);
|
|
if (ret >= 0 && !cfo_en) {
|
|
dev_err(fi->dev, "%s WARNING\n", __func__);
|
|
dev_err(fi->dev, "%s set %s mode with CFO=0\n",
|
|
__func__, flashlight_mode_str[mode]);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
mutex_lock(&fled_lock);
|
|
switch (mode) {
|
|
case FLASHLIGHT_MODE_TORCH:
|
|
if (mt6370_global_mode == FLASHLIGHT_MODE_FLASH)
|
|
break;
|
|
ret |= mt6370_pmu_reg_clr_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, MT6370_STROBE_EN_MASK);
|
|
udelay(500);
|
|
ret |= mt6370_pmu_reg_set_bit(fi->chip, MT6370_PMU_REG_FLEDEN,
|
|
fi->id == MT6370_FLED1 ? 0x02 : 0x01);
|
|
ret |= mt6370_pmu_reg_set_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, MT6370_TORCH_EN_MASK);
|
|
udelay(500);
|
|
dev_info(fi->dev, "set to torch mode with 500 us delay\n");
|
|
mt6370_global_mode = mode;
|
|
if (fi->id == MT6370_FLED1)
|
|
mt6370_fled_on |= 1 << MT6370_FLED1;
|
|
if (fi->id == MT6370_FLED2)
|
|
mt6370_fled_on |= 1 << MT6370_FLED2;
|
|
break;
|
|
case FLASHLIGHT_MODE_FLASH:
|
|
ret = mt6370_pmu_reg_clr_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, MT6370_STROBE_EN_MASK);
|
|
udelay(400);
|
|
ret |= mt6370_pmu_reg_set_bit(fi->chip, MT6370_PMU_REG_FLEDEN,
|
|
fi->id == MT6370_FLED1 ? 0x02 : 0x01);
|
|
ret |= mt6370_pmu_reg_set_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, MT6370_STROBE_EN_MASK);
|
|
mdelay(5);
|
|
dev_info(fi->dev, "set to flash mode with 400/4500 us delay\n");
|
|
mt6370_global_mode = mode;
|
|
if (fi->id == MT6370_FLED1)
|
|
mt6370_fled_on |= 1 << MT6370_FLED1;
|
|
if (fi->id == MT6370_FLED2)
|
|
mt6370_fled_on |= 1 << MT6370_FLED2;
|
|
break;
|
|
case FLASHLIGHT_MODE_OFF:
|
|
ret = mt6370_pmu_reg_clr_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN,
|
|
fi->id == MT6370_FLED1 ? 0x02 : 0x01);
|
|
dev_info(fi->dev, "set to off mode\n");
|
|
if (fi->id == MT6370_FLED1)
|
|
mt6370_fled_on &= ~(1 << MT6370_FLED1);
|
|
if (fi->id == MT6370_FLED2)
|
|
mt6370_fled_on &= ~(1 << MT6370_FLED2);
|
|
if (mt6370_fled_on == 0)
|
|
mt6370_global_mode = mode;
|
|
break;
|
|
case FLASHLIGHT_MODE_DUAL_FLASH:
|
|
if (fi->id == MT6370_FLED2)
|
|
goto out;
|
|
/* strobe off */
|
|
ret = mt6370_pmu_reg_clr_bit(fi->chip, MT6370_PMU_REG_FLEDEN,
|
|
MT6370_STROBE_EN_MASK);
|
|
if (ret < 0)
|
|
break;
|
|
udelay(400);
|
|
/* fled en/strobe on */
|
|
val = BIT(MT6370_FLED1) | BIT(MT6370_FLED2) |
|
|
MT6370_STROBE_EN_MASK;
|
|
mask = val;
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN,
|
|
mask, val);
|
|
if (ret < 0)
|
|
break;
|
|
mt6370_global_mode = mode;
|
|
mt6370_fled_on |= (BIT(MT6370_FLED1) | BIT(MT6370_FLED2));
|
|
break;
|
|
case FLASHLIGHT_MODE_DUAL_TORCH:
|
|
if (fi->id == MT6370_FLED2)
|
|
goto out;
|
|
if (mt6370_global_mode == FLASHLIGHT_MODE_FLASH ||
|
|
mt6370_global_mode == FLASHLIGHT_MODE_DUAL_FLASH)
|
|
goto out;
|
|
/* Fled en/Strobe off/Torch on */
|
|
ret = mt6370_pmu_reg_clr_bit(fi->chip, MT6370_PMU_REG_FLEDEN,
|
|
MT6370_STROBE_EN_MASK);
|
|
if (ret < 0)
|
|
break;
|
|
udelay(500);
|
|
val = BIT(MT6370_FLED1) | BIT(MT6370_FLED2) |
|
|
MT6370_TORCH_EN_MASK;
|
|
ret = mt6370_pmu_reg_set_bit(fi->chip,
|
|
MT6370_PMU_REG_FLEDEN, val);
|
|
if (ret < 0)
|
|
break;
|
|
udelay(500);
|
|
mt6370_global_mode = mode;
|
|
mt6370_fled_on |= (BIT(MT6370_FLED1) | BIT(MT6370_FLED2));
|
|
break;
|
|
case FLASHLIGHT_MODE_DUAL_OFF:
|
|
if (fi->id == MT6370_FLED2)
|
|
goto out;
|
|
ret = mt6370_pmu_reg_clr_bit(fi->chip, MT6370_PMU_REG_FLEDEN,
|
|
BIT(MT6370_FLED1) | BIT(MT6370_FLED2));
|
|
if (ret < 0)
|
|
break;
|
|
mt6370_fled_on = 0;
|
|
mt6370_global_mode = FLASHLIGHT_MODE_OFF;
|
|
break;
|
|
default:
|
|
mutex_unlock(&fled_lock);
|
|
return -EINVAL;
|
|
}
|
|
if (ret < 0)
|
|
dev_info(fi->dev, "%s set %s mode fail\n", __func__,
|
|
flashlight_mode_str[mode]);
|
|
else
|
|
dev_info(fi->dev, "%s set %s\n", __func__,
|
|
flashlight_mode_str[mode]);
|
|
out:
|
|
mutex_unlock(&fled_lock);
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_get_mode(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret;
|
|
|
|
if (fi->id == MT6370_FLED2) {
|
|
pr_err("%s FLED2 not support get mode\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
ret = mt6370_pmu_reg_read(fi->chip, MT6370_PMU_REG_FLEDEN);
|
|
if (ret < 0)
|
|
return -EINVAL;
|
|
|
|
if (ret & MT6370_STROBE_EN_MASK)
|
|
return FLASHLIGHT_MODE_FLASH;
|
|
else if (ret & MT6370_TORCH_EN_MASK)
|
|
return FLASHLIGHT_MODE_TORCH;
|
|
else
|
|
return FLASHLIGHT_MODE_OFF;
|
|
}
|
|
|
|
static int mt6370_fled_strobe(struct rt_fled_dev *info)
|
|
{
|
|
return mt6370_fled_set_mode(info, FLASHLIGHT_MODE_FLASH);
|
|
}
|
|
|
|
static int mt6370_fled_torch_current_list(
|
|
struct rt_fled_dev *info, int selector)
|
|
{
|
|
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
|
|
return (selector > fi->base.init_props->torch_max_brightness) ?
|
|
-EINVAL : 25000 + selector * 12500;
|
|
}
|
|
|
|
static int mt6370_fled_strobe_current_list(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
|
|
if (selector > fi->base.init_props->strobe_max_brightness)
|
|
return -EINVAL;
|
|
if (selector < 128)
|
|
return 50000 + selector * 12500;
|
|
else
|
|
return 25000 + (selector - 128) * 6250;
|
|
}
|
|
|
|
static unsigned int mt6370_timeout_level_list[] = {
|
|
50000, 75000, 100000, 125000, 150000, 175000, 200000, 200000,
|
|
};
|
|
|
|
static int mt6370_fled_timeout_level_list(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
return (selector >= ARRAY_SIZE(mt6370_timeout_level_list)) ?
|
|
-EINVAL : mt6370_timeout_level_list[selector];
|
|
}
|
|
|
|
static int mt6370_fled_strobe_timeout_list(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
if (selector > 74)
|
|
return -EINVAL;
|
|
return 64 + selector * 32;
|
|
}
|
|
|
|
static int mt6370_fled_set_torch_current_sel(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret;
|
|
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip, fi->fled_tor_cur_reg,
|
|
MT6370_FLED_TORCHCUR_MASK,
|
|
selector << MT6370_FLED_TORCHCUR_SHIFT);
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_set_strobe_current_sel(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret;
|
|
|
|
if (selector > fi->base.init_props->strobe_max_brightness)
|
|
return -EINVAL;
|
|
if (selector < 128)
|
|
mt6370_pmu_reg_clr_bit(fi->chip, fi->fled_strb_cur_reg, 0x80);
|
|
else
|
|
mt6370_pmu_reg_set_bit(fi->chip, fi->fled_strb_cur_reg, 0x80);
|
|
|
|
if (selector >= 128)
|
|
selector -= 128;
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip,
|
|
fi->fled_strb_cur_reg,
|
|
MT6370_FLED_STROBECUR_MASK,
|
|
selector << MT6370_FLED_STROBECUR_SHIFT);
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_set_timeout_level_sel(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret;
|
|
|
|
if (fi->id == MT6370_FLED1) {
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip,
|
|
MT6370_PMU_REG_FLED1CTRL,
|
|
MT6370_FLED_TIMEOUT_LEVEL_MASK,
|
|
selector << MT6370_TIMEOUT_LEVEL_SHIFT);
|
|
} else {
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip,
|
|
MT6370_PMU_REG_FLED2CTRL,
|
|
MT6370_FLED_TIMEOUT_LEVEL_MASK,
|
|
selector << MT6370_TIMEOUT_LEVEL_SHIFT);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_set_strobe_timeout_sel(struct rt_fled_dev *info,
|
|
int selector)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
if (fi->id == MT6370_FLED2) {
|
|
pr_err("%s not support set strobe timeout\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
ret = mt6370_pmu_reg_update_bits(fi->chip, fi->fled_strb_to_reg,
|
|
MT6370_FLED_STROBE_TIMEOUT_MASK,
|
|
selector << MT6370_FLED_STROBE_TIMEOUT_SHIFT);
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_get_torch_current_sel(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
ret = mt6370_pmu_reg_read(fi->chip, fi->fled_tor_cur_reg);
|
|
if (ret < 0) {
|
|
pr_err("%s get fled tor current sel fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret &= MT6370_FLED_TORCHCUR_MASK;
|
|
ret >>= MT6370_FLED_TORCHCUR_SHIFT;
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_get_strobe_current_sel(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
ret = mt6370_pmu_reg_read(fi->chip, fi->fled_strb_cur_reg);
|
|
if (ret < 0) {
|
|
pr_err("%s get fled strobe curr sel fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret &= MT6370_FLED_STROBECUR_MASK;
|
|
ret >>= MT6370_FLED_STROBECUR_SHIFT;
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_get_timeout_level_sel(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
if (fi->id == MT6370_FLED1)
|
|
ret = mt6370_pmu_reg_read(fi->chip, MT6370_PMU_REG_FLED1CTRL);
|
|
else
|
|
ret = mt6370_pmu_reg_read(fi->chip, MT6370_PMU_REG_FLED2CTRL);
|
|
if (ret < 0) {
|
|
pr_err("%s get fled timeout level fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret &= MT6370_FLED_TIMEOUT_LEVEL_MASK;
|
|
ret >>= MT6370_TIMEOUT_LEVEL_SHIFT;
|
|
return ret;
|
|
}
|
|
|
|
static int mt6370_fled_get_strobe_timeout_sel(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret = 0;
|
|
|
|
ret = mt6370_pmu_reg_read(fi->chip, fi->fled_strb_to_reg);
|
|
if (ret < 0) {
|
|
pr_err("%s get fled timeout level fail\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
ret &= MT6370_FLED_STROBE_TIMEOUT_MASK;
|
|
ret >>= MT6370_FLED_STROBE_TIMEOUT_SHIFT;
|
|
return ret;
|
|
}
|
|
|
|
static void mt6370_fled_shutdown(struct rt_fled_dev *info)
|
|
{
|
|
mt6370_fled_set_mode(info, FLASHLIGHT_MODE_OFF);
|
|
}
|
|
|
|
static int mt6370_fled_is_ready(struct rt_fled_dev *info)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi = (struct mt6370_pmu_fled_data *)info;
|
|
int ret;
|
|
|
|
ret = mt6370_pmu_reg_read(fi->chip, MT6370_PMU_REG_CHGSTAT2);
|
|
if (ret < 0) {
|
|
pr_err("%s read flash ready bit fail\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
/* CHG_STAT2 bit[3] CHG_VINOVP,
|
|
* if OVP = 0 --> V < 5.3, if OVP = 1, V > 5.6
|
|
*/
|
|
return ret & 0x08 ? 0 : 1;
|
|
}
|
|
|
|
static struct rt_fled_hal mt6370_fled_hal = {
|
|
.rt_hal_fled_init = mt6370_fled_init,
|
|
.rt_hal_fled_suspend = mt6370_fled_suspend,
|
|
.rt_hal_fled_resume = mt6370_fled_resume,
|
|
.rt_hal_fled_set_mode = mt6370_fled_set_mode,
|
|
.rt_hal_fled_get_mode = mt6370_fled_get_mode,
|
|
.rt_hal_fled_strobe = mt6370_fled_strobe,
|
|
.rt_hal_fled_get_is_ready = mt6370_fled_is_ready,
|
|
.rt_hal_fled_torch_current_list = mt6370_fled_torch_current_list,
|
|
.rt_hal_fled_strobe_current_list = mt6370_fled_strobe_current_list,
|
|
.rt_hal_fled_timeout_level_list = mt6370_fled_timeout_level_list,
|
|
/* .fled_lv_protection_list = mt6370_fled_lv_protection_list, */
|
|
.rt_hal_fled_strobe_timeout_list = mt6370_fled_strobe_timeout_list,
|
|
/* method to set */
|
|
.rt_hal_fled_set_torch_current_sel = mt6370_fled_set_torch_current_sel,
|
|
.rt_hal_fled_set_strobe_current_sel =
|
|
mt6370_fled_set_strobe_current_sel,
|
|
.rt_hal_fled_set_timeout_level_sel = mt6370_fled_set_timeout_level_sel,
|
|
|
|
.rt_hal_fled_set_strobe_timeout_sel =
|
|
mt6370_fled_set_strobe_timeout_sel,
|
|
|
|
/* method to get */
|
|
.rt_hal_fled_get_torch_current_sel = mt6370_fled_get_torch_current_sel,
|
|
.rt_hal_fled_get_strobe_current_sel =
|
|
mt6370_fled_get_strobe_current_sel,
|
|
.rt_hal_fled_get_timeout_level_sel = mt6370_fled_get_timeout_level_sel,
|
|
.rt_hal_fled_get_strobe_timeout_sel =
|
|
mt6370_fled_get_strobe_timeout_sel,
|
|
/* PM shutdown, optional */
|
|
.rt_hal_fled_shutdown = mt6370_fled_shutdown,
|
|
};
|
|
|
|
#define MT6370_FLED_TOR_CUR0 MT6370_PMU_REG_FLED1TORCTRL
|
|
#define MT6370_FLED_TOR_CUR1 MT6370_PMU_REG_FLED2TORCTRL
|
|
#define MT6370_FLED_STRB_CUR0 MT6370_PMU_REG_FLED1STRBCTRL
|
|
#define MT6370_FLED_STRB_CUR1 MT6370_PMU_REG_FLED2STRBCTRL2
|
|
#define MT6370_FLED_CS_MASK0 0x02
|
|
#define MT6370_FLED_CS_MASK1 0x01
|
|
|
|
|
|
#define MT6370_FLED_DEVICE(_id) \
|
|
{ \
|
|
.id = _id, \
|
|
.fled_ctrl_reg = MT6370_PMU_REG_FLEDEN, \
|
|
.fled_tor_cur_reg = MT6370_FLED_TOR_CUR##_id, \
|
|
.fled_strb_cur_reg = MT6370_FLED_STRB_CUR##_id, \
|
|
.fled_strb_to_reg = MT6370_PMU_REG_FLEDSTRBCTRL, \
|
|
.fled_cs_mask = MT6370_FLED_CS_MASK##_id, \
|
|
}
|
|
|
|
static struct mt6370_pmu_fled_data mt6370_pmu_fleds[] = {
|
|
MT6370_FLED_DEVICE(0),
|
|
MT6370_FLED_DEVICE(1),
|
|
};
|
|
|
|
static struct mt6370_pmu_fled_data *mt6370_find_info(int id)
|
|
{
|
|
struct mt6370_pmu_fled_data *fi;
|
|
unsigned int i;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(mt6370_pmu_fleds); i++) {
|
|
fi = &mt6370_pmu_fleds[i];
|
|
if (fi->id == id)
|
|
return fi;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static int mt6370_pmu_fled_probe(struct platform_device *pdev)
|
|
{
|
|
struct mt6370_pmu_fled_data *fled_data;
|
|
bool use_dt = pdev->dev.of_node;
|
|
int ret;
|
|
|
|
pr_info("%s: (%s) id = %d\n", __func__, MT6370_PMU_FLED_DRV_VERSION,
|
|
pdev->id);
|
|
fled_data = mt6370_find_info(pdev->id);
|
|
if (fled_data == NULL) {
|
|
dev_err(&pdev->dev, "invalid fled ID Specified\n");
|
|
return -EINVAL;
|
|
}
|
|
|
|
fled_data->chip = dev_get_drvdata(pdev->dev.parent);
|
|
fled_data->dev = &pdev->dev;
|
|
|
|
if (use_dt)
|
|
mt6370_fled_parse_dt(&pdev->dev, fled_data);
|
|
platform_set_drvdata(pdev, fled_data);
|
|
|
|
fled_data->base.init_props = &mt6370_fled_props;
|
|
fled_data->base.hal = &mt6370_fled_hal;
|
|
if (pdev->id == 0)
|
|
fled_data->base.name = "mt-flash-led1";
|
|
else
|
|
fled_data->base.name = "mt-flash-led2";
|
|
fled_data->base.chip_name = "mt6370_pmu_fled";
|
|
pr_info("%s flash name = %s\n", __func__, fled_data->base.name);
|
|
fled_data->mt_flash_dev = platform_device_register_resndata(
|
|
fled_data->dev, "rt-flash-led",
|
|
fled_data->id, NULL, 0, NULL, 0);
|
|
|
|
if (!mt6370_fled_inited) {
|
|
ret = mt6370_pmu_reg_clr_bit(fled_data->chip,
|
|
MT6370_PMU_REG_FLEDVMIDTRKCTRL1,
|
|
MT6370_FLED_FIXED_MODE_MASK);
|
|
if (ret < 0) {
|
|
pr_err("%s set fled fixed mode fail\n", __func__);
|
|
return -EINVAL;
|
|
}
|
|
|
|
mt6370_pmu_fled_irq_register(pdev);
|
|
mt6370_fled_inited = 1;
|
|
dev_info(&pdev->dev, "mt6370 fled inited\n");
|
|
}
|
|
dev_info(&pdev->dev, "%s successfully\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static int mt6370_pmu_fled_remove(struct platform_device *pdev)
|
|
{
|
|
struct mt6370_pmu_fled_data *fled_data = platform_get_drvdata(pdev);
|
|
|
|
platform_device_unregister(fled_data->mt_flash_dev);
|
|
dev_info(fled_data->dev, "%s successfully\n", __func__);
|
|
return 0;
|
|
}
|
|
|
|
static const struct of_device_id mt_ofid_table[] = {
|
|
{ .compatible = "mediatek,mt6370_pmu_fled1", },
|
|
{ .compatible = "mediatek,mt6370_pmu_fled2", },
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(of, mt_ofid_table);
|
|
|
|
#if 0
|
|
static const struct platform_device_id mt_id_table[] = {
|
|
{ "mt6370_pmu_fled1", 0},
|
|
{ "mt6370_pmu_fled2", 0},
|
|
{ },
|
|
};
|
|
MODULE_DEVICE_TABLE(platform, mt_id_table);
|
|
#endif
|
|
|
|
static struct platform_driver mt6370_pmu_fled = {
|
|
.driver = {
|
|
.name = "mt6370_pmu_fled",
|
|
.owner = THIS_MODULE,
|
|
.of_match_table = of_match_ptr(mt_ofid_table),
|
|
},
|
|
.probe = mt6370_pmu_fled_probe,
|
|
.remove = mt6370_pmu_fled_remove,
|
|
/*.id_table = mt_id_table, */
|
|
};
|
|
module_platform_driver(mt6370_pmu_fled);
|
|
|
|
MODULE_LICENSE("GPL v2");
|
|
MODULE_DESCRIPTION("MediaTek MT6370 PMU Fled");
|
|
MODULE_VERSION(MT6370_PMU_FLED_DRV_VERSION);
|
|
|
|
/*
|
|
* Release Note
|
|
* 1.0.3_MTK
|
|
* (1) Print warnings when strobe mode with HZ=1 or CFO=0
|
|
*
|
|
* 1.0.2_MTK
|
|
* (1) Add delay for strobe on/off
|
|
*
|
|
* 1.0.1_MTK
|
|
* (1) Remove typedef
|
|
*
|
|
* 1.0.0_MTK
|
|
* (1) Initial Release
|
|
*/
|