mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-09 13:49:24 -04:00
Merge "NFC: Add support for LDO voting"
This commit is contained in:
commit
043aeefccb
4 changed files with 183 additions and 4 deletions
|
|
@ -10,9 +10,10 @@
|
|||
|
||||
|
||||
int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
||||
uint8_t interface)
|
||||
struct platform_ldo *ldo, uint8_t interface)
|
||||
{
|
||||
struct device_node *np = dev->of_node;
|
||||
int ret;
|
||||
|
||||
if (!np) {
|
||||
pr_err("nfc of_node NULL\n");
|
||||
|
|
@ -49,9 +50,139 @@ int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
|||
pr_info("%s: ven %d, dwl req %d, clkreq %d\n", __func__,
|
||||
nfc_gpio->ven, nfc_gpio->dwl_req, nfc_gpio->clkreq);
|
||||
|
||||
// optional property
|
||||
ret = of_property_read_u32_array(np, NFC_LDO_VOL_DT_NAME,
|
||||
(u32 *) ldo->vdd_levels,
|
||||
ARRAY_SIZE(ldo->vdd_levels));
|
||||
if (ret) {
|
||||
dev_err(dev, "error reading NFC VDDIO min and max value\n");
|
||||
// set default as per datasheet
|
||||
ldo->vdd_levels[0] = NFC_VDDIO_MIN;
|
||||
ldo->vdd_levels[1] = NFC_VDDIO_MAX;
|
||||
}
|
||||
|
||||
// optional property
|
||||
ret = of_property_read_u32(np, NFC_LDO_CUR_DT_NAME, &ldo->max_current);
|
||||
if (ret) {
|
||||
dev_err(dev, "error reading NFC current value\n");
|
||||
// set default as per datasheet
|
||||
ldo->max_current = NFC_CURRENT_MAX;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfc_ldo_vote()
|
||||
* @nfc_dev: NFC device containing regulator handle
|
||||
*
|
||||
* LDO voting based on voltage and current entries in DT
|
||||
*
|
||||
* Return: 0 on success and -ve on failure
|
||||
*/
|
||||
int nfc_ldo_vote(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = regulator_set_voltage(nfc_dev->reg,
|
||||
nfc_dev->ldo.vdd_levels[0],
|
||||
nfc_dev->ldo.vdd_levels[1]);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: set voltage failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* pass expected current from NFC in uA */
|
||||
ret = regulator_set_load(nfc_dev->reg, nfc_dev->ldo.max_current);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: set load failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_enable(nfc_dev->reg);
|
||||
if (ret < 0)
|
||||
pr_err("%s: regulator_enable failed\n", __func__);
|
||||
else
|
||||
nfc_dev->is_vreg_enabled = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfc_ldo_config()
|
||||
* @dev: device instance to read DT entry
|
||||
* @nfc_dev: NFC device containing regulator handle
|
||||
*
|
||||
* Configure LDO if entry is present in DT file otherwise
|
||||
* return with success as it's optional
|
||||
*
|
||||
* Return: 0 on success and -ve on failure
|
||||
*/
|
||||
int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (of_get_property(dev->of_node, NFC_LDO_SUPPLY_NAME, NULL)) {
|
||||
// Get the regulator handle
|
||||
nfc_dev->reg = regulator_get(dev, NFC_LDO_SUPPLY_DT_NAME);
|
||||
if (IS_ERR(nfc_dev->reg)) {
|
||||
ret = PTR_ERR(nfc_dev->reg);
|
||||
nfc_dev->reg = NULL;
|
||||
pr_err("%s: regulator_get failed, ret = %d\n",
|
||||
__func__, ret);
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
nfc_dev->reg = NULL;
|
||||
pr_err("%s: regulator entry not present\n", __func__);
|
||||
// return success as it's optional to configure LDO
|
||||
return 0;
|
||||
}
|
||||
|
||||
// LDO config supported by platform DT
|
||||
ret = nfc_ldo_vote(nfc_dev);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: LDO voting failed, ret = %d\n", __func__, ret);
|
||||
regulator_put(nfc_dev->reg);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfc_ldo_unvote()
|
||||
* @nfc_dev: NFC device containing regulator handle
|
||||
*
|
||||
* set voltage and load to zero and disable regulator
|
||||
*
|
||||
* Return: 0 on success and -ve on failure
|
||||
*/
|
||||
int nfc_ldo_unvote(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!nfc_dev->is_vreg_enabled) {
|
||||
pr_err("%s: regulator already disabled\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = regulator_disable(nfc_dev->reg);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: regulator_disable failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
nfc_dev->is_vreg_enabled = false;
|
||||
|
||||
ret = regulator_set_voltage(nfc_dev->reg, 0, NFC_VDDIO_MAX);
|
||||
if (ret < 0) {
|
||||
pr_err("%s: set voltage failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regulator_set_load(nfc_dev->reg, 0);
|
||||
if (ret < 0)
|
||||
pr_err("%s: set load failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void gpio_set_ven(struct nfc_dev *nfc_dev, int value)
|
||||
{
|
||||
if (gpio_get_value(nfc_dev->gpio.ven) != value) {
|
||||
|
|
@ -295,6 +426,7 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
|||
} else {
|
||||
pr_debug("ven already HIGH\n");
|
||||
}
|
||||
nfc_dev->is_ese_session_active = true;
|
||||
} else if (arg == ESE_POWER_OFF) {
|
||||
if (!nfc_dev->nfc_ven_enabled) {
|
||||
pr_debug("NFC not enabled, disabling ven\n");
|
||||
|
|
@ -302,6 +434,7 @@ int nfc_ese_pwr(struct nfc_dev *nfc_dev, unsigned long arg)
|
|||
} else {
|
||||
pr_debug("keep ven high as NFC is enabled\n");
|
||||
}
|
||||
nfc_dev->is_ese_session_active = false;
|
||||
} else if (arg == ESE_COLD_RESET) {
|
||||
|
||||
// set default value for status as failure
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include <linux/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nfcinfo.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include "nfc_i2c_drv.h"
|
||||
#include "nfc_i3c_drv.h"
|
||||
|
|
@ -86,6 +87,15 @@
|
|||
#define DTS_FWDN_GPIO_STR "qcom,sn-firm"
|
||||
#define DTS_CLKREQ_GPIO_STR "qcom,sn-clkreq"
|
||||
#define DTS_CLKSRC_GPIO_STR "qcom,clk-src"
|
||||
#define NFC_LDO_SUPPLY_DT_NAME "qcom,nq-vdd-1p8"
|
||||
#define NFC_LDO_SUPPLY_NAME "qcom,nq-vdd-1p8-supply"
|
||||
#define NFC_LDO_VOL_DT_NAME "qcom,nq-vdd-1p8-voltage"
|
||||
#define NFC_LDO_CUR_DT_NAME "qcom,nq-vdd-1p8-current"
|
||||
|
||||
//as per SN1x0 datasheet
|
||||
#define NFC_VDDIO_MIN 1650000 //in uV
|
||||
#define NFC_VDDIO_MAX 1950000 //in uV
|
||||
#define NFC_CURRENT_MAX 157000 //in uA
|
||||
|
||||
enum ese_ioctl_request {
|
||||
/* eSE POWER ON */
|
||||
|
|
@ -163,6 +173,12 @@ struct platform_gpio {
|
|||
unsigned int dwl_req;
|
||||
};
|
||||
|
||||
// NFC LDO entries from DT
|
||||
struct platform_ldo {
|
||||
int vdd_levels[2];
|
||||
int max_current;
|
||||
};
|
||||
|
||||
//Features specific Parameters
|
||||
struct cold_reset {
|
||||
wait_queue_head_t read_wq;
|
||||
|
|
@ -186,12 +202,16 @@ struct nfc_dev {
|
|||
uint8_t interface;
|
||||
/* NFC VEN pin state */
|
||||
bool nfc_ven_enabled;
|
||||
bool is_vreg_enabled;
|
||||
bool is_ese_session_active;
|
||||
union {
|
||||
struct i2c_dev i2c_dev;
|
||||
struct i3c_dev i3c_dev;
|
||||
};
|
||||
struct platform_gpio gpio;
|
||||
struct platform_ldo ldo;
|
||||
struct cold_reset cold_reset;
|
||||
struct regulator *reg;
|
||||
|
||||
/* read buffer*/
|
||||
size_t kbuflen;
|
||||
|
|
@ -211,7 +231,7 @@ int nfc_dev_open(struct inode *inode, struct file *filp);
|
|||
int nfc_dev_close(struct inode *inode, struct file *filp);
|
||||
long nfc_dev_ioctl(struct file *pfile, unsigned int cmd, unsigned long arg);
|
||||
int nfc_parse_dt(struct device *dev, struct platform_gpio *nfc_gpio,
|
||||
uint8_t interface);
|
||||
struct platform_ldo *ldo, uint8_t interface);
|
||||
int nfc_misc_probe(struct nfc_dev *nfc_dev,
|
||||
const struct file_operations *nfc_fops, int count,
|
||||
char *devname, char *classname);
|
||||
|
|
@ -220,5 +240,8 @@ int configure_gpio(unsigned int gpio, int flag);
|
|||
void read_cold_reset_rsp(struct nfc_dev *nfc_dev, char *header);
|
||||
void gpio_set_ven(struct nfc_dev *nfc_dev, int value);
|
||||
int nfcc_hw_check(struct nfc_dev *nfc_dev);
|
||||
int nfc_ldo_config(struct device *dev, struct nfc_dev *nfc_dev);
|
||||
int nfc_ldo_vote(struct nfc_dev *nfc_dev);
|
||||
int nfc_ldo_unvote(struct nfc_dev *nfc_dev);
|
||||
|
||||
#endif //_NFC_COMMON_H_
|
||||
|
|
|
|||
|
|
@ -256,12 +256,13 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
struct nfc_dev *nfc_dev = NULL;
|
||||
struct i2c_dev *i2c_dev = NULL;
|
||||
struct platform_gpio nfc_gpio;
|
||||
struct platform_ldo nfc_ldo;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
|
||||
//retrieve details of gpios from dt
|
||||
|
||||
ret = nfc_parse_dt(&client->dev, &nfc_gpio, PLATFORM_IF_I2C);
|
||||
ret = nfc_parse_dt(&client->dev, &nfc_gpio, &nfc_ldo, PLATFORM_IF_I2C);
|
||||
if (ret) {
|
||||
pr_err("%s : failed to parse dt\n", __func__);
|
||||
goto err;
|
||||
|
|
@ -341,6 +342,12 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
i2c_disable_irq(nfc_dev);
|
||||
i2c_set_clientdata(client, nfc_dev);
|
||||
|
||||
ret = nfc_ldo_config(&client->dev, nfc_dev);
|
||||
if (ret) {
|
||||
pr_err("LDO config failed\n");
|
||||
goto err_ldo_config_failed;
|
||||
}
|
||||
|
||||
ret = nfcc_hw_check(nfc_dev);
|
||||
if (ret) {
|
||||
pr_err("nfc hw check failed ret %d\n", ret);
|
||||
|
|
@ -349,11 +356,17 @@ int nfc_i2c_dev_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|||
|
||||
device_init_wakeup(&client->dev, true);
|
||||
i2c_dev->irq_wake_up = false;
|
||||
nfc_dev->is_ese_session_active = false;
|
||||
|
||||
pr_info("%s success\n", __func__);
|
||||
return 0;
|
||||
|
||||
err_nfcc_hw_check:
|
||||
if (nfc_dev->reg) {
|
||||
nfc_ldo_unvote(nfc_dev);
|
||||
regulator_put(nfc_dev->reg);
|
||||
}
|
||||
err_ldo_config_failed:
|
||||
free_irq(client->irq, nfc_dev);
|
||||
err_nfc_misc_remove:
|
||||
nfc_misc_remove(nfc_dev, DEV_COUNT);
|
||||
|
|
@ -386,6 +399,15 @@ int nfc_i2c_dev_remove(struct i2c_client *client)
|
|||
ret = -ENODEV;
|
||||
return ret;
|
||||
}
|
||||
|
||||
gpio_set_value(nfc_dev->gpio.ven, 0);
|
||||
// HW dependent delay before LDO goes into LPM mode
|
||||
usleep_range(10000, 10100);
|
||||
if (nfc_dev->reg) {
|
||||
nfc_ldo_unvote(nfc_dev);
|
||||
regulator_put(nfc_dev->reg);
|
||||
}
|
||||
|
||||
device_init_wakeup(&client->dev, false);
|
||||
free_irq(client->irq, nfc_dev);
|
||||
nfc_misc_remove(nfc_dev, DEV_COUNT);
|
||||
|
|
|
|||
|
|
@ -584,12 +584,13 @@ int nfc_i3c_dev_probe(struct i3c_device *device)
|
|||
int ret = 0;
|
||||
struct nfc_dev *nfc_dev = NULL;
|
||||
struct platform_gpio nfc_gpio;
|
||||
struct platform_ldo nfc_ldo;
|
||||
|
||||
pr_debug("%s: enter\n", __func__);
|
||||
|
||||
//retrieve gpio details from dt
|
||||
|
||||
ret = nfc_parse_dt(&device->dev, &nfc_gpio, PLATFORM_IF_I3C);
|
||||
ret = nfc_parse_dt(&device->dev, &nfc_gpio, &nfc_ldo, PLATFORM_IF_I3C);
|
||||
if (ret) {
|
||||
pr_err("%s : failed to parse nfc dt node\n", __func__);
|
||||
goto err;
|
||||
|
|
|
|||
Loading…
Reference in a new issue