mfd: da9052-core: Use regmap_irq_get_virq() and fix the probe
RFC 1/3 mfd: da9052-core: Use regmap_irq_get_virq() and fix the probe
From: Fabio Estevam <[email protected]>
On a mx53qsb dt-kernel the da9052-core driver fails to probe as follows:
da9052 1-0048: DA9052 ADC IRQ failed ret=-22
The reason for the error was due to passing only the offset as the interrupt number in request_threaded_irq().
The recommended approach though is to use regmap_get_virq() to acquire the interrupt number.
Fix it and allow the driver to probe successfully.
Also provide a few more error logs and change the irq string to "adc-irq", so that it appears as a single word in 'cat /proc/inte
--- drivers/mfd/da9052-core.c | 89 ++++++++++++++++++++++++++++++------- include/linux/mfd/da9052/da9052.h | 1 + 2 files changed, 74 insertions(+), 16 deletions(-)
drivers/mfd/da9052-core.c +73 -16
@@ -16,6 +16,7 @@#include <linux/input.h> #include <linux/interrupt.h> #include <linux/irq.h> +#include <linux/irqdomain.h> #include <linux/mfd/core.h> #include <linux/slab.h> #include <linux/module.h>
@@ -364,6 +365,52 @@ static const int32_t tbat_lookup[255] = {-11823 ,-11903 ,-11982 }; +static void da9052_irq_enable (struct irq_data *data) +{ +} + +static void da9052_irq_disable (struct irq_data *data) +{ +} + +static struct irq_chip da9052_irq_chip = { + .name ="da9052" , + .irq_disable = da9052_irq_disable, + .irq_enable = da9052_irq_enable, +}; + +static int da9052_irq_map (struct irq_domain *h,unsigned int virq, +irq_hw_number_t hw) +{ +struct regmap_irq_chip_data *data = h->host_data; + +irq_set_chip_data (virq, data); +irq_set_chip_and_handler (virq, &da9052_irq_chip, handle_edge_irq); +irq_set_nested_thread (virq,1 ); + +/* +* ARM needs us to explicitly flag the IRQ as valid +* and will set them noprobe when we do so. +*/ +#ifdef CONFIG_ARM +set_irq_flags (virq,IRQF_VALID ); +#else +irq_set_noprobe (virq); +#endif + +return 0 ; +} + +static struct irq_domain_ops da9052_domain_ops = { + .map = da9052_irq_map, + .xlate = irq_domain_xlate_twocell, +}; + +static int da9052_map_irq (struct da9052 *da9052,int irq) +{ +return regmap_irq_get_virq (da9052->irq_data, irq); +} +static const u8 chan_mux[DA9052_ADC_VBBAT +1 ] = { [DA9052_ADC_VDDOUT ] =DA9052_ADC_MAN_MUXSEL_VDDOUT , [DA9052_ADC_ICH] = DA9052_ADC_MAN_MUXSEL_ICH,
@@ -772,7 +819,7 @@ EXPORT_SYMBOL_GPL(da9052_regmap_config);int __devinit da9052_device_init (struct da9052 *da9052,u8 chip_id) {struct da9052_pdata *pdata = da9052->dev->platform_data; -int ret; +int ret, i;mutex_init (&da9052->auxadc_lock);init_completion (&da9052->done);
@@ -782,35 +829,44 @@ int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) da9052->chip_id = chip_id; -if (!pdata || !pdata->irq_base) - da9052->irq_base =-1 ; -else - da9052->irq_base = pdata->irq_base; +/* Allocate a virtual IRQ domain to distribute to the regmap domains */ + da9052->virq =irq_domain_add_linear (NULL ,ARRAY_SIZE (da9052_irqs), + &da9052_domain_ops, da9052); +if (!da9052->virq) { + ret = -EINVAL ; + goto regmap_err; + } - ret =regmap_add_irq_chip (da9052->regmap, da9052->chip_irq, + ret =regmap_add_irq_chip (da9052->regmap, +irq_create_mapping (da9052->virq,0 ),IRQF_TRIGGER_LOW |IRQF_ONESHOT , - da9052->irq_base, &da9052_regmap_irq_chip, +-1 , &da9052_regmap_irq_chip, &da9052->irq_data); -if (ret <0 ) +if (ret <0 ) { +dev_err (da9052->dev,"regmap_add_irq_chip failed: %d\n" , ret); goto regmap_err; + } - da9052->irq_base =regmap_irq_chip_get_base (da9052->irq_data); - - ret =request_threaded_irq (DA9052_IRQ_ADC_EOM ,NULL , da9052_auxadc_irq, + i =da9052_map_irq (da9052,DA9052_IRQ_ADC_EOM ); + ret =request_threaded_irq (i,NULL , da9052_auxadc_irq,IRQF_TRIGGER_LOW |IRQF_ONESHOT , -"adc irq" , da9052); +"adc-irq" , da9052);if (ret !=0 )dev_err (da9052->dev,"DA9052 ADC IRQ failed ret=%d\n" , ret); ret =mfd_add_devices (da9052->dev,-1 , da9052_subdev_info,ARRAY_SIZE (da9052_subdev_info),NULL ,0 ,NULL ); -if (ret) +if (ret) { +dev_err (da9052->dev,"mfd_add_devices failed: %d\n" , ret); goto err; + }return 0 ; err: -free_irq (DA9052_IRQ_ADC_EOM , da9052); +free_irq (da9052_map_irq (da9052,DA9052_IRQ_ADC_EOM ), da9052); +regmap_del_irq_chip (irq_create_mapping (da9052->virq,0 ), + da9052->irq_data);mfd_remove_devices (da9052->dev); regmap_err:return ret;
@@ -818,8 +874,9 @@ regmap_err:void da9052_device_exit (struct da9052 *da9052) { -free_irq (DA9052_IRQ_ADC_EOM , da9052); -regmap_del_irq_chip (da9052->chip_irq, da9052->irq_data); +free_irq (da9052_map_irq (da9052,DA9052_IRQ_ADC_EOM ), da9052); +regmap_del_irq_chip (irq_create_mapping (da9052->virq,0 ), + da9052->irq_data);mfd_remove_devices (da9052->dev); }
include/linux/mfd/da9052/da9052.h +1 -0
@@ -99,6 +99,7 @@ struct da9052 {u8 chip_id;int chip_irq; +struct irq_domain *virq; };/* ADC API */
Signature · 1 line
1.7.9.5
RFC 2/3 mfd: da9052: Introduce da9052-irq.c
Create a da9052-irq.c file so that it can handle interrupt related operations.
--- drivers/mfd/Makefile | 1 + drivers/mfd/da9052-core.c | 323 +------------------------------------ drivers/mfd/da9052-irq.c | 304 ++++++++++++++++++++++++++++++++++ include/linux/mfd/da9052/da9052.h | 6 + 4 files changed, 319 insertions(+), 315 deletions(-) create mode 100644 drivers/mfd/da9052-irq.c
drivers/mfd/Makefile +1 -0
@@ -85,6 +85,7 @@ obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o obj-$(CONFIG_PMIC_DA903X) += da903x.o +obj-$(CONFIG_PMIC_DA9052) += da9052-irq.o obj-$(CONFIG_PMIC_DA9052) += da9052-core.o obj-$(CONFIG_MFD_DA9052_SPI) += da9052-spi.o obj-$(CONFIG_MFD_DA9052_I2C) += da9052-i2c.o
drivers/mfd/da9052-core.c +8 -315
403 lines not on this page · raw message
drivers/mfd/da9052-irq.c new file +304 -0
304 lines not on this page · raw message
include/linux/mfd/da9052/da9052.h +6 -0
@@ -147,4 +147,10 @@ void da9052_device_exit(struct da9052 *da9052);extern struct regmap_config da9052_regmap_config; +int da9052_irq_init (struct da9052 *da9052); +int da9052_irq_exit (struct da9052 *da9052); +int da9052_request_irq (struct da9052 *da9052,int irq,char *name, +irq_handler_t handler,void *data); +void da9052_free_irq (struct da9052 *da9052,int irq,void *data); +#endif /* __MFD_DA9052_DA9052_H */
Signature · 1 line
1.7.9.5
RFC 3/3 Input: da9052_tsi.c: Use the new da9052 irq functions
In reply to Fabio EstevamFrom: Fabio Estevam <[email protected]>
Currently da9062_tsi does not probe and it fails as follows:
da9052 1-0048: Unable to determine device interrupts
Use the new da9052 irq functions and allow the driver to probe successfully.
---
Hi,
Even though I can get the da9052_tsi driver to probe succesffully on a mx53qsb, I still do not get any interrupts when touching the LCD when using "evtest".
This is why I marked the series as RFC.
Ashish,
I never used this driver before, so I do not know if it has ever worked.
Please let me know if you have suggestions to make this drive functional.
drivers/input/touchscreen/da9052_tsi.c | 60 +++++++++++--------------------- drivers/mfd/da9052-irq.c | 38 +++++++++++++++++++- include/linux/mfd/da9052/da9052.h | 4 +++ 3 files changed, 62 insertions(+), 40 deletions(-)
drivers/input/touchscreen/da9052_tsi.c +21 -39
@@ -27,8 +27,6 @@ struct da9052_tsi {struct input_dev *dev;struct delayed_work ts_pen_work;struct mutex mutex; -unsigned int irq_pendwn; -unsigned int irq_datardy;bool stopped;bool adc_on; };
@@ -45,8 +43,8 @@ static irqreturn_t da9052_ts_pendwn_irq(int irq, void *data)if (!tsi->stopped) {/* Mask PEN_DOWN event and unmask TSI_READY event */ -disable_irq_nosync (tsi->irq_pendwn); -enable_irq (tsi->irq_datardy); +da9052_disable_irq_nosync (tsi->da9052,DA9052_IRQ_PENDOWN ); +da9052_enable_irq (tsi->da9052,DA9052_IRQ_TSIREADY );da9052_ts_adc_toggle (tsi, true);
@@ -137,8 +135,8 @@ static void da9052_ts_pen_work(struct work_struct *work)return ;/* Mask TSI_READY event and unmask PEN_DOWN event */ -disable_irq (tsi->irq_datardy); -enable_irq (tsi->irq_pendwn); +da9052_disable_irq (tsi->da9052,DA9052_IRQ_TSIREADY ); +da9052_enable_irq (tsi->da9052,DA9052_IRQ_PENDOWN ); } } }
@@ -197,7 +195,7 @@ static int da9052_ts_input_open(struct input_dev *input_dev)mb ();/* Unmask PEN_DOWN event */ -enable_irq (tsi->irq_pendwn); +da9052_enable_irq (tsi->da9052,DA9052_IRQ_PENDOWN );/* Enable Pen Detect Circuit */ return da9052_reg_update(tsi->da9052, DA9052_TSI_CONT_A_REG,
@@ -210,11 +208,11 @@ static void da9052_ts_input_close(struct input_dev *input_dev) tsi->stopped = true;mb (); -disable_irq (tsi->irq_pendwn); +da9052_disable_irq (tsi->da9052,DA9052_IRQ_PENDOWN );cancel_delayed_work_sync (&tsi->ts_pen_work);if (tsi->adc_on) { -disable_irq (tsi->irq_datardy); +da9052_disable_irq (tsi->da9052,DA9052_IRQ_TSIREADY );da9052_ts_adc_toggle (tsi, false);/*
@@ -222,7 +220,7 @@ static void da9052_ts_input_close(struct input_dev *input_dev)* twice and we need to enable it to keep enable/disable * counter balanced. IRQ is still off though. */ -enable_irq (tsi->irq_pendwn); +da9052_enable_irq (tsi->da9052,DA9052_IRQ_PENDOWN ); }/* Disable Pen Detect Circuit */
@@ -234,21 +232,12 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev)struct da9052 *da9052;struct da9052_tsi *tsi;struct input_dev *input_dev; -int irq_pendwn; -int irq_datardy;int error; da9052 =dev_get_drvdata (pdev->dev.parent);if (!da9052)return -EINVAL ; - irq_pendwn =platform_get_irq_byname (pdev,"PENDWN" ); - irq_datardy =platform_get_irq_byname (pdev,"TSIRDY" ); -if (irq_pendwn <0 || irq_datardy <0 ) { -dev_err (da9052->dev,"Unable to determine device interrupts\n" ); -return -ENXIO ; - } - tsi =kzalloc (sizeof (struct da9052_tsi ),GFP_KERNEL ); input_dev =input_allocate_device ();if (!tsi || !input_dev) {
@@ -258,8 +247,6 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev) tsi->da9052 = da9052; tsi->dev = input_dev; - tsi->irq_pendwn = da9052->irq_base + irq_pendwn; - tsi->irq_datardy = da9052->irq_base + irq_datardy; tsi->stopped = true;INIT_DELAYED_WORK (&tsi->ts_pen_work, da9052_ts_pen_work);
@@ -287,31 +274,25 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev)/* Disable ADC */ da9052_ts_adc_toggle (tsi, false); - error =request_threaded_irq (tsi->irq_pendwn, -NULL , da9052_ts_pendwn_irq, -IRQF_TRIGGER_LOW |IRQF_ONESHOT , -"PENDWN" , tsi); + error =da9052_request_irq (tsi->da9052,DA9052_IRQ_PENDOWN ,"pendown-irq" , + da9052_ts_pendwn_irq, da9052);if (error) {dev_err (tsi->da9052->dev, -"Failed to register PENDWN IRQ %d, error = %d\n" , - tsi->irq_pendwn, error); +"Failed to register PENDWN IRQ: %d\n" , error); goto err_free_mem; } - error =request_threaded_irq (tsi->irq_datardy, -NULL , da9052_ts_datardy_irq, -IRQF_TRIGGER_LOW |IRQF_ONESHOT , -"TSIRDY" , tsi); + error =da9052_request_irq (tsi->da9052,DA9052_IRQ_TSIREADY ,"tsiready-irq" , + da9052_ts_datardy_irq, da9052);if (error) {dev_err (tsi->da9052->dev, -"Failed to register TSIRDY IRQ %d, error = %d\n" , - tsi->irq_datardy, error); +"Failed to register TSIRDY IRQ :%d\n" , error); goto err_free_pendwn_irq; }/* Mask PEN_DOWN and TSI_READY events */ -disable_irq (tsi->irq_pendwn); -disable_irq (tsi->irq_datardy); +da9052_disable_irq (tsi->da9052,DA9052_IRQ_PENDOWN ); +da9052_disable_irq (tsi->da9052,DA9052_IRQ_TSIREADY ); error =da9052_configure_tsi (tsi);if (error)
@@ -326,9 +307,9 @@ static int __devinit da9052_ts_probe(struct platform_device *pdev)return 0 ; err_free_datardy_irq: -free_irq (tsi->irq_datardy, tsi); +da9052_free_irq (da9052,DA9052_IRQ_TSIREADY , da9052); err_free_pendwn_irq: -free_irq (tsi->irq_pendwn, tsi); +da9052_free_irq (da9052,DA9052_IRQ_PENDOWN , da9052); err_free_mem:kfree (tsi);input_free_device (input_dev);
@@ -339,11 +320,12 @@ err_free_mem: static int __devexit da9052_ts_remove(struct platform_device *pdev) {struct da9052_tsi *tsi =platform_get_drvdata (pdev); +struct da9052 *da9052 =dev_get_drvdata (pdev->dev.parent);da9052_reg_write (tsi->da9052,DA9052_LDO9_REG ,0x19 ); -free_irq (tsi->irq_pendwn, tsi); -free_irq (tsi->irq_datardy, tsi); +da9052_free_irq (da9052,DA9052_IRQ_TSIREADY , da9052); +da9052_free_irq (da9052,DA9052_IRQ_PENDOWN , da9052);input_unregister_device (tsi->dev);kfree (tsi);
drivers/mfd/da9052-irq.c +37 -1
@@ -196,7 +196,7 @@ static int da9052_irq_map(struct irq_domain *h, unsigned int virq,struct regmap_irq_chip_data *data = h->host_data;irq_set_chip_data (virq, data); -irq_set_chip_and_handler (virq, &da9052_irq_chip, handle_edge_irq); +irq_set_chip_and_handler (virq, &da9052_irq_chip, handle_level_irq);irq_set_nested_thread (virq,1 );/*
@@ -222,6 +222,42 @@ static int da9052_map_irq(struct da9052 *da9052, int irq)return regmap_irq_get_virq (da9052->irq_data, irq); } +int da9052_enable_irq (struct da9052 *da9052,int irq) +{ + irq =da9052_map_irq (da9052, irq); +if (irq <0 ) +return irq; + +enable_irq (irq); + +return 0 ; +} +EXPORT_SYMBOL_GPL (da9052_enable_irq); + +int da9052_disable_irq (struct da9052 *da9052,int irq) +{ + irq =da9052_map_irq (da9052, irq); +if (irq <0 ) +return irq; + +disable_irq (irq); + +return 0 ; +} +EXPORT_SYMBOL_GPL (da9052_disable_irq); + +int da9052_disable_irq_nosync (struct da9052 *da9052,int irq) +{ + irq =da9052_map_irq (da9052, irq); +if (irq <0 ) +return irq; + +disable_irq_nosync (irq); + +return 0 ; +} +EXPORT_SYMBOL_GPL (da9052_disable_irq_nosync); +int da9052_request_irq (struct da9052 *da9052,int irq,char *name,irq_handler_t handler,void *data) {
include/linux/mfd/da9052/da9052.h +4 -0
@@ -153,4 +153,8 @@ int da9052_request_irq(struct da9052 *da9052, int irq, char *name, irq_handler_t handler, void *data);void da9052_free_irq (struct da9052 *da9052,int irq,void *data); +int da9052_enable_irq (struct da9052 *da9052,int irq); +int da9052_disable_irq (struct da9052 *da9052,int irq); +int da9052_disable_irq_nosync (struct da9052 *da9052,int irq); +#endif /* __MFD_DA9052_DA9052_H */
Signature · 1 line
1.7.9.5
drivers/mfd/da9052-core.c int __devinit da9052_device_init(struct da9052 *da9052, u8 chip_id) · line 838
Quoted 7 lines · Fabio Estevam
drivers/mfd/da9052-core.c +7
-0+/* Allocate a virtual IRQ domain to distribute to the regmap domains */ + da9052->virq =irq_domain_add_linear (NULL ,ARRAY_SIZE (da9052_irqs), + &da9052_domain_ops, da9052); +if (!da9052->virq) { + ret = -EINVAL ; + goto regmap_err; + }
I still don't understand what on earth this is doing, as far as I can tell there's only one domain in the device so you're not distrubting anything between domains and there's as many interrupts in this domain as there are in the domain allocated by regmap which is even odder.
There doesn't seem to be anything about this driver that's unusual, why does it need this weird code?
Quoted 4 lines · Mark Brown
I still don't understand what on earth this is doing, as far as I can tell there's only one domain in the device so you're not distrubting anything between domains and there's as many interrupts in this domain as there are in the domain allocated by regmap which is even odder.
Thanks for your clarification, Mark. I fixed it and managed to get touchscreen to work now.
Will submit the patches shortly.
Thanks,
Fabio Estevam