diff options
| author | Sebastian Reichel <sre@debian.org> | 2014-03-15 21:43:26 -0400 |
|---|---|---|
| committer | Lee Jones <lee.jones@linaro.org> | 2014-03-18 04:13:23 -0400 |
| commit | 2f39b70fef194a54c9decd8687bb05d576afebe5 (patch) | |
| tree | a2a808796c150d93fbbb8c5f246bb7282d630670 | |
| parent | e7f22b75167d8b8a4d4c67d12b026a746aec05f6 (diff) | |
mfd: twl4030-madc: Add DT support and convert to IIO framework
This converts twl4030-madc module to use the Industrial IO ADC
framework and adds device tree support.
Signed-off-by: Sebastian Reichel <sre@debian.org>
Tested-by: Marek Belisko <marek@goldelico.com>
Acked-by: Jonathan Cameron <jic23@kernel.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
| -rw-r--r-- | drivers/mfd/twl4030-madc.c | 127 |
1 files changed, 116 insertions, 11 deletions
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c index 54585617ab51..93ef91229cd3 100644 --- a/drivers/mfd/twl4030-madc.c +++ b/drivers/mfd/twl4030-madc.c | |||
| @@ -47,11 +47,14 @@ | |||
| 47 | #include <linux/gfp.h> | 47 | #include <linux/gfp.h> |
| 48 | #include <linux/err.h> | 48 | #include <linux/err.h> |
| 49 | 49 | ||
| 50 | #include <linux/iio/iio.h> | ||
| 51 | |||
| 50 | /* | 52 | /* |
| 51 | * struct twl4030_madc_data - a container for madc info | 53 | * struct twl4030_madc_data - a container for madc info |
| 52 | * @dev - pointer to device structure for madc | 54 | * @dev - pointer to device structure for madc |
| 53 | * @lock - mutex protecting this data structure | 55 | * @lock - mutex protecting this data structure |
| 54 | * @requests - Array of request struct corresponding to SW1, SW2 and RT | 56 | * @requests - Array of request struct corresponding to SW1, SW2 and RT |
| 57 | * @use_second_irq - IRQ selection (main or co-processor) | ||
| 55 | * @imr - Interrupt mask register of MADC | 58 | * @imr - Interrupt mask register of MADC |
| 56 | * @isr - Interrupt status register of MADC | 59 | * @isr - Interrupt status register of MADC |
| 57 | */ | 60 | */ |
| @@ -59,10 +62,71 @@ struct twl4030_madc_data { | |||
| 59 | struct device *dev; | 62 | struct device *dev; |
| 60 | struct mutex lock; /* mutex protecting this data structure */ | 63 | struct mutex lock; /* mutex protecting this data structure */ |
| 61 | struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; | 64 | struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; |
| 65 | bool use_second_irq; | ||
| 62 | int imr; | 66 | int imr; |
| 63 | int isr; | 67 | int isr; |
| 64 | }; | 68 | }; |
| 65 | 69 | ||
| 70 | static int twl4030_madc_read(struct iio_dev *iio_dev, | ||
| 71 | const struct iio_chan_spec *chan, | ||
| 72 | int *val, int *val2, long mask) | ||
| 73 | { | ||
| 74 | struct twl4030_madc_data *madc = iio_priv(iio_dev); | ||
| 75 | struct twl4030_madc_request req; | ||
| 76 | int ret; | ||
| 77 | |||
| 78 | req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1; | ||
| 79 | |||
| 80 | req.channels = BIT(chan->channel); | ||
| 81 | req.active = false; | ||
| 82 | req.func_cb = NULL; | ||
| 83 | req.type = TWL4030_MADC_WAIT; | ||
| 84 | req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); | ||
| 85 | req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); | ||
| 86 | |||
| 87 | ret = twl4030_madc_conversion(&req); | ||
| 88 | if (ret < 0) | ||
| 89 | return ret; | ||
| 90 | |||
| 91 | *val = req.rbuf[chan->channel]; | ||
| 92 | |||
| 93 | return IIO_VAL_INT; | ||
| 94 | } | ||
| 95 | |||
| 96 | static const struct iio_info twl4030_madc_iio_info = { | ||
| 97 | .read_raw = &twl4030_madc_read, | ||
| 98 | .driver_module = THIS_MODULE, | ||
| 99 | }; | ||
| 100 | |||
| 101 | #define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \ | ||
| 102 | .type = _type, \ | ||
| 103 | .channel = _channel, \ | ||
| 104 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ | ||
| 105 | BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ | ||
| 106 | BIT(IIO_CHAN_INFO_PROCESSED), \ | ||
| 107 | .datasheet_name = _name, \ | ||
| 108 | .indexed = 1, \ | ||
| 109 | } | ||
| 110 | |||
| 111 | static const struct iio_chan_spec twl4030_madc_iio_channels[] = { | ||
| 112 | TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"), | ||
| 113 | TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"), | ||
| 114 | TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"), | ||
| 115 | TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"), | ||
| 116 | TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"), | ||
| 117 | TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"), | ||
| 118 | TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"), | ||
| 119 | TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"), | ||
| 120 | TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"), | ||
| 121 | TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"), | ||
| 122 | TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"), | ||
| 123 | TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"), | ||
| 124 | TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"), | ||
| 125 | TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"), | ||
| 126 | TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"), | ||
| 127 | TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"), | ||
| 128 | }; | ||
| 129 | |||
| 66 | static struct twl4030_madc_data *twl4030_madc; | 130 | static struct twl4030_madc_data *twl4030_madc; |
| 67 | 131 | ||
| 68 | struct twl4030_prescale_divider_ratios { | 132 | struct twl4030_prescale_divider_ratios { |
| @@ -702,28 +766,49 @@ static int twl4030_madc_probe(struct platform_device *pdev) | |||
| 702 | { | 766 | { |
| 703 | struct twl4030_madc_data *madc; | 767 | struct twl4030_madc_data *madc; |
| 704 | struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); | 768 | struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); |
| 769 | struct device_node *np = pdev->dev.of_node; | ||
| 705 | int irq, ret; | 770 | int irq, ret; |
| 706 | u8 regval; | 771 | u8 regval; |
| 772 | struct iio_dev *iio_dev = NULL; | ||
| 707 | 773 | ||
| 708 | if (!pdata) { | 774 | if (!pdata && !np) { |
| 709 | dev_err(&pdev->dev, "platform_data not available\n"); | 775 | dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n"); |
| 710 | return -EINVAL; | 776 | return -EINVAL; |
| 711 | } | 777 | } |
| 712 | madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL); | 778 | |
| 713 | if (!madc) | 779 | iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc)); |
| 780 | if (!iio_dev) { | ||
| 781 | dev_err(&pdev->dev, "failed allocating iio device\n"); | ||
| 714 | return -ENOMEM; | 782 | return -ENOMEM; |
| 783 | } | ||
| 715 | 784 | ||
| 785 | madc = iio_priv(iio_dev); | ||
| 716 | madc->dev = &pdev->dev; | 786 | madc->dev = &pdev->dev; |
| 717 | 787 | ||
| 788 | iio_dev->name = dev_name(&pdev->dev); | ||
| 789 | iio_dev->dev.parent = &pdev->dev; | ||
| 790 | iio_dev->dev.of_node = pdev->dev.of_node; | ||
| 791 | iio_dev->info = &twl4030_madc_iio_info; | ||
| 792 | iio_dev->modes = INDIO_DIRECT_MODE; | ||
| 793 | iio_dev->channels = twl4030_madc_iio_channels; | ||
| 794 | iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels); | ||
| 795 | |||
| 718 | /* | 796 | /* |
| 719 | * Phoenix provides 2 interrupt lines. The first one is connected to | 797 | * Phoenix provides 2 interrupt lines. The first one is connected to |
| 720 | * the OMAP. The other one can be connected to the other processor such | 798 | * the OMAP. The other one can be connected to the other processor such |
| 721 | * as modem. Hence two separate ISR and IMR registers. | 799 | * as modem. Hence two separate ISR and IMR registers. |
| 722 | */ | 800 | */ |
| 723 | madc->imr = (pdata->irq_line == 1) ? | 801 | if (pdata) |
| 724 | TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; | 802 | madc->use_second_irq = (pdata->irq_line != 1); |
| 725 | madc->isr = (pdata->irq_line == 1) ? | 803 | else |
| 726 | TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; | 804 | madc->use_second_irq = of_property_read_bool(np, |
| 805 | "ti,system-uses-second-madc-irq"); | ||
| 806 | |||
| 807 | madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 : | ||
| 808 | TWL4030_MADC_IMR1; | ||
| 809 | madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 : | ||
| 810 | TWL4030_MADC_ISR1; | ||
| 811 | |||
| 727 | ret = twl4030_madc_set_power(madc, 1); | 812 | ret = twl4030_madc_set_power(madc, 1); |
| 728 | if (ret < 0) | 813 | if (ret < 0) |
| 729 | return ret; | 814 | return ret; |
| @@ -768,7 +853,7 @@ static int twl4030_madc_probe(struct platform_device *pdev) | |||
| 768 | } | 853 | } |
| 769 | } | 854 | } |
| 770 | 855 | ||
| 771 | platform_set_drvdata(pdev, madc); | 856 | platform_set_drvdata(pdev, iio_dev); |
| 772 | mutex_init(&madc->lock); | 857 | mutex_init(&madc->lock); |
| 773 | 858 | ||
| 774 | irq = platform_get_irq(pdev, 0); | 859 | irq = platform_get_irq(pdev, 0); |
| @@ -776,11 +861,19 @@ static int twl4030_madc_probe(struct platform_device *pdev) | |||
| 776 | twl4030_madc_threaded_irq_handler, | 861 | twl4030_madc_threaded_irq_handler, |
| 777 | IRQF_TRIGGER_RISING, "twl4030_madc", madc); | 862 | IRQF_TRIGGER_RISING, "twl4030_madc", madc); |
| 778 | if (ret) { | 863 | if (ret) { |
| 779 | dev_dbg(&pdev->dev, "could not request irq\n"); | 864 | dev_err(&pdev->dev, "could not request irq\n"); |
| 780 | goto err_i2c; | 865 | goto err_i2c; |
| 781 | } | 866 | } |
| 782 | twl4030_madc = madc; | 867 | twl4030_madc = madc; |
| 868 | |||
| 869 | ret = iio_device_register(iio_dev); | ||
| 870 | if (ret) { | ||
| 871 | dev_err(&pdev->dev, "could not register iio device\n"); | ||
| 872 | goto err_i2c; | ||
| 873 | } | ||
| 874 | |||
