mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
drivers: misc: Import WL2866D LDO driver
This commit is contained in:
parent
c2f03375fb
commit
c945da5f0e
@ -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"
|
||||
|
@ -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
861
drivers/misc/wl2866d.c
Normal 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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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, ®_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
57
include/misc/wl2866d.h
Normal 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 */
|
Loading…
x
Reference in New Issue
Block a user