Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Sebastian Reichel and committed by
Lee Jones
2f39b70f e7f22b75

+117 -12
+117 -12
drivers/mfd/twl4030-madc.c
··· 47 47 #include <linux/gfp.h> 48 48 #include <linux/err.h> 49 49 50 + #include <linux/iio/iio.h> 51 + 50 52 /* 51 53 * struct twl4030_madc_data - a container for madc info 52 54 * @dev - pointer to device structure for madc 53 55 * @lock - mutex protecting this data structure 54 56 * @requests - Array of request struct corresponding to SW1, SW2 and RT 57 + * @use_second_irq - IRQ selection (main or co-processor) 55 58 * @imr - Interrupt mask register of MADC 56 59 * @isr - Interrupt status register of MADC 57 60 */ ··· 62 59 struct device *dev; 63 60 struct mutex lock; /* mutex protecting this data structure */ 64 61 struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS]; 62 + bool use_second_irq; 65 63 int imr; 66 64 int isr; 65 + }; 66 + 67 + static int twl4030_madc_read(struct iio_dev *iio_dev, 68 + const struct iio_chan_spec *chan, 69 + int *val, int *val2, long mask) 70 + { 71 + struct twl4030_madc_data *madc = iio_priv(iio_dev); 72 + struct twl4030_madc_request req; 73 + int ret; 74 + 75 + req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1; 76 + 77 + req.channels = BIT(chan->channel); 78 + req.active = false; 79 + req.func_cb = NULL; 80 + req.type = TWL4030_MADC_WAIT; 81 + req.raw = !(mask == IIO_CHAN_INFO_PROCESSED); 82 + req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW); 83 + 84 + ret = twl4030_madc_conversion(&req); 85 + if (ret < 0) 86 + return ret; 87 + 88 + *val = req.rbuf[chan->channel]; 89 + 90 + return IIO_VAL_INT; 91 + } 92 + 93 + static const struct iio_info twl4030_madc_iio_info = { 94 + .read_raw = &twl4030_madc_read, 95 + .driver_module = THIS_MODULE, 96 + }; 97 + 98 + #define TWL4030_ADC_CHANNEL(_channel, _type, _name) { \ 99 + .type = _type, \ 100 + .channel = _channel, \ 101 + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 102 + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ 103 + BIT(IIO_CHAN_INFO_PROCESSED), \ 104 + .datasheet_name = _name, \ 105 + .indexed = 1, \ 106 + } 107 + 108 + static const struct iio_chan_spec twl4030_madc_iio_channels[] = { 109 + TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"), 110 + TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"), 111 + TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"), 112 + TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"), 113 + TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"), 114 + TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"), 115 + TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"), 116 + TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"), 117 + TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"), 118 + TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"), 119 + TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"), 120 + TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"), 121 + TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"), 122 + TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"), 123 + TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"), 124 + TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"), 67 125 }; 68 126 69 127 static struct twl4030_madc_data *twl4030_madc; ··· 766 702 { 767 703 struct twl4030_madc_data *madc; 768 704 struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev); 705 + struct device_node *np = pdev->dev.of_node; 769 706 int irq, ret; 770 707 u8 regval; 708 + struct iio_dev *iio_dev = NULL; 771 709 772 - if (!pdata) { 773 - dev_err(&pdev->dev, "platform_data not available\n"); 710 + if (!pdata && !np) { 711 + dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n"); 774 712 return -EINVAL; 775 713 } 776 - madc = devm_kzalloc(&pdev->dev, sizeof(*madc), GFP_KERNEL); 777 - if (!madc) 778 - return -ENOMEM; 779 714 715 + iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc)); 716 + if (!iio_dev) { 717 + dev_err(&pdev->dev, "failed allocating iio device\n"); 718 + return -ENOMEM; 719 + } 720 + 721 + madc = iio_priv(iio_dev); 780 722 madc->dev = &pdev->dev; 723 + 724 + iio_dev->name = dev_name(&pdev->dev); 725 + iio_dev->dev.parent = &pdev->dev; 726 + iio_dev->dev.of_node = pdev->dev.of_node; 727 + iio_dev->info = &twl4030_madc_iio_info; 728 + iio_dev->modes = INDIO_DIRECT_MODE; 729 + iio_dev->channels = twl4030_madc_iio_channels; 730 + iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels); 781 731 782 732 /* 783 733 * Phoenix provides 2 interrupt lines. The first one is connected to 784 734 * the OMAP. The other one can be connected to the other processor such 785 735 * as modem. Hence two separate ISR and IMR registers. 786 736 */ 787 - madc->imr = (pdata->irq_line == 1) ? 788 - TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2; 789 - madc->isr = (pdata->irq_line == 1) ? 790 - TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2; 737 + if (pdata) 738 + madc->use_second_irq = (pdata->irq_line != 1); 739 + else 740 + madc->use_second_irq = of_property_read_bool(np, 741 + "ti,system-uses-second-madc-irq"); 742 + 743 + madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 : 744 + TWL4030_MADC_IMR1; 745 + madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 : 746 + TWL4030_MADC_ISR1; 747 + 791 748 ret = twl4030_madc_set_power(madc, 1); 792 749 if (ret < 0) 793 750 return ret; ··· 853 768 } 854 769 } 855 770 856 - platform_set_drvdata(pdev, madc); 771 + platform_set_drvdata(pdev, iio_dev); 857 772 mutex_init(&madc->lock); 858 773 859 774 irq = platform_get_irq(pdev, 0); ··· 861 776 twl4030_madc_threaded_irq_handler, 862 777 IRQF_TRIGGER_RISING, "twl4030_madc", madc); 863 778 if (ret) { 864 - dev_dbg(&pdev->dev, "could not request irq\n"); 779 + dev_err(&pdev->dev, "could not request irq\n"); 865 780 goto err_i2c; 866 781 } 867 782 twl4030_madc = madc; 783 + 784 + ret = iio_device_register(iio_dev); 785 + if (ret) { 786 + dev_err(&pdev->dev, "could not register iio device\n"); 787 + goto err_i2c; 788 + } 789 + 868 790 return 0; 791 + 869 792 err_i2c: 870 793 twl4030_madc_set_current_generator(madc, 0, 0); 871 794 err_current_generator: ··· 883 790 884 791 static int twl4030_madc_remove(struct platform_device *pdev) 885 792 { 886 - struct twl4030_madc_data *madc = platform_get_drvdata(pdev); 793 + struct iio_dev *iio_dev = platform_get_drvdata(pdev); 794 + struct twl4030_madc_data *madc = iio_priv(iio_dev); 795 + 796 + iio_device_unregister(iio_dev); 887 797 888 798 twl4030_madc_set_current_generator(madc, 0, 0); 889 799 twl4030_madc_set_power(madc, 0); ··· 894 798 return 0; 895 799 } 896 800 801 + #ifdef CONFIG_OF 802 + static const struct of_device_id twl_madc_of_match[] = { 803 + { .compatible = "ti,twl4030-madc", }, 804 + { }, 805 + }; 806 + MODULE_DEVICE_TABLE(of, twl_madc_of_match); 807 + #endif 808 + 897 809 static struct platform_driver twl4030_madc_driver = { 898 810 .probe = twl4030_madc_probe, 899 811 .remove = twl4030_madc_remove, 900 812 .driver = { 901 813 .name = "twl4030_madc", 902 814 .owner = THIS_MODULE, 815 + .of_match_table = of_match_ptr(twl_madc_of_match), 903 816 }, 904 817 }; 905 818