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

Commit 3e1004cb authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "NFC: add gpio clk interrupt for 8610 qrd device"

parents e46e7580 294db64b
Loading
Loading
Loading
Loading
+8 −6
Original line number Diff line number Diff line
@@ -8,13 +8,15 @@ Required properties:
- reg: NCI i2c slave address.
- qcom,dis-gpio: specific gpio for hardware reset.
- qcom,irq-gpio: specific gpio for read interrupt.
- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", "GPCLK2" ...)
- qcom,clk-en-gpio: msm gpio clock,used ony if clock source is msm gpio
- qcom,clk-src: nfc clock source ("BBCLK2", "RFCLK3", "GPCLK", "GPCLK2", ...)
- qcom,clk-src-gpio: msm gpio clock,used ony if clock source is msm gpio
- qcom,clk-req-gpio: clk-req input gpio for MSM based clocks.
                     not used for pmic implementation
- vlogic-supply: LDO for power supply
- interrupt-parent: Should be phandle for the interrupt controller
                    that services interrupts for this device.
- interrupts: should contain the NFC interrupt. NFC has one read interrupt.
- qcom,clk-gpio: pmic gpio on which bbclk2 signal is coming.
- interrupts: Nfc read interrupt,gpio-clk-req interrupt
- qcom,clk-gpio: pmic or msm gpio on which bbclk2 signal is coming.

LDO example:

@@ -24,8 +26,8 @@ LDO example:
			reg = <0x0e>;
			qcom,irq-gpio = <&msmgpio 77 0x00>;
			qcom,dis-gpio = <&msmgpio 93 0x00>;
			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
			qcom,clk-src = "GPCLK";
			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
			qcom,clk-src = "GPCLK2";
			interrupt-parent = <&msmgpio>;
			interrupts = <77 0>;
			qcom,clk-gpio = <&msmgpio 75 0x00>;
+3 −2
Original line number Diff line number Diff line
@@ -151,10 +151,11 @@
			reg = <0x0e>;
			qcom,irq-gpio = <&msmgpio 77 0x00>;
			qcom,dis-gpio = <&msmgpio 93 0x00>;
			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
			qcom,clk-req-gpio = <&msmgpio 75 0x00>;
			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
			qcom,clk-src = "GPCLK";
			interrupt-parent = <&msmgpio>;
			interrupts = <77 0>;
			interrupts = <77 75 0>;
			qcom,clk-gpio = <&pm8110_gpios 1 0>;
		};
	};
+6 −6
Original line number Diff line number Diff line
/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2014, The Linux Foundation. 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 version 2 and
@@ -28,18 +28,18 @@
        qcom,ext-spk-amp-gpio = <&msmgpio 92 0x0>;
    };

	i2c@f9925000 { /* BLSP-1 QUP-3 */
	i2c@f9924000 { /* BLSP-1 QUP-2 */
		nfc-nci@e {
			compatible = "qcom,nfc-nci";
			reg = <0x0e>;
			qcom,irq-gpio = <&msmgpio 77 0x00>;
			qcom,clk-req-gpio = <&msmgpio 75 0x00>;
			qcom,dis-gpio = <&msmgpio 93 0x00>;
			qcom,clk-en-gpio = <&msmgpio 78 0x00>;
			qcom,clk-src = "GPCLK";
			qcom,clk-src-gpio = <&msmgpio 78 0x00>;
			qcom,clk-src = "GPCLK2";
			interrupt-parent = <&msmgpio>;
			interrupts = <77 0>;
			interrupts = <77 75 0>;
			qcom,clk-gpio = <&msmgpio 75 0x00>;
			vlogic-supply = <&pm8110_l14>;
		};
	};
};
+7 −0
Original line number Diff line number Diff line
@@ -613,6 +613,13 @@ static struct gpiomux_setting interrupt_gpio_suspend_pulldown = {
};

static struct msm_gpiomux_config msm_interrupt_configs[] __initdata = {
	{
		.gpio = 75,	/* NFC_CLK_REQ_IRQ*/
		.settings = {
			[GPIOMUX_ACTIVE]    = &interrupt_gpio_active,
			[GPIOMUX_SUSPENDED] = &interrupt_gpio_suspend_pullup,
		},
	},
	{
		.gpio = 77,	/* NFC_IRQ */
		.settings = {
+262 −52
Original line number Diff line number Diff line
@@ -31,8 +31,10 @@

struct qca199x_platform_data {
	unsigned int irq_gpio;
	unsigned int	irq_gpio_clk_req;
	unsigned int	clk_req_irq_num;
	unsigned int dis_gpio;
	unsigned int ven_gpio;
	unsigned int clkreq_gpio;
	unsigned int reg;
	const char *clk_src_name;
	unsigned int clk_src_gpio;
@@ -58,24 +60,38 @@ MODULE_DEVICE_TABLE(of, msm_match_table);
#define	CORE_RESET_OID			(0x00)
#define CORE_RST_NTF_LENGTH		(0x02)

static void clk_req_update(struct work_struct *work);

struct qca199x_dev {
	wait_queue_head_t read_wq;
	struct	mutex		read_mutex;
	struct	i2c_client	*client;
	struct	miscdevice	qca199x_device;
	/* NFC_IRQ new NCI data available */
	unsigned int		irq_gpio;
	/* CLK_REQ IRQ to signal the state has changed */
	unsigned int		irq_gpio_clk_req;
	/* Actual IRQ no. assigned to CLK_REQ */
	unsigned int		clk_req_irq_num;
	unsigned int		dis_gpio;
	unsigned int ven_gpio;
	unsigned int		clkreq_gpio;
	/* NFC_IRQ state */
	bool			irq_enabled;
	bool			sent_first_nci_write;
	spinlock_t		irq_enabled_lock;
	unsigned int		count_irq;
	/* CLK_REQ IRQ state */
	bool			irq_enabled_clk_req;
	spinlock_t		irq_enabled_lock_clk_req;
	unsigned int		count_irq_clk_req;
	enum	nfcc_state	state;
	/* CLK control */
	unsigned int		clk_src_gpio;
	const	char		*clk_src_name;
	struct	clk		*s_clk;
	bool			clk_run;
	struct work_struct	msm_clock_controll_work;
	struct workqueue_struct *my_wq;
};

static int nfc_i2c_write(struct i2c_client *client, u8 *buf, int len);
@@ -97,6 +113,7 @@ static struct devicemode device_mode;
static int					ftm_raw_write_mode;
static int					ftm_werr_code;


unsigned int	disable_ctrl;

static void qca199x_init_stat(struct qca199x_dev *qca199x_dev)
@@ -159,6 +176,95 @@ static unsigned int nfc_poll(struct file *filp, poll_table *wait)
	return mask;
}

/* Handlers for CLK_REQ */
static void qca199x_disable_irq_clk_req(struct qca199x_dev *qca199x_dev)
{
	unsigned long flags;

	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
	if (qca199x_dev->irq_enabled_clk_req) {
		disable_irq_nosync(qca199x_dev->clk_req_irq_num);
		qca199x_dev->irq_enabled_clk_req = false;
	}
	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);
}


static void qca199x_enable_irq_clk_req(struct qca199x_dev *qca199x_dev)
{
	unsigned long flags;

	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
	if (!qca199x_dev->irq_enabled_clk_req) {
		qca199x_dev->irq_enabled_clk_req = true;
		enable_irq(qca199x_dev->clk_req_irq_num);
	}
	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);
}


static irqreturn_t qca199x_dev_irq_handler_clk_req(int irq, void *dev_id)
{
	struct qca199x_dev *qca199x_dev = dev_id;
	unsigned long flags;

	spin_lock_irqsave(&qca199x_dev->irq_enabled_lock_clk_req, flags);
	qca199x_dev->count_irq_clk_req++;
	spin_unlock_irqrestore(&qca199x_dev->irq_enabled_lock_clk_req, flags);

	queue_work(qca199x_dev->my_wq, &qca199x_dev->msm_clock_controll_work);

	return IRQ_HANDLED;
}


static struct gpiomux_setting nfc_clk_on = {
	.func = GPIOMUX_FUNC_2,
	.drv  = GPIOMUX_DRV_2MA,
	.pull = GPIOMUX_PULL_NONE,
};
static struct gpiomux_setting nfc_clk_on_suspend = {
	.func = GPIOMUX_FUNC_2,
	.drv  = GPIOMUX_DRV_2MA,
	.pull = GPIOMUX_PULL_DOWN,
};
static struct gpiomux_setting nfc_clk_off = {
	.func = GPIOMUX_FUNC_GPIO,
	.drv  = GPIOMUX_DRV_2MA,
	.pull = GPIOMUX_PULL_DOWN,
};

static void clk_req_update(struct work_struct *work)
{
	struct	i2c_client *client;
	struct	qca199x_dev *qca199x_dev;
	int		gpio_clk_req_level = 0;

	qca199x_dev =	container_of(work, struct qca199x_dev,
			msm_clock_controll_work);
	client =	qca199x_dev->client;

	/* Read status level of CLK_REQ from NFC Controller, QCA199_x */
	gpio_clk_req_level = gpio_get_value(qca199x_dev->irq_gpio_clk_req);
	if (gpio_clk_req_level == 1) {
		if (qca199x_dev->clk_run == false) {
			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
				GPIOMUX_ACTIVE, &nfc_clk_on, NULL);
			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
				GPIOMUX_SUSPENDED, &nfc_clk_on_suspend, NULL);
			qca199x_dev->clk_run = true;
			}
	} else{
		if (qca199x_dev->clk_run == true) {
			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
				GPIOMUX_ACTIVE, &nfc_clk_off, NULL);
			msm_gpiomux_write(qca199x_dev->clk_src_gpio,
				GPIOMUX_SUSPENDED, &nfc_clk_off, NULL);
			qca199x_dev->clk_run = false;
		}
	}
}

/*
 * ONLY for FTM-RAW-I2C Mode
 * Required to instigate a read, which comes from DT layer. This means we need
@@ -399,7 +505,14 @@ static int nfc_open(struct inode *inode, struct file *filp)

	filp->private_data = qca199x_dev;
	qca199x_init_stat(qca199x_dev);
	/* Enable interrupts from NFCC NFC_INT new NCI data available */
	qca199x_enable_irq(qca199x_dev);

	if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) ||
		(!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) {
		/* Enable interrupts from NFCC CLK_REQ */
		qca199x_enable_irq_clk_req(qca199x_dev);
	}
	dev_dbg(&qca199x_dev->client->dev,
			"%d,%d\n", imajor(inode), iminor(inode));
	return ret;
@@ -1006,10 +1119,6 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata)
	if (r)
		return -EINVAL;

	r = of_property_read_u32(np, "qcom,clk-gpio", &pdata->ven_gpio);
	if (r)
		return -EINVAL;

	pdata->dis_gpio = of_get_named_gpio(np, "qcom,dis-gpio", 0);
	if ((!gpio_is_valid(pdata->dis_gpio)))
		return -EINVAL;
@@ -1021,11 +1130,24 @@ static int nfc_parse_dt(struct device *dev, struct qca199x_platform_data *pdata)

	r = of_property_read_string(np, "qcom,clk-src", &pdata->clk_src_name);

	if (strcmp(pdata->clk_src_name, "GPCLK2")) {
		r = of_property_read_u32(np, "qcom,clk-gpio",
					&pdata->clkreq_gpio);
		if (r)
			return -EINVAL;
	}

	if ((!strcmp(pdata->clk_src_name, "GPCLK")) ||
	    (!strcmp(pdata->clk_src_name, "GPCLK2")))
	    (!strcmp(pdata->clk_src_name, "GPCLK2"))) {
			pdata->clk_src_gpio = of_get_named_gpio(np,
				"qcom,clk-en-gpio", 0);

					"qcom,clk-src-gpio", 0);
			if ((!gpio_is_valid(pdata->clk_src_gpio)))
				return -EINVAL;
			pdata->irq_gpio_clk_req = of_get_named_gpio(np,
					"qcom,clk-req-gpio", 0);
			if ((!gpio_is_valid(pdata->irq_gpio_clk_req)))
				return -EINVAL;
	}
	if (r)
		return -EINVAL;
	return r;
@@ -1089,7 +1211,6 @@ static int qca199x_probe(struct i2c_client *client,
				platform_data->irq_gpio);
			goto err_irq;
		}
		gpio_to_irq(0);
		irqn = gpio_to_irq(platform_data->irq_gpio);
		if (irqn < 0) {
			r = irqn;
@@ -1101,13 +1222,45 @@ static int qca199x_probe(struct i2c_client *client,
		dev_err(&client->dev, "irq gpio not provided\n");
		goto err_free_dev;
	}
	/* Interrupt from NFCC CLK_REQ to handle REF_CLK
		o/p gating/selection */
	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
		if (gpio_is_valid(platform_data->irq_gpio_clk_req)) {
			r = gpio_request(platform_data->irq_gpio_clk_req,
				"nfc_irq_gpio_clk_en");
			if (r) {
				dev_err(&client->dev, "unable to request CLK_EN gpio [%d]\n",
					platform_data->irq_gpio_clk_req);
				goto err_irq;
			}
			r = gpio_direction_input(
					platform_data->irq_gpio_clk_req);
			if (r) {
				dev_err(&client->dev,
					"unable to set direction for CLK_EN gpio [%d]\n",
					platform_data->irq_gpio_clk_req);
				goto err_irq_clk;
			}
			gpio_to_irq(0);
			irqn = gpio_to_irq(platform_data->irq_gpio_clk_req);
			if (irqn < 0) {
				r = irqn;
				goto err_irq_clk;
			}
			platform_data->clk_req_irq_num = irqn;
		} else {
			dev_err(&client->dev, "irq CLK_EN gpio not provided\n");
			goto err_irq;
		}
	}
	if (gpio_is_valid(platform_data->dis_gpio)) {
		r = gpio_request(platform_data->dis_gpio, "nfc_reset_gpio");
		if (r) {
			dev_err(&client->dev,
			"NFC: unable to request gpio [%d]\n",
				platform_data->dis_gpio);
			goto err_irq;
			goto err_irq_clk;
		}
		r = gpio_direction_output(platform_data->dis_gpio, 1);
		if (r) {
@@ -1118,7 +1271,7 @@ static int qca199x_probe(struct i2c_client *client,
		}
	} else {
		dev_err(&client->dev, "dis gpio not provided\n");
		goto err_irq;
		goto err_irq_clk;
	}
	/* Get the clock source name and gpio from from Device Tree */
	qca199x_dev->clk_src_name = platform_data->clk_src_name;
@@ -1131,35 +1284,47 @@ static int qca199x_probe(struct i2c_client *client,
		else
			goto err_dis_gpio;
	}
	platform_data->ven_gpio = of_get_named_gpio(node,
						"qcom,clk-gpio", 0);

	if (gpio_is_valid(platform_data->ven_gpio)) {
		r = gpio_request(platform_data->ven_gpio, "nfc_ven_gpio");
	if (strcmp(platform_data->clk_src_name, "GPCLK2")) {
		platform_data->clkreq_gpio =
			of_get_named_gpio(node, "qcom,clk-gpio", 0);

		if (gpio_is_valid(platform_data->clkreq_gpio)) {
			r = gpio_request(platform_data->clkreq_gpio,
				"nfc_clkreq_gpio");
			if (r) {
				dev_err(&client->dev, "unable to request gpio [%d]\n",
						platform_data->ven_gpio);
			goto err_ven_gpio;
						platform_data->clkreq_gpio);
				goto err_clkreq_gpio;
			}
		r = gpio_direction_input(platform_data->ven_gpio);
			r = gpio_direction_input(platform_data->clkreq_gpio);
			if (r) {
				dev_err(&client->dev,
						"unable to set direction for gpio [%d]\n",
						platform_data->ven_gpio);
			goto err_ven_gpio;
						platform_data->clkreq_gpio);
				goto err_clkreq_gpio;
			}
		} else {
		dev_err(&client->dev, "ven gpio not provided\n");
			dev_err(&client->dev, "clkreq gpio not provided\n");
			goto err_clk;
		}
		qca199x_dev->clkreq_gpio = platform_data->clkreq_gpio;
	}
	qca199x_dev->dis_gpio = platform_data->dis_gpio;
	qca199x_dev->irq_gpio = platform_data->irq_gpio;
	qca199x_dev->ven_gpio = platform_data->ven_gpio;
	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
			qca199x_dev->irq_gpio_clk_req	=
						platform_data->irq_gpio_clk_req;
			qca199x_dev->clk_req_irq_num		=
						platform_data->clk_req_irq_num;
	}

	/* init mutex and queues */
	init_waitqueue_head(&qca199x_dev->read_wq);
	mutex_init(&qca199x_dev->read_mutex);
	spin_lock_init(&qca199x_dev->irq_enabled_lock);
	spin_lock_init(&qca199x_dev->irq_enabled_lock_clk_req);

	qca199x_dev->qca199x_device.minor = MISC_DYNAMIC_MINOR;
	qca199x_dev->qca199x_device.name = "nfc-nci";
@@ -1189,6 +1354,7 @@ static int qca199x_probe(struct i2c_client *client,
	* for reading.  It is cleared when all data has been read.
	*/
	device_mode.handle_flavour = UNSOLICITED_MODE;
	/* NFC_INT IRQ */
	qca199x_dev->irq_enabled = true;
	r = request_irq(client->irq, qca199x_dev_irq_handler,
			  IRQF_TRIGGER_RISING, client->name, qca199x_dev);
@@ -1197,6 +1363,31 @@ static int qca199x_probe(struct i2c_client *client,
		goto err_request_irq_failed;
	}
	qca199x_disable_irq(qca199x_dev);
	/* CLK_REQ IRQ */
	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
		r = request_irq(qca199x_dev->clk_req_irq_num,
				qca199x_dev_irq_handler_clk_req,
				(IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING),
						client->name, qca199x_dev);
		if (r) {
			dev_err(&client->dev,
			"nfc-nci probe: request_irq failed. irq no = %d\n, main irq =  %d",
				qca199x_dev->clk_req_irq_num, client->irq);
			goto err_request_irq_failed;
		}
		qca199x_dev->irq_enabled_clk_req = true;
		qca199x_disable_irq_clk_req(qca199x_dev);


		qca199x_dev->my_wq =
			create_singlethread_workqueue("qca1990x_CLK_REQ_queue");
		if (!qca199x_dev->my_wq)
			goto err_create_workq;

		INIT_WORK(&qca199x_dev->msm_clock_controll_work,
			clk_req_update);
	}
	i2c_set_clientdata(client, qca199x_dev);
	gpio_set_value(platform_data->dis_gpio, 1);
	dev_dbg(&client->dev,
@@ -1204,12 +1395,18 @@ static int qca199x_probe(struct i2c_client *client,
		 __func__);
	return 0;

err_create_workq:
	dev_err(&client->dev,
	"nfc-nci probe: %s, work_queue creation failure\n",
		 __func__);
	free_irq(client->irq, qca199x_dev);
err_request_irq_failed:
	misc_deregister(&qca199x_dev->qca199x_device);
err_misc_register:
	mutex_destroy(&qca199x_dev->read_mutex);
err_ven_gpio:
	gpio_free(platform_data->ven_gpio);
err_clkreq_gpio:
	if (strcmp(platform_data->clk_src_name, "GPCLK2"))
		gpio_free(platform_data->clkreq_gpio);
err_clk:
		qca199x_clock_deselect(qca199x_dev);
err_dis_gpio:
@@ -1224,6 +1421,14 @@ err_dis_gpio:
		gpio_free(platform_data->clk_src_gpio);
	}
	gpio_free(platform_data->dis_gpio);
err_irq_clk:
	if ((!strcmp(platform_data->clk_src_name, "GPCLK")) ||
		(!strcmp(platform_data->clk_src_name, "GPCLK2"))) {
		r = gpio_direction_input(platform_data->irq_gpio_clk_req);
		if (r)
			dev_err(&client->dev, "nfc-nci probe: Unable to set direction\n");
		gpio_free(platform_data->irq_gpio_clk_req);
	}
err_irq:
	gpio_free(platform_data->irq_gpio);
err_free_dev:
@@ -1240,8 +1445,13 @@ static int qca199x_remove(struct i2c_client *client)
	misc_deregister(&qca199x_dev->qca199x_device);
	mutex_destroy(&qca199x_dev->read_mutex);
	gpio_free(qca199x_dev->irq_gpio);
	if ((!strcmp(qca199x_dev->clk_src_name, "GPCLK")) ||
		(!strcmp(qca199x_dev->clk_src_name, "GPCLK2"))) {
		gpio_free(qca199x_dev->irq_gpio_clk_req);
	}
	gpio_free(qca199x_dev->dis_gpio);
	gpio_free(qca199x_dev->ven_gpio);
	if (strcmp(qca199x_dev->clk_src_name, "GPCLK2"))
		gpio_free(qca199x_dev->clkreq_gpio);
	kfree(qca199x_dev);

	return 0;