drivers: misc: Import WL2866D LDO driver

This commit is contained in:
Adithya R 2021-01-08 22:34:17 +05:30
parent c2f03375fb
commit c945da5f0e
4 changed files with 924 additions and 0 deletions

View File

@ -595,6 +595,11 @@ config TEST_IRQ_REQUESTER
If in doubt, say N.
config LDO_WL2866D
bool "multi ldo wl2866d"
---help---
This option enables multi ldo wl2866d.
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"

View File

@ -94,3 +94,4 @@ obj-$(CONFIG_OKL4_LINK_SHBUF) += okl4-link-shbuf.o
obj-$(CONFIG_AW8624_HAPTIC) += aw8624_haptic/
obj-$(CONFIG_DRV2624_HAPTIC) += drv2624_haptic/
obj-$(CONFIG_LDO_WL2866D) += wl2866d.o

861
drivers/misc/wl2866d.c Normal file
View File

@ -0,0 +1,861 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/irq.h>
#include <linux/mfd/core.h>
#include <misc/wl2866d.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <asm/unaligned.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <linux/pm.h>
#include <linux/regulator/consumer.h>
#define WL2866D_ID 0x64
#define WL2866D_ID1 0x55
#define AW_I2C_RETRIES 2
#define AW_I2C_RETRY_DELAY 2
//#ifdef __XIAOMI_CAMERA__
struct wl2866d_chip *camera_chip;
//#endif
static const struct wl2866d_map wl2866d_on_config[] = {
{0x03, 0x55},
{0x04, 0x55},
{0x05, 0x80},
{0x06, 0x88},
{0x0E, 0x0F},
{0x0E, 0x00},
};
static int wl2866d_i2c_write(struct wl2866d_chip *chip,
unsigned char reg_addr, unsigned char reg_data)
{
int ret = -1;
unsigned char cnt = 0;
while (cnt < AW_I2C_RETRIES) {
ret =
i2c_smbus_write_byte_data(chip->client, reg_addr, reg_data);
if (ret < 0) {
pr_err("%s: i2c_write cnt=%d error=%d\n", __func__, cnt,
ret);
} else {
break;
}
cnt++;
msleep(AW_I2C_RETRY_DELAY);
}
return ret;
}
static int wl2866d_i2c_read(struct wl2866d_chip *chip,
unsigned char reg_addr, unsigned char *reg_data)
{
int ret = -1;
unsigned char cnt = 0;
while (cnt < AW_I2C_RETRIES) {
ret = i2c_smbus_read_byte_data(chip->client, reg_addr);
if (ret < 0) {
pr_err("%s: i2c_read cnt=%d error=%d\n", __func__, cnt,
ret);
} else {
*reg_data = ret;
break;
}
cnt++;
msleep(AW_I2C_RETRY_DELAY);
}
return ret;
}
int wl2866d_camera_power_down_all()
{
int ret = -1;
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, 0);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
return ret;
}
//#ifdef __XIAOMI_CAMERA__
//bit0:DVDD1, bit1:DVDD2, bit2:AVDD1, bit3:AVDD2
//{0x03, 0x55}, OUT_DVDD1
//{0x04, 0x55}, OUT_DVDD2
//{0x05, 0x80}, OUT_AVDD1
//{0x06, 0x88}, OUT_AVDD2
//{0x0E, 0x0F}, VOL_ENABLE
//{0x0E, 0x00}, VOL_DISABLE
int wl2866d_camera_power_up(uint16_t camera_id)
{
int ret = -1;
unsigned char reg_val = 0;
if (0 == camera_id) {
//camera_id 0 --> imx682
pr_err("xyz wide:imx682 camera_id=[%d] power up\n", camera_id);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[OUT_DVDD2].reg, 0x55);//bit1
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[OUT_AVDD2].reg, 0x88);//bit3
if (ret < 0) {
pr_err("xyz wl2866d set avdd2/dvdd2 failed\n");
return ret;
}
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val |= 0b1010;//bit1,bit3
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
}
else if ((1 == camera_id) || (2 == camera_id) || (4 == camera_id)) {
//camera_id 2 --> s5k3t2
//camera_id 1 --> ov02b1b/gc02m1b
//camera_id 4 --> hi259
if (2 == camera_id) {
pr_err("xyz front:s5k3t2 camera_id=[%d] power up\n", camera_id);
} else if(1 == camera_id) {
pr_err("xyz depth:ov02b1b/gc02m1b camera_id=[%d] power up\n", camera_id);
} else if(4 == camera_id) {
pr_err("xyz macro:hi259 camera_id=[%d] power up\n", camera_id);
}
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[OUT_AVDD1].reg, 0x80);//bit2
if (ret < 0) {
pr_err("xyz wl2866d set avdd1 failed\n");
return ret;
}
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val |= 0b0100;//bit2
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
}
else if ((3 == camera_id) || (5 == camera_id)) {
//camera_id 5 --> hi847
//camera_id 3 --> hi1337
if (3 == camera_id) {
pr_err("xyz ulta wide:hi1337 camera_id=[%d] power up\n", camera_id);
} else if(5 == camera_id) {
pr_err("xyz tele:hi847 camera_id=[%d] power up\n", camera_id);
}
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[OUT_DVDD1].reg, 0x55);//bit2
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[OUT_AVDD1].reg, 0x80);//bit2
if (ret < 0) {
pr_err("xyz wl2866d set avdd1 failed\n");
return ret;
}
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val |= 0b0101;//bit0,bit2
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
} else {
pr_err("xyz wl2866d unknown camera!!!\n");
}
pr_err("xyz wl2866d result = %d\n", ret);
return ret;
}
EXPORT_SYMBOL(wl2866d_camera_power_up);
int wl2866d_camera_power_down(uint16_t camera_id)
{
int ret = -1;
unsigned char reg_val = 0;
if (0 == camera_id) {
//camera_id 0 --> imx682
pr_err("xyz wide:imx682 camera_id=[%d] power down\n", camera_id);
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val &= 0b0101;//bit1,bit3
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
}
else if ((1 == camera_id) || (2 == camera_id) || (4 == camera_id)) {
//camera_id 2 --> s5k3t2
//camera_id 1 --> ov02b1b/gc02m1b
//camera_id 4 --> hi259
if (2 == camera_id) {
pr_err("xyz front:s5k3t2 camera_id=[%d] power down\n", camera_id);
} else if(1 == camera_id) {
pr_err("xyz depth:ov02b1b/gc02m1b camera_id=[%d] power down\n", camera_id);
} else if(4 == camera_id) {
pr_err("xyz macro:hi259 camera_id=[%d] power down\n", camera_id);
}
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val &= 0b1011;//bit2
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
}
else if ((3 == camera_id) || (5 == camera_id)) {
//camera_id 5 --> hi847
//camera_id 3 --> hi1337
if (3 == camera_id) {
pr_err("xyz ulta wide:hi1337 camera_id=[%d] power up\n", camera_id);
} else if(5 == camera_id) {
pr_err("xyz tele:hi847 camera_id=[%d] power up\n", camera_id);
}
ret = wl2866d_i2c_read(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
if (ret < 0) {
pr_err("xyz wl2866d read enable failed\n");
return ret;
}
pr_err("xyz before set enable value = 0x%x\n", reg_val);
reg_val &= 0b1010;//bit0,bit2
pr_err("xyz after set enable value = 0x%x\n", reg_val);
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);//bit1
if (ret < 0) {
pr_err("xyz wl2866d set enable failed\n");
return ret;
}
} else {
pr_err("xyz wl2866d unknown camera!!!\n");
}
pr_err("xyz wl2866d result = %d\n", ret);
return ret;
}
EXPORT_SYMBOL(wl2866d_camera_power_down);
//#endif
static ssize_t wl2866d_vol_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl2866d_chip *chip = dev_get_drvdata(dev);
unsigned char reg_val = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[VOL_ENABLE].reg, &reg_val);
return snprintf(buf, 10, "%d\n", reg_val);
}
static ssize_t wl2866d_vol_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
unsigned char reg_val = 0;
struct wl2866d_chip *chip = dev_get_drvdata(dev);
ret = kstrtou8(buf, 0, &reg_val);
if (ret < 0)
return ret;
ret = wl2866d_i2c_write(chip, wl2866d_on_config[VOL_ENABLE].reg, reg_val);
if (ret < 0) {
pr_err("wl2866d set enable failed\n");
return ret;
}
return count;
}
static ssize_t wl2866d_out_avdd2_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl2866d_chip *chip = dev_get_drvdata(dev);
unsigned char reg_val = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[OUT_AVDD2].reg, &reg_val);
return snprintf(buf, 10, "%d\n", reg_val);
}
static ssize_t wl2866d_out_avdd2_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
unsigned char reg_val = 0;
struct wl2866d_chip *chip = dev_get_drvdata(dev);
ret = kstrtou8(buf, 0, &reg_val);
if (ret < 0)
return ret;
ret = wl2866d_i2c_write(chip, wl2866d_on_config[OUT_AVDD2].reg, reg_val);
if (ret < 0) {
pr_err("wl2866d open avdd2 failed\n");
return ret;
}
return count;
}
static ssize_t wl2866d_out_avdd1_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl2866d_chip *chip = dev_get_drvdata(dev);
unsigned char reg_val = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[OUT_AVDD1].reg, &reg_val);
return snprintf(buf, 10, "%d\n", reg_val);
}
static ssize_t wl2866d_out_avdd1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
unsigned char reg_val = 0;
struct wl2866d_chip *chip = dev_get_drvdata(dev);
ret = kstrtou8(buf, 0, &reg_val);
if (ret < 0)
return ret;
ret = wl2866d_i2c_write(chip, wl2866d_on_config[OUT_AVDD1].reg, reg_val);
if (ret < 0) {
pr_err("wl2866d open avdd1 failed\n");
return ret;
}
return count;
}
static ssize_t wl2866d_out_dvdd2_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl2866d_chip *chip = dev_get_drvdata(dev);
unsigned char reg_val = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[OUT_DVDD1].reg, &reg_val);
return snprintf(buf, 10, "%d\n", reg_val);
}
static ssize_t wl2866d_out_dvdd2_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
unsigned char reg_val = 0;
struct wl2866d_chip *chip = dev_get_drvdata(dev);
ret = kstrtou8(buf, 0, &reg_val);
if (ret < 0)
return ret;
ret = wl2866d_i2c_write(chip, wl2866d_on_config[OUT_DVDD1].reg, reg_val);
if (ret < 0) {
pr_err("wl2866d open dvdd2 failed\n");
return ret;
}
return count;
}
static ssize_t wl2866d_out_dvdd1_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct wl2866d_chip *chip = dev_get_drvdata(dev);
unsigned char reg_val = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[OUT_DVDD1].reg, &reg_val);
return snprintf(buf, 10, "%d\n", reg_val);
}
static ssize_t wl2866d_out_dvdd1_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
int ret = 0;
unsigned char reg_val = 0;
struct wl2866d_chip *chip = dev_get_drvdata(dev);
ret = kstrtou8(buf, 0, &reg_val);
if (ret < 0)
return ret;
ret = wl2866d_i2c_write(chip, wl2866d_on_config[OUT_DVDD1].reg, reg_val);
if (ret < 0) {
pr_err("wl2866d open dvdd1 failed\n");
return ret;
}
return count;
}
static DEVICE_ATTR(vol_enable, 0664, wl2866d_vol_enable_show, wl2866d_vol_enable_store);
static DEVICE_ATTR(out_avdd2, 0664, wl2866d_out_avdd2_show, wl2866d_out_avdd2_store);
static DEVICE_ATTR(out_avdd1, 0664, wl2866d_out_avdd1_show, wl2866d_out_avdd1_store);
static DEVICE_ATTR(out_dvdd2, 0664, wl2866d_out_dvdd2_show, wl2866d_out_dvdd2_store);
static DEVICE_ATTR(out_dvdd1, 0664, wl2866d_out_dvdd1_show, wl2866d_out_dvdd1_store);
static struct attribute *wl2866d_attributes[] = {
&dev_attr_out_dvdd1.attr,
&dev_attr_out_dvdd2.attr,
&dev_attr_out_avdd1.attr,
&dev_attr_out_avdd2.attr,
&dev_attr_vol_enable.attr,
NULL
};
static struct attribute_group wl2866d_attribute_group = {
.attrs = wl2866d_attributes
};
static int wl2866d_get_id(struct wl2866d_chip *chip)
{
unsigned char reg_val = 0;
int ret = 0;
wl2866d_i2c_read(chip, wl2866d_on_config[OUT_DVDD1].reg, &reg_val);
pr_err("%s:wl2866d id is %d\n", __func__, reg_val);
if ((reg_val != WL2866D_ID) && (reg_val != WL2866D_ID1)) {
ret = -1;
return ret;
}
return 0;
}
static int set_init_voltage(struct wl2866d_chip *chip)
{
int ret = 0;
int i;
for (i = 0 ; i < (ARRAY_SIZE(wl2866d_on_config) - 1); i++) {
ret = wl2866d_i2c_write(chip, wl2866d_on_config[i].reg, wl2866d_on_config[i].value);
if (ret < 0) {
pr_err("wl2866d init voltage failed\n");
return ret;
}
}
return 0;
}
int wl2866d_camera_power_up_eeprom(void)
{
int ret = -1;
ret = set_init_voltage(camera_chip);
return ret;
}
EXPORT_SYMBOL(wl2866d_camera_power_up_eeprom);
int wl2866d_camera_power_up_all(void)
{
int ret = -1;
ret = set_init_voltage(camera_chip);
return ret;
}
EXPORT_SYMBOL(wl2866d_camera_power_up_all);
int wl2866d_camera_power_down_eeprom(void)
{
int ret = -1;
ret = wl2866d_i2c_write(camera_chip, wl2866d_on_config[VOL_ENABLE].reg, 0);//bit1
return ret;
}
EXPORT_SYMBOL(wl2866d_camera_power_down_eeprom);
void wl2866d_print_reg(struct wl2866d_chip *chip)
{
int i;
unsigned char reg_val = 0;
for (i = 0 ; i < ARRAY_SIZE(wl2866d_on_config); i++) {
wl2866d_i2c_read(chip, wl2866d_on_config[i].reg, &reg_val);
pr_err("%s:wl2866d info is reg %d, value %d\n", __func__, wl2866d_on_config[i].reg, reg_val);
}
}
static int wl2866d_init(struct wl2866d_chip *chip)
{
int ret = 0;
chip->en_gpio = of_get_named_gpio(chip->dev->of_node,
"en-gpio", 0);
if (!gpio_is_valid(chip->en_gpio)) {
pr_err("%s:%d, en gpio not specified\n",
__func__, __LINE__);
return -EINVAL;
}
pr_err("%s: en_gpio is %d\n", __func__, chip->en_gpio);
ret = gpio_request(chip->en_gpio, "wl2866d_en");
//ret = devm_gpio_request_one(chip->dev, chip->en_gpio,
// GPIOF_OUT_INIT_LOW,
// "wl2866d_en");
if (ret < 0) {
pr_err("wl2866d enable gpio request failed\n");
return ret;
}
gpio_direction_output(chip->en_gpio, 0);
//if (chip && gpio_is_valid(chip->en_gpio)) {
// gpio_set_value_cansleep(chip->en_gpio, 1);
//}
msleep(10);
ret = wl2866d_get_id(chip);
if (ret < 0) {
pr_err("wl2866d read id failed\n");
return ret;
}
ret = set_init_voltage(chip);
if (ret < 0)
pr_err("wl2866d init failed\n");
if (WL2866D_DEBUG) {
msleep(10);
wl2866d_print_reg(chip);
}
return 0;
}
static int wl2866d_disable_power(struct wl2866d_chip *chip)
{
int ret = 0;
ret = regulator_disable(chip->vin1);
if (ret)
dev_err(chip->dev, "Unable to disable vin1:%d\n", ret);
if (!regulator_is_enabled(chip->vin1)) {
ret = regulator_set_voltage(chip->vin1, 0,
VIN1_1P35_VOL_MAX);
if (ret)
dev_err(chip->dev,
"Unable to set (0) voltage for vin1:%d\n", ret);
}
ret = regulator_disable(chip->vin2);
if (ret)
dev_err(chip->dev, "Unable to disable vin2:%d\n", ret);
if (!regulator_is_enabled(chip->vin2)) {
ret = regulator_set_voltage(chip->vin2, 0,
VIN2_3P3_VOL_MAX);
if (ret)
dev_err(chip->dev,
"Unable to set (0) voltage for vin2:%d\n", ret);
}
return 0;
}
static int wl2866d_enable_power(struct wl2866d_chip *chip)
{
int ret = 0;
ret = regulator_set_voltage(chip->vin1, VIN1_1P35_VOL_MIN,
VIN1_1P35_VOL_MAX);
if (ret) {
dev_err(chip->dev,
"Unable to set voltage for vin1:%d\n", ret);
goto put_vin1;
}
ret = regulator_enable(chip->vin1);
if (ret) {
dev_err(chip->dev, "Unable to enable vin1:%d\n", ret);
goto unset_vin1;
}
ret = regulator_set_voltage(chip->vin2, VIN2_3P3_VOL_MIN,
VIN2_3P3_VOL_MAX);
if (ret) {
dev_err(chip->dev,
"Unable to set voltage for vin2:%d\n", ret);
goto disable_vin1;
}
ret = regulator_enable(chip->vin2);
if (ret) {
dev_err(chip->dev, "Unable to enable vin2:%d\n", ret);
goto unset_vin2;
}
return 0;
unset_vin2:
ret = regulator_set_voltage(chip->vin2, 0, VIN2_3P3_VOL_MAX);
if (ret)
dev_err(chip->dev,
"Unable to set (0) voltage for vin2:%d\n", ret);
disable_vin1:
ret = regulator_disable(chip->vin1);
if (ret)
dev_err(chip->dev, "Unable to disable vin1:%d\n", ret);
unset_vin1:
ret = regulator_set_voltage(chip->vin1, 0, VIN1_1P35_VOL_MAX);
if (ret)
dev_err(chip->dev,
"Unable to set (0) voltage for vin1:%d\n", ret);
put_vin1:
return ret;
}
static int wl2866d_vreg_init(struct wl2866d_chip *chip)
{
int ret = 0;
chip->vin1 = devm_regulator_get(chip->dev, "vin1");
if (IS_ERR(chip->vin1)) {
ret = PTR_ERR(chip->vin1);
dev_err(chip->dev, "%s: can't get VIN1,%d\n", __func__, ret);
goto err_vin1;
}
chip->vin2 = devm_regulator_get(chip->dev, "vin2");
if (IS_ERR(chip->vin2)) {
ret = PTR_ERR(chip->vin2);
dev_err(chip->dev, "%s: can't get VIN2,%d\n", __func__, ret);
goto err_vin2;
}
return 0;
err_vin2:
devm_regulator_put(chip->vin1);
err_vin1:
return ret;
}
static int wl2866d_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret = 0;
struct wl2866d_chip *chip;
pr_err("%s,enrty\n", __func__);
chip = devm_kzalloc(&client->dev, sizeof(struct wl2866d_chip), GFP_KERNEL);
if (!chip) {
ret = -ENOMEM;
goto err_mem;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_err(&client->dev, "check_functionality failed\n");
ret = -EIO;
goto init_err;
}
chip->client = client;
chip->dev = &client->dev;
dev_set_drvdata(chip->dev, chip);
i2c_set_clientdata(chip->client, chip);
ret = wl2866d_vreg_init(chip);
if (ret < 0) {
dev_err(&client->dev, "get vreg failed\n");
goto vreg_init_err;
}
ret = wl2866d_enable_power(chip);
if (ret) {
dev_err(&client->dev, "enable power failed\n");
ret = -1;
goto vreg_enable_err;
}
ret = wl2866d_init(chip);
if (ret < 0) {
dev_err(&client->dev, "wl2866d init fail!\n");
ret = -ENODEV;
goto init_err;
}
ret = sysfs_create_group(&client->dev.kobj,
&wl2866d_attribute_group);
if (ret < 0) {
dev_info(&client->dev, "%s error creating sysfs attr files\n",
__func__);
goto err_sysfs;
}
//#ifdef __XIAOMI_CAMERA__
camera_chip = chip;
//#endif
pr_err("%s,successfully\n", __func__);
return 0;
err_sysfs:
init_err:
vreg_enable_err:
devm_regulator_put(chip->vin1);
devm_regulator_put(chip->vin2);
vreg_init_err:
devm_kfree(chip->dev, chip);
chip = NULL;
err_mem:
return ret;
}
static int wl2866d_remove(struct i2c_client *client)
{
struct wl2866d_chip *chip = i2c_get_clientdata(client);
devm_kfree(chip->dev, chip);
chip = NULL;
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int wl2866d_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct wl2866d_chip *chip = i2c_get_clientdata(client);
int ret = 0;
pr_err("%s\n", __func__);
ret = wl2866d_i2c_write(chip, wl2866d_on_config[VOL_DISABLE].reg, wl2866d_on_config[VOL_DISABLE].value);
if (ret < 0)
pr_err("wl2866d close voltage failed\n");
wl2866d_disable_power(chip);
return 0;
}
static int wl2866d_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct wl2866d_chip *chip = i2c_get_clientdata(client);
//#ifdef __XIAOMI_CAMERA__
//int ret = 0;
pr_err("%s\n", __func__);
wl2866d_enable_power(chip);
gpio_direction_output(chip->en_gpio, 0);
/*
ret = wl2866d_i2c_write(chip, wl2866d_on_config[VOL_ENABLE].reg, wl2866d_on_config[VOL_ENABLE].value);
if (ret < 0) {
pr_err("wl2866d set enable failed\n");
return ret;
}
*/
//#endif
return 0;
}
#endif
static const struct dev_pm_ops wl2866d_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(wl2866d_suspend, wl2866d_resume)
};
static const struct i2c_device_id wl2866d_id_table[] = {
{"longcheer,wl2866d", 0},
{} /* NULL terminated */
};
MODULE_DEVICE_TABLE(i2c, wl2866d_id_table);
#ifdef CONFIG_OF
static const struct of_device_id wl2866d_i2c_of_match_table[] = {
{ .compatible = "longcheer,wl2866d" },
{},
};
MODULE_DEVICE_TABLE(of, wl2866d_i2c_of_match_table);
#endif
static struct i2c_driver wl2866d_driver = {
.driver = {
.name = "longcheer,wl2866d",
.pm = &wl2866d_pm_ops,
.of_match_table = of_match_ptr(wl2866d_i2c_of_match_table),
},
.probe = wl2866d_probe,
.remove = wl2866d_remove,
.id_table = wl2866d_id_table,
};
static int __init wl2866d_i2c_init(void)
{
return i2c_add_driver(&wl2866d_driver);
}
subsys_initcall(wl2866d_i2c_init);
//module_init(wl2866d_i2c_init);
static void __exit wl2866d_i2c_exit(void)
{
i2c_del_driver(&wl2866d_driver);
}
module_exit(wl2866d_i2c_exit);
MODULE_DESCRIPTION("PMIC Driver for Longcheer wl2866d");
MODULE_AUTHOR("Li Wei <liwei6@longcheer.com>");
MODULE_LICENSE("GPL");

57
include/misc/wl2866d.h Normal file
View File

@ -0,0 +1,57 @@
/*
* Marvell 88PM80x Interface
*
* Copyright (C) 2012 Marvell International Ltd.
* Copyright (C) 2020 XiaoMi, Inc.
*
* 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.
*/
#ifndef __WL2866D_H
#define __WL2866D_H
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/regmap.h>
#include <linux/atomic.h>
#include <linux/regulator/consumer.h>
#define WL2866D_DEBUG 1
#define VIN1_1P35_VOL_MIN 1350000
#define VIN1_1P35_VOL_MAX 1350000
#define VIN2_3P3_VOL_MIN 3296000
#define VIN2_3P3_VOL_MAX 3296000
//#ifdef __XIAOMI_CAMERA__
int wl2866d_camera_power_up(uint16_t camera_id);
int wl2866d_camera_power_down(uint16_t camera_id);
int wl2866d_camera_power_up_eeprom(void);
int wl2866d_camera_power_down_eeprom(void);
int wl2866d_camera_power_down_all(void);
int wl2866d_camera_power_up_all(void);
//#endif
struct wl2866d_chip {
struct device *dev;
struct i2c_client *client;
int en_gpio;
struct regulator *vin1;
struct regulator *vin2;
};
struct wl2866d_map {
u8 reg;
u8 value;
};
enum {
OUT_DVDD1,
OUT_DVDD2,
OUT_AVDD1,
OUT_AVDD2,
VOL_ENABLE,
VOL_DISABLE,
};
#endif /* __WL2866D_H */