Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 043aeefc authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "NFC: Add support for LDO voting"

parents bfaa5be3 a8901698
Loading
Loading
Loading
Loading
+134 −1
Original line number Diff line number Diff line
@@ -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
+24 −1
Original line number Diff line number Diff line
@@ -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_
+23 −1
Original line number Diff line number Diff line
@@ -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);
+2 −1
Original line number Diff line number Diff line
@@ -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;