1
0
Fork 0

Port TPS6518X driver

martin/tpsdriverting
Martin T. H. Sandsmark 2016-09-07 09:21:23 +02:00
parent 5c76066147
commit 4168ae8de1
10 changed files with 1808 additions and 0 deletions

View File

@ -834,6 +834,15 @@ config SENSORS_MAX17135
This driver can also be built as a module. If so, the module
will be called max17135_sensor.
config SENSORS_TPS6518X
tristate "Texas Instruments TPS6518X EPD temperature sensor"
depends on I2C
help
If you say yes here you get support for TPS6518X PMIC sensor.
This driver can also be built as a module. If so, the module
will be called tps6518x_sensor.
config SENSORS_MAX197
tristate "Maxim MAX197 and compatibles"
help

View File

@ -114,6 +114,7 @@ obj-$(CONFIG_SENSORS_MAX16065) += max16065.o
obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
obj-$(CONFIG_SENSORS_MAX1668) += max1668.o
obj-$(CONFIG_SENSORS_MAX17135) += max17135-hwmon.o
obj-$(CONFIG_SENSORS_TPS6518X) += tps6518x-hwmon.o
obj-$(CONFIG_SENSORS_MAX197) += max197.o
obj-$(CONFIG_SENSORS_MAX31722) += max31722.o
obj-$(CONFIG_SENSORS_MAX6639) += max6639.o

View File

@ -0,0 +1,319 @@
/*
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*
* tps65185.c
*
* Based on the MAX1619 driver.
* Copyright (C) 2003-2004 Alexey Fisher <fishor@mail.ru>
* Jean Delvare <khali@linux-fr.org>
*
* The TPS65185 is a sensor chip made by Texass Instruments.
* It reports up to two temperatures (its own plus up to
* one external one).
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/jiffies.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/sysfs.h>
#include <linux/platform_device.h>
#include <linux/mfd/tps6518x.h>
/*
* Conversions
*/
static int temp_from_reg(int val)
{
return val;
}
/*
* Functions declaration
*/
static int tps6518x_sensor_probe(struct platform_device *pdev);
static int tps6518x_sensor_remove(struct platform_device *pdev);
static const struct platform_device_id tps6518x_sns_id[] = {
{ "tps6518x-sns", 0},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(platform, tps6518x_sns_id);
/*
* Driver data (common to all clients)
*/
static struct platform_driver tps6518x_sensor_driver = {
.probe = tps6518x_sensor_probe,
.remove = tps6518x_sensor_remove,
.id_table = tps6518x_sns_id,
.driver = {
.name = "tps6518x_sensor",
},
};
/*
* Client data (each client gets its own)
*/
struct tps6518x_data {
struct device *hwmon_dev;
};
/*
* Sysfs stuff
*/
static ssize_t show_temp_input(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int reg_val;
/*
* begin Temperature conversion
*/
tps6518x_reg_read(REG_TPS6518x_REVID,&reg_val);
switch (reg_val & 0xff)
{
case TPS65180_PASS1 :
case TPS65180_PASS2 :
case TPS65181_PASS1 :
case TPS65181_PASS2 :
reg_val = 0x80;
tps6518x_reg_write(REG_TPS65180_TMST_CONFIG, reg_val);
// wait for completion completed
while ((0x20 & reg_val) == 0)
{
msleep(1);
tps6518x_reg_read(REG_TPS65180_TMST_CONFIG, &reg_val);
}
break;
case TPS65185_PASS0 :
case TPS65186_PASS0 :
case TPS65185_PASS1 :
case TPS65186_PASS1 :
case TPS65185_PASS2 :
case TPS65186_PASS2 :
reg_val = 0x80;
tps6518x_reg_write(REG_TPS65185_TMST1, reg_val);
// wait for completion completed
while ((0x20 & reg_val) == 0)
{
msleep(1);
tps6518x_reg_read(REG_TPS65185_TMST1, &reg_val);
}
break;
default:
break;
}
tps6518x_reg_read(REG_TPS6518x_TMST_VAL, &reg_val);
return snprintf(buf, PAGE_SIZE, "%d\n", temp_from_reg(reg_val));
}
static ssize_t show_intr_regs(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int reg_val;
unsigned int intr_reg_val;
/*
* get the interrupt status register value
*/
tps6518x_reg_read(REG_TPS6518x_REVID,&reg_val);
switch (reg_val & 0xff)
{
case TPS65180_PASS1 :
case TPS65180_PASS2 :
case TPS65181_PASS1 :
case TPS65181_PASS2 :
tps6518x_reg_read(REG_TPS65180_INT1, &intr_reg_val);
tps6518x_reg_read(REG_TPS65180_INT2, &reg_val);
intr_reg_val |= reg_val<<8;
break;
case TPS65185_PASS0 :
case TPS65186_PASS0 :
case TPS65185_PASS1 :
case TPS65186_PASS1 :
case TPS65185_PASS2 :
case TPS65186_PASS2 :
tps6518x_reg_read(REG_TPS65185_INT1, &intr_reg_val);
tps6518x_reg_read(REG_TPS65185_INT2, &reg_val);
intr_reg_val |= reg_val<<8;
break;
default:
break;
}
return snprintf(buf, PAGE_SIZE, "%d\n", intr_reg_val);
}
static ssize_t show_vcom(struct device *dev,
struct device_attribute *attr, char *buf)
{
unsigned int reg_val;
unsigned int vcom_reg_val;
/*
* get the vcom registers
*/
tps6518x_reg_read(REG_TPS6518x_REVID,&reg_val);
switch (reg_val & 0xff)
{
case TPS65180_PASS1 :
case TPS65180_PASS2 :
case TPS65181_PASS1 :
case TPS65181_PASS2 :
tps6518x_reg_read(REG_TPS65180_VCOM_ADJUST, &vcom_reg_val);
break;
case TPS65185_PASS0 :
case TPS65186_PASS0 :
case TPS65185_PASS1 :
case TPS65186_PASS1 :
case TPS65185_PASS2 :
case TPS65186_PASS2 :
tps6518x_reg_read(REG_TPS65185_VCOM1, &vcom_reg_val);
tps6518x_reg_read(REG_TPS65185_VCOM2, &reg_val);
vcom_reg_val |= reg_val<<8;
break;
default:
break;
}
return snprintf(buf, PAGE_SIZE, "%d\n", vcom_reg_val);
}
static ssize_t set_vcom(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
unsigned int reg_val;
long vcom_reg_val = simple_strtol(buf,NULL,10);
/*
* get the interrupt status register value
*/
tps6518x_reg_read(REG_TPS6518x_REVID,&reg_val);
switch (reg_val & 0xff)
{
case TPS65180_PASS1 :
case TPS65180_PASS2 :
case TPS65181_PASS1 :
case TPS65181_PASS2 :
tps6518x_reg_write(REG_TPS65180_VCOM_ADJUST, vcom_reg_val&0xff);
break;
case TPS65185_PASS0 :
case TPS65186_PASS0 :
case TPS65185_PASS1 :
case TPS65186_PASS1 :
case TPS65185_PASS2 :
case TPS65186_PASS2 :
tps6518x_reg_write(REG_TPS65185_VCOM1, vcom_reg_val&0xff);
tps6518x_reg_write(REG_TPS65185_VCOM2, (vcom_reg_val>>8)&0xff);
break;
default:
break;
}
return count;
}
static DEVICE_ATTR(temp_input, S_IRUGO, show_temp_input, NULL);
static DEVICE_ATTR(intr_input, S_IRUGO, show_intr_regs, NULL);
static DEVICE_ATTR(vcom_value, S_IWUSR | S_IRUGO, show_vcom, set_vcom);
static struct attribute *tps6518x_attributes[] = {
&dev_attr_temp_input.attr,
&dev_attr_intr_input.attr,
&dev_attr_vcom_value.attr,
NULL
};
static const struct attribute_group tps6518x_group = {
.attrs = tps6518x_attributes,
};
/*
* Real code
*/
static int tps6518x_sensor_probe(struct platform_device *pdev)
{
struct tps6518x_data *data;
int err;
printk("tps6518x_sensor_probe starting\n");
data = kzalloc(sizeof(struct tps6518x_data), GFP_KERNEL);
if (!data) {
err = -ENOMEM;
goto exit;
}
/* Register sysfs hooks */
err = sysfs_create_group(&pdev->dev.kobj, &tps6518x_group);
if (err)
goto exit_free;
data->hwmon_dev = hwmon_device_register(&pdev->dev);
if (IS_ERR(data->hwmon_dev)) {
err = PTR_ERR(data->hwmon_dev);
goto exit_remove_files;
}
platform_set_drvdata(pdev, data);
printk("tps6518x_sensor_probe success\n");
return 0;
exit_remove_files:
sysfs_remove_group(&pdev->dev.kobj, &tps6518x_group);
exit_free:
kfree(data);
exit:
return err;
}
static int tps6518x_sensor_remove(struct platform_device *pdev)
{
struct tps6518x_data *data = platform_get_drvdata(pdev);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&pdev->dev.kobj, &tps6518x_group);
kfree(data);
return 0;
}
static int __init sensors_tps6518x_init(void)
{
return platform_driver_register(&tps6518x_sensor_driver);
}
module_init(sensors_tps6518x_init);
static void __exit sensors_tps6518x_exit(void)
{
platform_driver_unregister(&tps6518x_sensor_driver);
}
module_exit(sensors_tps6518x_exit);
MODULE_DESCRIPTION("TPS6518x sensor driver");
MODULE_LICENSE("GPL");

View File

@ -590,6 +590,13 @@ config MFD_MAX17135
This is the MAX17135 PMIC support. It includes
core support for communication with the MAX17135 chip.
config MFD_TPS6518X
tristate "Texas Instruments TPS6518X EPD PMIC core"
depends on I2C
help
This is the TPS6518X PMIC support. It includes
core support for communication with the TPS6518X chip.
config MFD_MAX77620
bool "Maxim Semiconductor MAX77620 and MAX20024 PMIC Support"
depends on I2C=y

View File

@ -81,6 +81,7 @@ obj-$(CONFIG_MFD_TPS65912) += tps65912-core.o
obj-$(CONFIG_MFD_TPS65912_I2C) += tps65912-i2c.o
obj-$(CONFIG_MFD_TPS65912_SPI) += tps65912-spi.o
obj-$(CONFIG_MFD_TPS80031) += tps80031.o
obj-$(CONFIG_MFD_TPS6518X) += tps6518x-core.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_TWL4030_CORE) += twl-core.o twl4030-irq.o twl6030-irq.o

View File

@ -0,0 +1,299 @@
/*
* Copyright (C) 2010 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
/*!
* @file pmic/core/tps6518x.c
* @brief This file contains TPS6518x specific PMIC code. This implementaion
* may differ for each PMIC chip.
*
* @ingroup PMIC_CORE
*/
/*
* Includes
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/i2c.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/uaccess.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/pmic_status.h>
#include <linux/mfd/core.h>
#include <linux/mfd/tps6518x.h>
#include <asm/mach-types.h>
static int tps6518x_detect(struct i2c_client *client, struct i2c_board_info *info);
struct i2c_client *tps6518x_client;
static struct regulator *gpio_regulator;
static struct mfd_cell tps6518x_devs[] = {
{ .name = "tps6518x-pmic", },
{ .name = "tps6518x-sns", },
};
static const unsigned short normal_i2c[] = {EPDC_PMIC_I2C_ADDR, I2C_CLIENT_END};
int tps6518x_reg_read(int reg_num, unsigned int *reg_val)
{
int result;
if (tps6518x_client == NULL)
return PMIC_ERROR;
result = i2c_smbus_read_byte_data(tps6518x_client, reg_num);
if (result < 0) {
dev_err(&tps6518x_client->dev,
"Unable to read tps6518x register via I2C\n");
return PMIC_ERROR;
}
*reg_val = result;
return PMIC_SUCCESS;
}
int tps6518x_reg_write(int reg_num, const unsigned int reg_val)
{
int result;
if (tps6518x_client == NULL)
return PMIC_ERROR;
result = i2c_smbus_write_byte_data(tps6518x_client, reg_num, reg_val);
if (result < 0) {
// dev_err(&tps6518x_client->dev,
// "Unable to write TPS6518x register via I2C\n");
return PMIC_ERROR;
}
return PMIC_SUCCESS;
}
#ifdef CONFIG_OF
static struct tps6518x_platform_data *tps6518x_i2c_parse_dt_pdata(
struct device *dev)
{
struct tps6518x_platform_data *pdata;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata) {
dev_err(dev, "could not allocate memory for pdata\n");
return ERR_PTR(-ENOMEM);
}
return pdata;
}
#else
static struct tps6518x_platform_data *tps6518x_i2c_parse_dt_pdata(
struct device *dev)
{
return NULL;
}
#endif /* !CONFIG_OF */
static int tps6518x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct tps6518x *tps6518x;
struct tps6518x_platform_data *pdata = client->dev.platform_data;
struct device_node *np = client->dev.of_node;
int ret = 0;
printk("tps6518x_probe calling\n");
if (!np)
return -ENODEV;
gpio_regulator = devm_regulator_get(&client->dev, "SENSOR");
if (!IS_ERR(gpio_regulator)) {
ret = regulator_enable(gpio_regulator);
if (ret) {
dev_err(&client->dev, "gpio set voltage error\n");
return ret;
}
}
/* Create the PMIC data structure */
tps6518x = kzalloc(sizeof(struct tps6518x), GFP_KERNEL);
if (tps6518x == NULL) {
kfree(client);
return -ENOMEM;
}
/* Initialize the PMIC data structure */
i2c_set_clientdata(client, tps6518x);
tps6518x->dev = &client->dev;
tps6518x->i2c_client = client;
tps6518x_client = client;
ret = tps6518x_detect(client, NULL);
if (ret)
goto err1;
mfd_add_devices(tps6518x->dev, -1, tps6518x_devs,
ARRAY_SIZE(tps6518x_devs),
NULL, 0, NULL);
if (tps6518x->dev->of_node) {
pdata = tps6518x_i2c_parse_dt_pdata(tps6518x->dev);
if (IS_ERR(pdata)) {
ret = PTR_ERR(pdata);
goto err2;
}
}
tps6518x->pdata = pdata;
dev_info(&client->dev, "PMIC TPS6518x for eInk display\n");
printk("tps6518x_probe success\n");
return ret;
err2:
mfd_remove_devices(tps6518x->dev);
err1:
kfree(tps6518x);
return ret;
}
static int tps6518x_remove(struct i2c_client *i2c)
{
struct tps6518x *tps6518x = i2c_get_clientdata(i2c);
mfd_remove_devices(tps6518x->dev);
return 0;
}
static int tps6518x_suspend(struct i2c_client *client, pm_message_t state)
{
return 0;
}
static int tps6518x_resume(struct i2c_client *client)
{
return 0;
}
/* Return 0 if detection is successful, -ENODEV otherwise */
static int tps6518x_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
//struct tps6518x_platform_data *pdata = client->dev.platform_data;
struct i2c_adapter *adapter = client->adapter;
u8 revId;
printk("tps6518x_detect calling\n");
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
/* identification */
revId = i2c_smbus_read_byte_data(client,
REG_TPS6518x_REVID);
/*
* Known rev-ids
* tps165180 pass 1 = 0x50, tps65180 pass2 = 0x60, tps65181 pass1 = 0x51, tps65181 pass2 = 0x61,
* tps65182,
* tps65185 pass0 = 0x45, tps65186 pass0 0x46, tps65185 pass1 = 0x55, tps65186 pass1 0x56, tps65185 pass2 = 0x65, tps65186 pass2 0x66
*/
if (!((revId == TPS65180_PASS1) ||
(revId == TPS65181_PASS1) ||
(revId == TPS65180_PASS2) ||
(revId == TPS65181_PASS2) ||
(revId == TPS65185_PASS0) ||
(revId == TPS65186_PASS0) ||
(revId == TPS65185_PASS1) ||
(revId == TPS65186_PASS1) ||
(revId == TPS65185_PASS2) ||
(revId == TPS65186_PASS2)))
{
dev_info(&adapter->dev,
"Unsupported chip (Revision ID=0x%02X).\n", revId);
return -ENODEV;
}
if (info) {
strlcpy(info->type, "tps6518x_sensor", I2C_NAME_SIZE);
}
printk("tps6518x_detect success\n");
return 0;
}
static const struct i2c_device_id tps6518x_id[] = {
{ "tps6518x", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tps6518x_id);
static const struct of_device_id tps6518x_dt_ids[] = {
{
.compatible = "ti,tps6518x",
.data = (void *) &tps6518x_id[0],
}, {
/* sentinel */
}
};
MODULE_DEVICE_TABLE(of, tps6518x_dt_ids);
static struct i2c_driver tps6518x_driver = {
.driver = {
.name = "tps6518x",
.owner = THIS_MODULE,
.of_match_table = tps6518x_dt_ids,
},
.probe = tps6518x_probe,
.remove = tps6518x_remove,
.suspend = tps6518x_suspend,
.resume = tps6518x_resume,
.id_table = tps6518x_id,
.detect = tps6518x_detect,
.address_list = &normal_i2c[0],
};
static int __init tps6518x_init(void)
{
return i2c_add_driver(&tps6518x_driver);
}
static void __exit tps6518x_exit(void)
{
i2c_del_driver(&tps6518x_driver);
}
/*
* Module entry points
*/
subsys_initcall(tps6518x_init);
module_exit(tps6518x_exit);

View File

@ -390,6 +390,10 @@ config REGULATOR_MAX77620
chip to control Step-Down DC-DC and LDOs. Say Y here to
enable the regulator driver.
config REGULATOR_TPS6518X
tristate "Texas Instruments TPS6518X Regulator Support"
depends on MFD_TPS6518X
config REGULATOR_MAX8649
tristate "Maxim 8649 voltage regulator"
depends on I2C

View File

@ -52,6 +52,7 @@ obj-$(CONFIG_REGULATOR_MAX14577) += max14577-regulator.o
obj-$(CONFIG_REGULATOR_MAX1586) += max1586.o
obj-$(CONFIG_REGULATOR_MAX17135) += max17135-regulator.o
obj-$(CONFIG_REGULATOR_MAX77620) += max77620-regulator.o
obj-$(CONFIG_REGULATOR_TPS6518X) += tps6518x-regulator.o
obj-$(CONFIG_REGULATOR_MAX8649) += max8649.o
obj-$(CONFIG_REGULATOR_MAX8660) += max8660.o
obj-$(CONFIG_REGULATOR_MAX8907) += max8907-regulator.o

View File

@ -0,0 +1,810 @@
/*
* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/tps6518x.h>
#include <linux/gpio.h>
#include <linux/pmic_status.h>
#include <linux/of_gpio.h>
struct tps6518x_data {
int num_regulators;
struct tps6518x *tps6518x;
struct regulator_dev **rdev;
};
static int tps6518x_pass_num = { 2 };
static int tps6518x_vcom = { -2680000 };
static int tps65180_current_Enable_Register = 0;
static int tps6518x_is_power_good(struct tps6518x *tps6518x);
/*
* to_reg_val(): Creates a register value with new data
*
* Creates a new register value for a particular field. The data
* outside of the new field is not modified.
*
* @cur_reg: current value in register
* @reg_mask: mask of field bits to be modified
* @fld_val: new value for register field.
*/
static unsigned int to_reg_val(unsigned int cur_reg, unsigned int fld_mask,
unsigned int fld_val)
{
return (cur_reg & (~fld_mask)) | fld_val;
}
/*
* Regulator operations
*/
/* Convert uV to the VCOM register bitfield setting */
static int vcom_rs_to_uV(unsigned int reg_setting)
{
if (reg_setting <= TPS65180_VCOM_MIN_SET)
return TPS65180_VCOM_MIN_uV;
if (reg_setting >= TPS65180_VCOM_MAX_SET)
return TPS65180_VCOM_MAX_uV;
return -(reg_setting * TPS65180_VCOM_STEP_uV);
}
static int vcom2_rs_to_uV(unsigned int reg_setting)
{
if (reg_setting <= TPS65185_VCOM_MIN_SET)
return TPS65185_VCOM_MIN_uV;
if (reg_setting >= TPS65185_VCOM_MAX_SET)
return TPS65185_VCOM_MAX_uV;
return -(reg_setting * TPS65185_VCOM_STEP_uV);
}
static int vcom_uV_to_rs(int uV)
{
if (uV <= TPS65180_VCOM_MIN_uV)
return TPS65180_VCOM_MIN_SET;
if (uV >= TPS65180_VCOM_MAX_uV)
return TPS65180_VCOM_MAX_SET;
return (-uV) / TPS65180_VCOM_STEP_uV;
}
static int vcom2_uV_to_rs(int uV)
{
if (uV <= TPS65185_VCOM_MIN_uV)
return TPS65185_VCOM_MIN_SET;
if (uV >= TPS65185_VCOM_MAX_uV)
return TPS65185_VCOM_MAX_SET;
return (-uV) / TPS65185_VCOM_STEP_uV;
}
static int epdc_pwr0_enable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
gpio_set_value(tps6518x->gpio_pmic_powerup, 1);
return 0;
}
static int epdc_pwr0_disable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
gpio_set_value(tps6518x->gpio_pmic_powerup, 0);
return 0;
}
static int tps6518x_v3p3_enable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
gpio_set_value(tps6518x->gpio_pmic_powerup, 1);
return 0;
}
static int tps6518x_v3p3_disable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
gpio_set_value(tps6518x->gpio_pmic_powerup, 0);
return 0;
}
static int tps6518x_v3p3_is_enabled(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
int gpio = gpio_get_value(tps6518x->gpio_pmic_powerup);
if (gpio == 0)
return 0;
else
return 1;
}
static int tps6518x_vcom_set_voltage(struct regulator_dev *reg,
int minuV, int uV, unsigned *selector)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
unsigned int cur_reg_val; /* current register value to modify */
unsigned int new_reg_val; /* new register value to write */
int retval;
/*
* this will not work on tps65182
*/
if (tps6518x->revID == 65182)
return 0;
#if 0
if (uV < 200000)
return 0;
#endif
switch (tps6518x->revID & 15)
{
case 0 : /* TPS65180 */
case 1 : /* TPS65181 */
case 4 : /* TPS65180-rev1 */
tps6518x_reg_read(REG_TPS65180_VCOM_ADJUST,&cur_reg_val);
new_reg_val = to_reg_val(cur_reg_val,
BITFMASK(VCOM_SET),
BITFVAL(VCOM_SET, vcom_uV_to_rs(uV)));
retval = tps6518x_reg_write(REG_TPS65180_VCOM_ADJUST,
new_reg_val);
break;
case 5 : /* TPS65185 */
case 6 : /* TPS65186 */
gpio_set_value(tps6518x->gpio_pmic_wakeup,1);
retval = tps6518x_reg_write(REG_TPS65185_VCOM1,
vcom2_uV_to_rs(uV) & 255);
tps6518x_reg_read( REG_TPS65185_VCOM2,&cur_reg_val);
new_reg_val = to_reg_val(cur_reg_val,
BITFMASK(VCOM2_SET),
BITFVAL(VCOM2_SET, vcom2_uV_to_rs(uV)/256));
retval = tps6518x_reg_write(REG_TPS65185_VCOM2,
new_reg_val);
break;
default :
retval = -1;
}
return retval;
}
static int tps6518x_vcom_get_voltage(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
unsigned int cur_reg_val; /* current register value */
unsigned int cur_reg2_val; /* current register value */
unsigned int cur_fld_val; /* current bitfield value*/
int vcomValue;
/*
* this will not work on tps65182
*/
if (tps6518x->revID == 65182)
return 0;
switch (tps6518x->revID & 15)
{
case 0 : /* TPS65180 */
case 1 : /* TPS65181 */
case 4 : /* TPS65180-rev1 */
tps6518x_reg_read(REG_TPS65180_VCOM_ADJUST, &cur_reg_val);
cur_fld_val = BITFEXT(cur_reg_val, VCOM_SET);
vcomValue = vcom_rs_to_uV(cur_fld_val);
break;
case 5 : /* TPS65185 */
case 6 : /* TPS65186 */
tps6518x_reg_read(REG_TPS65185_VCOM1,&cur_reg_val);
tps6518x_reg_read(REG_TPS65185_VCOM2,&cur_reg2_val);
cur_reg_val |= 256 * (1 & cur_reg2_val);
vcomValue = vcom2_rs_to_uV(cur_reg_val);
break;
default:
vcomValue = 0;
}
return vcomValue;
}
static int tps6518x_vcom_enable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
unsigned int cur_reg_val; /* current register value */
int vcomEnable = 0;
/*
* check for the TPS65182 device
*/
if (tps6518x->revID == 65182)
{
gpio_set_value(tps6518x->gpio_pmic_vcom_ctrl,vcomEnable);
return 0;
}
/*
* Check to see if we need to set the VCOM voltage.
* Should only be done one time. And, we can
* only change vcom voltage if we have been enabled.
*/
if (!tps6518x->vcom_setup && tps6518x_is_power_good(tps6518x)) {
tps6518x_vcom_set_voltage(reg,
tps6518x->vcom_uV,
tps6518x->vcom_uV,
NULL);
tps6518x->vcom_setup = true;
}
switch (tps6518x->revID & 15)
{
case 0 : /* TPS65180 */
case 1 : /* TPS65181 */
case 4 : /* TPS65180-rev1 */
vcomEnable = 1;
break;
case 5 : /* TPS65185 */
case 6 : /* TPS65186 */
tps6518x_reg_read(REG_TPS65185_VCOM2,&cur_reg_val);
// do not enable vcom if HiZ bit is set
if (cur_reg_val & (1<<VCOM_HiZ_LSH))
vcomEnable = 0;
else
vcomEnable = 1;
break;
default:
vcomEnable = 0;
}
gpio_set_value(tps6518x->gpio_pmic_vcom_ctrl,vcomEnable);
return 0;
}
static int tps6518x_vcom_disable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
gpio_set_value(tps6518x->gpio_pmic_vcom_ctrl,0);
return 0;
}
static int tps6518x_vcom_is_enabled(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
int gpio = gpio_get_value(tps6518x->gpio_pmic_vcom_ctrl);
if (gpio == 0)
return 0;
else
return 1;
}
static int tps6518x_is_power_good(struct tps6518x *tps6518x)
{
/*
* XOR of polarity (starting value) and current
* value yields whether power is good.
*/
return gpio_get_value(tps6518x->gpio_pmic_pwrgood) ^
tps6518x->pwrgood_polarity;
}
static int tps6518x_wait_power_good(struct tps6518x *tps6518x)
{
int i;
for (i = 0; i < tps6518x->max_wait * 3; i++) {
if (tps6518x_is_power_good(tps6518x))
return 0;
msleep(1);
}
return -ETIMEDOUT;
}
static int tps6518x_display_enable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
unsigned int cur_reg_val; /* current register value to modify */
unsigned int fld_mask; /* register mask for bitfield to modify */
unsigned int fld_val; /* new bitfield value to write */
unsigned int new_reg_val; /* new register value to write */
if (tps6518x->revID == 65182)
{
epdc_pwr0_enable(reg);
}
else
{
gpio_set_value(tps6518x->gpio_pmic_wakeup,1);
/* enable display regulators */
cur_reg_val = tps65180_current_Enable_Register & 0x3f;
fld_mask = BITFMASK(VDDH_EN) | BITFMASK(VPOS_EN) |
BITFMASK(VEE_EN) | BITFMASK(VNEG_EN);
fld_val = BITFVAL(VDDH_EN, true) | BITFVAL(VPOS_EN, true) |
BITFVAL(VEE_EN, true) | BITFVAL(VNEG_EN, true) | BITFVAL(VCOM_EN, true);
new_reg_val = tps65180_current_Enable_Register = to_reg_val(cur_reg_val, fld_mask, fld_val);
tps6518x_reg_write(REG_TPS65180_ENABLE, new_reg_val);
/* turn on display regulators */
cur_reg_val = tps65180_current_Enable_Register & 0x3f;
fld_mask = BITFMASK(ACTIVE);
fld_val = BITFVAL(ACTIVE, true);
new_reg_val = tps65180_current_Enable_Register = to_reg_val(cur_reg_val, fld_mask, fld_val);
tps6518x_reg_write(REG_TPS65180_ENABLE, new_reg_val);
}
return tps6518x_wait_power_good(tps6518x);
}
static int tps6518x_display_disable(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
unsigned int cur_reg_val; /* current register value to modify */
unsigned int fld_mask; /* register mask for bitfield to modify */
unsigned int fld_val; /* new bitfield value to write */
unsigned int new_reg_val; /* new register value to write */
if (tps6518x->revID == 65182)
{
epdc_pwr0_disable(reg);
}
else
{
/* turn off display regulators */
cur_reg_val = tps65180_current_Enable_Register & 0x3f;
fld_mask = BITFMASK(VCOM_EN) | BITFMASK(STANDBY);
fld_val = BITFVAL(VCOM_EN, true) | BITFVAL(STANDBY, true);
new_reg_val = tps65180_current_Enable_Register = to_reg_val(cur_reg_val, fld_mask, fld_val);
tps6518x_reg_write(REG_TPS65180_ENABLE, new_reg_val);
}
msleep(tps6518x->max_wait);
return 0;
}
static int tps6518x_display_is_enabled(struct regulator_dev *reg)
{
struct tps6518x *tps6518x = rdev_get_drvdata(reg);
if (tps6518x->revID == 65182)
return gpio_get_value(tps6518x->gpio_pmic_wakeup) ? 1:0;
else
return tps65180_current_Enable_Register & BITFMASK(ACTIVE);
}
/*
* Regulator operations
*/
static struct regulator_ops tps6518x_display_ops = {
.enable = tps6518x_display_enable,
.disable = tps6518x_display_disable,
.is_enabled = tps6518x_display_is_enabled,
};
static struct regulator_ops tps6518x_vcom_ops = {
.enable = tps6518x_vcom_enable,
.disable = tps6518x_vcom_disable,
.get_voltage = tps6518x_vcom_get_voltage,
.set_voltage = tps6518x_vcom_set_voltage,
.is_enabled = tps6518x_vcom_is_enabled,
};
static struct regulator_ops tps6518x_v3p3_ops = {
.enable = tps6518x_v3p3_enable,
.disable = tps6518x_v3p3_disable,
.is_enabled = tps6518x_v3p3_is_enabled,
};
/*
* Regulator descriptors
*/
static struct regulator_desc tps6518x_reg[TPS6518x_NUM_REGULATORS] = {
{
.name = "DISPLAY",
.id = TPS6518x_DISPLAY,
.ops = &tps6518x_display_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "VCOM",
.id = TPS6518x_VCOM,
.ops = &tps6518x_vcom_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
{
.name = "V3P3",
.id = TPS6518x_V3P3,
.ops = &tps6518x_v3p3_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
},
};
static void tps6518x_setup_timings(struct tps6518x *tps6518x)
{
int temp0, temp1, temp2, temp3;
/* read the current setting in the PMIC */
if ((tps6518x->revID == TPS65180_PASS1) || (tps6518x->revID == TPS65181_PASS1) ||
(tps6518x->revID == TPS65180_PASS2) || (tps6518x->revID == TPS65181_PASS2)) {
tps6518x_reg_read(REG_TPS65180_PWRSEQ0, &temp0);
tps6518x_reg_read(REG_TPS65180_PWRSEQ1, &temp1);
tps6518x_reg_read(REG_TPS65180_PWRSEQ2, &temp2);
if ((temp0 != tps6518x->pwr_seq0) ||
(temp1 != tps6518x->pwr_seq1) ||
(temp2 != tps6518x->pwr_seq2)) {
tps6518x_reg_write(REG_TPS65180_PWRSEQ0, tps6518x->pwr_seq0);
tps6518x_reg_write(REG_TPS65180_PWRSEQ1, tps6518x->pwr_seq1);
tps6518x_reg_write(REG_TPS65180_PWRSEQ2, tps6518x->pwr_seq2);
}
}
if ((tps6518x->revID == TPS65185_PASS0) ||
(tps6518x->revID == TPS65186_PASS0) ||
(tps6518x->revID == TPS65185_PASS1) ||
(tps6518x->revID == TPS65186_PASS1) ||
(tps6518x->revID == TPS65185_PASS2) ||
(tps6518x->revID == TPS65186_PASS2)) {
tps6518x_reg_read(REG_TPS65185_UPSEQ0, &temp0);
tps6518x_reg_read(REG_TPS65185_UPSEQ1, &temp1);
tps6518x_reg_read(REG_TPS65185_DWNSEQ0, &temp2);
tps6518x_reg_read(REG_TPS65185_DWNSEQ1, &temp3);
if ((temp0 != tps6518x->upseq0) ||
(temp1 != tps6518x->upseq1) ||
(temp2 != tps6518x->dwnseq0) ||
(temp3 != tps6518x->dwnseq1)) {
tps6518x_reg_write(REG_TPS65185_UPSEQ0, tps6518x->upseq0);
tps6518x_reg_write(REG_TPS65185_UPSEQ1, tps6518x->upseq1);
tps6518x_reg_write(REG_TPS65185_DWNSEQ0, tps6518x->dwnseq0);
tps6518x_reg_write(REG_TPS65185_DWNSEQ1, tps6518x->dwnseq1);
}
}
}
#define CHECK_PROPERTY_ERROR_KFREE(prop) \
do { \
int ret = of_property_read_u32(tps6518x->dev->of_node, \
#prop, &tps6518x->prop); \
if (ret < 0) { \
return ret; \
} \
} while (0);
#ifdef CONFIG_OF
static int tps6518x_pmic_dt_parse_pdata(struct platform_device *pdev,
struct tps6518x_platform_data *pdata)
{
struct tps6518x *tps6518x = dev_get_drvdata(pdev->dev.parent);
struct device_node *pmic_np, *regulators_np, *reg_np;
struct tps6518x_regulator_data *rdata;
int i, ret;
pmic_np = of_node_get(tps6518x->dev->of_node);
if (!pmic_np) {
dev_err(&pdev->dev, "could not find pmic sub-node\n");
return -ENODEV;
}
regulators_np = of_find_node_by_name(pmic_np, "regulators");
if (!regulators_np) {
dev_err(&pdev->dev, "could not find regulators sub-node\n");
return -EINVAL;
}
pdata->num_regulators = of_get_child_count(regulators_np);
dev_dbg(&pdev->dev, "num_regulators %d\n", pdata->num_regulators);
rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
pdata->num_regulators, GFP_KERNEL);
if (!rdata) {
of_node_put(regulators_np);
dev_err(&pdev->dev, "could not allocate memory for"
"regulator data\n");
return -ENOMEM;
}
pdata->regulators = rdata;
for_each_child_of_node(regulators_np, reg_np) {
for (i = 0; i < ARRAY_SIZE(tps6518x_reg); i++)
if (!of_node_cmp(reg_np->name, tps6518x_reg[i].name))
break;
if (i == ARRAY_SIZE(tps6518x_reg)) {
dev_warn(&pdev->dev, "don't know how to configure"
"regulator %s\n", reg_np->name);
continue;
}
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(&pdev->dev,
reg_np);
rdata->reg_node = reg_np;
rdata++;
}
of_node_put(regulators_np);
tps6518x->max_wait = (6 + 6 + 6 + 6);
tps6518x->gpio_pmic_wakeup = of_get_named_gpio(pmic_np,
"gpio_pmic_wakeup", 0);
if (!gpio_is_valid(tps6518x->gpio_pmic_wakeup)) {
dev_err(&pdev->dev, "no epdc pmic wakeup pin available\n");
goto err;
}
ret = devm_gpio_request_one(&pdev->dev, tps6518x->gpio_pmic_wakeup,
GPIOF_OUT_INIT_LOW, "epdc-pmic-wake");
if (ret < 0)
goto err;
tps6518x->gpio_pmic_vcom_ctrl = of_get_named_gpio(pmic_np,
"gpio_pmic_vcom_ctrl", 0);
if (!gpio_is_valid(tps6518x->gpio_pmic_vcom_ctrl)) {
dev_err(&pdev->dev, "no epdc pmic vcom_ctrl pin available\n");
goto err;
}
ret = devm_gpio_request_one(&pdev->dev, tps6518x->gpio_pmic_vcom_ctrl,
GPIOF_OUT_INIT_LOW, "epdc-vcom");
if (ret < 0)
goto err;
tps6518x->gpio_pmic_powerup = of_get_named_gpio(pmic_np,
"gpio_pmic_powerup", 0);
if (!gpio_is_valid(tps6518x->gpio_pmic_powerup)) {
dev_err(&pdev->dev, "no epdc pmic powerup pin available\n");
goto err;
}
ret = devm_gpio_request_one(&pdev->dev, tps6518x->gpio_pmic_powerup,
GPIOF_OUT_INIT_LOW, "epdc-powerup");
if (ret < 0)
goto err;
tps6518x->gpio_pmic_intr = of_get_named_gpio(pmic_np,
"gpio_pmic_intr", 0);
if (!gpio_is_valid(tps6518x->gpio_pmic_intr)) {
dev_err(&pdev->dev, "no epdc pmic intr pin available\n");
goto err;
}
ret = devm_gpio_request_one(&pdev->dev, tps6518x->gpio_pmic_intr,
GPIOF_IN, "epdc-pmic-int");
if (ret < 0)
goto err;
tps6518x->gpio_pmic_pwrgood = of_get_named_gpio(pmic_np,
"gpio_pmic_pwrgood", 0);
if (!gpio_is_valid(tps6518x->gpio_pmic_pwrgood)) {
dev_err(&pdev->dev, "no epdc pmic pwrgood pin available\n");
goto err;
}
ret = devm_gpio_request_one(&pdev->dev, tps6518x->gpio_pmic_pwrgood,
GPIOF_IN, "epdc-pwrstat");
if (ret < 0)
goto err;
err:
return 0;
}
#else
static int tps6518x_pmic_dt_parse_pdata(struct platform_device *pdev,
struct tps6518x *tps6518x)
{
return 0;
}
#endif /* !CONFIG_OF */
/*
* Regulator init/probing/exit functions
*/
static int tps6518x_regulator_probe(struct platform_device *pdev)
{
struct tps6518x *tps6518x = dev_get_drvdata(pdev->dev.parent);
struct tps6518x_platform_data *pdata = tps6518x->pdata;
struct tps6518x_data *priv;
struct regulator_dev **rdev;
struct regulator_config config = { };
int size, i, ret = 0;
printk("tps6518x_regulator_probe starting\n");
if (tps6518x->dev->of_node) {
ret = tps6518x_pmic_dt_parse_pdata(pdev, pdata);
if (ret)
return ret;
}
priv = devm_kzalloc(&pdev->dev, sizeof(struct tps6518x_data),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
size = sizeof(struct regulator_dev *) * pdata->num_regulators;
priv->rdev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
if (!priv->rdev)
return -ENOMEM;
rdev = priv->rdev;
priv->num_regulators = pdata->num_regulators;
platform_set_drvdata(pdev, priv);
tps6518x->vcom_setup = false;
tps6518x->pass_num = tps6518x_pass_num;
tps6518x->vcom_uV = tps6518x_vcom;
for (i = 0; i < pdata->num_regulators; i++) {
int id = pdata->regulators[i].id;
config.dev = tps6518x->dev;
config.init_data = pdata->regulators[i].initdata;
config.driver_data = tps6518x;
config.of_node = pdata->regulators[i].reg_node;
rdev[i] = regulator_register(&tps6518x_reg[id], &config);
if (IS_ERR(rdev[i])) {
ret = PTR_ERR(rdev[i]);
dev_err(&pdev->dev, "regulator init failed for %d\n",
id);
rdev[i] = NULL;
goto err;
}
}
/*
* Set up PMIC timing values.
* Should only be done one time! Timing values may only be
* changed a limited number of times according to spec.
*/
tps6518x_setup_timings(tps6518x);
printk("tps6518x_regulator_probe success\n");
return 0;
err:
while (--i >= 0)
regulator_unregister(rdev[i]);
return ret;
}
static int tps6518x_regulator_remove(struct platform_device *pdev)
{
struct tps6518x_data *priv = platform_get_drvdata(pdev);
struct regulator_dev **rdev = priv->rdev;
int i;
for (i = 0; i < priv->num_regulators; i++)
regulator_unregister(rdev[i]);
return 0;
}
static const struct platform_device_id tps6518x_pmic_id[] = {
{ "tps6518x-pmic", 0},
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(platform, tps6518x_pmic_id);
static struct platform_driver tps6518x_regulator_driver = {
.probe = tps6518x_regulator_probe,
.remove = tps6518x_regulator_remove,
.id_table = tps6518x_pmic_id,
.driver = {
.name = "tps6518x-pmic",
},
};
static int __init tps6518x_regulator_init(void)
{
return platform_driver_register(&tps6518x_regulator_driver);
}
subsys_initcall_sync(tps6518x_regulator_init);
static void __exit tps6518x_regulator_exit(void)
{
platform_driver_unregister(&tps6518x_regulator_driver);
}
module_exit(tps6518x_regulator_exit);
/*
* Parse user specified options (`tps6518x:')
* example:
* tps6518x:pass=2,vcom=-1250000
*/
static int __init tps6518x_setup(char *options)
{
int ret;
char *opt;
unsigned long ulResult;
while ((opt = strsep(&options, ",")) != NULL) {
if (!*opt)
continue;
if (!strncmp(opt, "pass=", 5)) {
ret = strict_strtoul((const char *)(opt + 5), 0, &ulResult);
tps6518x_pass_num = ulResult;
if (ret < 0)
return ret;
}
if (!strncmp(opt, "vcom=", 5)) {
int offs = 5;
if (opt[5] == '-')
offs = 6;
ret = strict_strtoul((const char *)(opt + offs), 0, &ulResult);
tps6518x_vcom = (int) ulResult;
if (ret < 0)
return ret;
tps6518x_vcom = -tps6518x_vcom;
}
}
return 1;
}
__setup("tps6518x:", tps6518x_setup);
static int __init tps65182_setup(char *options)
{
int ret;
char *opt;
unsigned long ulResult;
while ((opt = strsep(&options, ",")) != NULL) {
if (!*opt)
continue;
if (!strncmp(opt, "pass=", 5)) {
ret = strict_strtoul((const char *)(opt + 5), 0, &ulResult);
tps6518x_pass_num = ulResult;
if (ret < 0)
return ret;
}
if (!strncmp(opt, "vcom=", 5)) {
int offs = 5;
if (opt[5] == '-')
offs = 6;
ret = strict_strtoul((const char *)(opt + offs), 0, &ulResult);
tps6518x_vcom = (int) ulResult;
if (ret < 0)
return ret;
tps6518x_vcom = -tps6518x_vcom;
}
}
return 1;
}
__setup("tps65182:", tps65182_setup);
/* Module information */
MODULE_DESCRIPTION("TPS6518x regulator driver");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,357 @@
/*
* Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#ifndef __LINUX_REGULATOR_TPS6518x_H_
#define __LINUX_REGULATOR_TPS6518x_H_
/*
* EPDC PMIC I2C address
* PAPYRUS II 1p1 and later uses 0x68, others 0x48
*/
#define EPDC_PMIC_I2C_ADDR 0x68
/*
* currently supported rev IDs
*/
//#define TPS65180_PASS1 0x54
//#define TPS65181_PASS1 0x55
#define TPS65180_PASS1 0x50
#define TPS65181_PASS1 0x51
#define TPS65180_PASS2 0x60
#define TPS65181_PASS2 0x61
#define TPS65185_PASS0 0x45
#define TPS65186_PASS0 0x46
#define TPS65185_PASS1 0x55
#define TPS65186_PASS1 0x56
#define TPS65185_PASS2 0x65
#define TPS65186_PASS2 0x66
/*
* PMIC Register Addresses
*/
enum {
REG_TPS6518x_TMST_VAL = 0x0,
REG_TPS65185_ENABLE,
REG_TPS65185_VADJ,
REG_TPS65185_VCOM1,
REG_TPS65185_VCOM2,
REG_TPS65185_INT_EN1,
REG_TPS65185_INT_EN2,
REG_TPS65185_INT1,
REG_TPS65185_INT2,
REG_TPS65185_UPSEQ0,
REG_TPS65185_UPSEQ1,
REG_TPS65185_DWNSEQ0,
REG_TPS65185_DWNSEQ1,
REG_TPS65185_TMST1,
REG_TPS65185_TMST2,
REG_TPS6518x_PG,
REG_TPS6518x_REVID,
TPS6518x_REG_NUM,
};
enum {
REG_TPS65180_TMST_VAL = 0x0,
REG_TPS65180_ENABLE,
REG_TPS65180_VP_ADJUST,
REG_TPS65180_VN_ADJUST,
REG_TPS65180_VCOM_ADJUST,
REG_TPS65180_INT_EN1,
REG_TPS65180_INT_EN2,
REG_TPS65180_INT1,
REG_TPS65180_INT2,
REG_TPS65180_PWRSEQ0,
REG_TPS65180_PWRSEQ1,
REG_TPS65180_PWRSEQ2,
REG_TPS65180_TMST_CONFIG,
REG_TPS65180_TMST_OS,
REG_TPS65180_TMST_HYST,
REG_TPS65180_PG_STATUS,
REG_TPS65180_REVID,
REG_TPS65180_FIX_READ_PTR,
TPS65180_REG_NUM,
};
#define TPS6518x_MAX_REGISTER 0xFF
/*
* Bitfield macros that use rely on bitfield width/shift information.
*/
#define BITFMASK(field) (((1U << (field ## _WID)) - 1) << (field ## _LSH))
#define BITFVAL(field, val) ((val) << (field ## _LSH))
#define BITFEXT(var, bit) ((var & BITFMASK(bit)) >> (bit ## _LSH))
/*
* Shift and width values for each register bitfield
*/
/* TMST_VALUE */
#define TMST_VALUE_LSH 0
#define TMST_VALUE_WID 8
/* ENABLE */
#define ACTIVE_LSH 7
#define ACTIVE_WID 1
#define STANDBY_LSH 6
#define STANDBY_WID 1
#define V3P3_SW_EN_LSH 5
#define V3P3_SW_EN_WID 1
#define VCOM_EN_LSH 4
#define VCOM_EN_WID 1
#define VDDH_EN_LSH 3
#define VDDH_EN_WID 1
#define VPOS_EN_LSH 2
#define VPOS_EN_WID 1
#define VEE_EN_LSH 1
#define VEE_EN_WID 1
#define VNEG_EN_LSH 0
#define VNEG_EN_WID 1
/* VCOM_ADJUST */
#define VCOM_SET_LSH 0
#define VCOM_SET_WID 8
#define VCOM1_SET_LSH 0
#define VCOM1_SET_WID 8
#define VCOM2_SET_LSH 0
#define VCOM2_SET_WID 1
#define VCOM_ACQ_LSH 15
#define VCOM_ACQ_WID 1
#define VCOM_PROG_LSH 14
#define VCOM_PEOG_WID 1
#define VCOM_HiZ_LSH 13
#define VCOM_HiZ_WID 1
#define VCOM_AVG_LSH 11
#define VCOM_AVG_WID 2
/* INT_ENABLE1 */
#define TSD_EN_LSH 6
#define TSD_EN_WID 1
#define HOT_EN_LSH 5
#define HOT_EN_WID 1
#define TMST_HOT_EN_LSH 4
#define TMST_HOT_EN_WID 1
#define TMST_COOL_EN_LSH 3
#define TMST_COOL_EN_WID 1
#define UVLO_EN_LSH 2
#define UVLO_EN_WID 1
/* INT_ENABLE2 */
#define VB_UV_EN_LSH 7
#define VB_UV_EN_WID 1
#define VDDH_UV_EN_LSH 6
#define VDDH_UV_EN_WID 1
#define VN_UV_EN_LSH 5
#define VN_UV_EN_WID 1
#define VPOS_UV_EN_LSH 4
#define VPOS_UV_EN_WID 1
#define VEE_UV_EN_LSH 3
#define VEE_UV_EN_WID 1
#define VNEG_UV_EN_LSH 1
#define VNEG_UV_EN_WID 1
#define EOC_EN_LSH 0
#define EOC_EN_WID 1
/* INT_STATUS1 */
#define TSDN_LSH 6
#define TSDN_WID 1
#define HOT_LSH 5
#define HOT_WID 1
#define TMST_HOT_LSH 4
#define TMST_HOT_WID 1
#define TMST_COOL_LSH 3
#define TMST_COOL_WID 1
#define UVLO_LSH 2
#define UVLO_WID 1
/* INT_STATUS2 */
#define VB_UV_LSH 7
#define VB_UV_WID 1
#define VDDH_UV_LSH 6
#define VDDH_UV_WID 1
#define VN_UV_LSH 5
#define VN_UV_WID 1
#define VPOS_UV_LSH 4
#define VPOS_UV_WID 1
#define VEE_UV_LSH 3
#define VEE_UV_WID 1
#define VNEG_UV_LSH 1
#define VNEG_UV_WID 1
#define EOC_LSH 0
#define EOC_WID 1
/* PWR_SEQ0 */
#define VDDH_SEQ_LSH 6
#define VDDH_SEQ_WID 2
#define VPOS_SEQ_LSH 4
#define VPOS_SEQ_WID 2
#define VEE_SEQ_LSH 2
#define VEE_SEQ_WID 2
#define VNEG_SEQ_LSH 0
#define VNEG_SEQ_WID 2
/* PWR_SEQ1 */
#define DLY1_LSH 4
#define DLY1_WID 4
#define DLY0_LSH 0
#define DLY0_WID 4
/* PWR_SEQ2 */
#define DLY3_LSH 4
#define DLY3_WID 4
#define DLY2_LSH 0
#define DLY2_WID 4
/* TMST_CONFIG */
#define READ_THERM_LSH 7
#define READ_THERM_WID 1
#define CONV_END_LSH 5
#define CONV_END_WID 1
#define FAULT_QUE_LSH 3
#define FAULT_QUE_WID 2
#define FAULT_QUE_CLR_LSH 2
#define FAULT_QUE_CLR_WID 1
/* TMST_OS */
#define TMST_HOT_SET_LSH 0
#define TMST_HOT_SET_WID 8
/* TMST_HYST */
#define TMST_COOL_SET_LSH 0
#define TMST_COOL_SET_WID 8
/* PG_STATUS */
#define VB_PG_LSH 7
#define VB_PG_WID 1
#define VDDH_PG_LSH 6
#define VDDH_PG_WID 1
#define VN_PG_LSH 5
#define VN_PG_WID 1
#define VPOS_PG_LSH 4
#define VPOS_PG_WID 1
#define VEE_PG_LSH 3
#define VEE_PG_WID 1
#define VNEG_PG_LSH 1
#define VNEG_PG_WID 1
/* REVID */
#define MJREV_LSH 6
#define MJREV_WID 2
#define MNREV_LSH 4
#define MNREV_WID 2
#define VERSION_LSH 0
#define VERSION_WID 4
/* FIX_READ_POINTER */
#define FIX_RD_PTR_LSH 0
#define FIX_RD_PTR_WID 1
/*
* VCOM Definitions
*
* The register fields accept voltages in the range 0V to -2.75V, but the
* VCOM parametric performance is only guaranteed from -0.3V to -2.5V.
*/
#define TPS65180_VCOM_MIN_uV -2750000
#define TPS65180_VCOM_MAX_uV 0
#define TPS65180_VCOM_MIN_SET 0
#define TPS65180_VCOM_MAX_SET 255
#define TPS65180_VCOM_BASE_uV 10740
#define TPS65180_VCOM_STEP_uV 10740
#define TPS65185_VCOM_MIN_uV -5110000
#define TPS65185_VCOM_MAX_uV 0
#define TPS65185_VCOM_MIN_SET 0
#define TPS65185_VCOM_MAX_SET 511
#define TPS65185_VCOM_BASE_uV 10000
#define TPS65185_VCOM_STEP_uV 10000
#define TPS6518x_VCOM_MIN_VAL 0
#define TPS6518x_VCOM_MAX_VAL 255
struct regulator_init_data;
struct tps6518x {
/* chip revision */
int revID;
struct device *dev;
struct tps6518x_platform_data *pdata;
/* Platform connection */
struct i2c_client *i2c_client;
/* Timings */
unsigned int pwr_seq0;
unsigned int pwr_seq1;
unsigned int pwr_seq2;
unsigned int upseq0;
unsigned int upseq1;
unsigned int dwnseq0;
unsigned int dwnseq1;
/* GPIOs */
int gpio_pmic_pwrgood;
int gpio_pmic_vcom_ctrl;
int gpio_pmic_wakeup;
int gpio_pmic_intr;
int gpio_pmic_powerup;
/* TPS6518x part variables */
int pass_num;
int vcom_uV;
/* One-time VCOM setup marker */
bool vcom_setup;
/* powerup/powerdown wait time */
int max_wait;
/* Dynamically determined polarity for PWRGOOD */
int pwrgood_polarity;
};
enum {
/* In alphabetical order */
TPS6518x_DISPLAY, /* virtual master enable */
TPS6518x_VCOM,
TPS6518x_V3P3,
TPS6518x_NUM_REGULATORS,
};
/*
* Declarations
*/
struct regulator_init_data;
struct tps6518x_regulator_data;
struct tps6518x_platform_data {
unsigned int pwr_seq0;
unsigned int pwr_seq1;
unsigned int pwr_seq2;
unsigned int upseq0;
unsigned int upseq1;
unsigned int dwnseq0;
unsigned int dwnseq1;
int gpio_pmic_pwrgood;
int gpio_pmic_vcom_ctrl;
int gpio_pmic_wakeup;
int gpio_pmic_intr;
int gpio_pmic_powerup;
int pass_num;
int vcom_uV;
/* PMIC */
struct tps6518x_regulator_data *regulators;
int num_regulators;
};
struct tps6518x_regulator_data {
int id;
struct regulator_init_data *initdata;
struct device_node *reg_node;
};
int tps6518x_reg_read(int reg_num, unsigned int *reg_val);
int tps6518x_reg_write(int reg_num, const unsigned int reg_val);
#endif