Loading Documentation/devicetree/bindings/nfc/nfc-nci.txt +8 −6 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -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>; Loading arch/arm/boot/dts/qcom/msm8610-mtp.dtsi +3 −2 Original line number Diff line number Diff line Loading @@ -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>; }; }; Loading arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi +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 Loading Loading @@ -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>; }; }; }; Loading arch/arm/mach-msm/board-8610-gpiomux.c +7 −0 Original line number Diff line number Diff line Loading @@ -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 = { Loading drivers/nfc/nfc-nci.c +262 −52 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading @@ -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) Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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); Loading @@ -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, Loading @@ -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: Loading @@ -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: Loading @@ -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; Loading Loading
Documentation/devicetree/bindings/nfc/nfc-nci.txt +8 −6 Original line number Diff line number Diff line Loading @@ -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: Loading @@ -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>; Loading
arch/arm/boot/dts/qcom/msm8610-mtp.dtsi +3 −2 Original line number Diff line number Diff line Loading @@ -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>; }; }; Loading
arch/arm/boot/dts/qcom/msm8610-qrd-skuaa.dtsi +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 Loading Loading @@ -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>; }; }; }; Loading
arch/arm/mach-msm/board-8610-gpiomux.c +7 −0 Original line number Diff line number Diff line Loading @@ -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 = { Loading
drivers/nfc/nfc-nci.c +262 −52 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); Loading @@ -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) Loading Loading @@ -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 Loading Loading @@ -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; Loading Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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); Loading @@ -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, Loading @@ -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: Loading @@ -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: Loading @@ -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; Loading