All of lore.kernel.org
 help / color / mirror / Atom feed
From: Grygorii Strashko <grygorii.strashko@ti.com>
To: Lars-Peter Clausen <lars@metafoo.de>
Cc: Oleksandr Kozaruk <oleksandr.kozaruk@ti.com>, <tony@atomide.com>,
	<benoit.cousson@linaro.org>, <rnayak@ti.com>,
	<peter.ujfalusi@ti.com>, <kishon@ti.com>, <jic23@cam.ac.uk>,
	<grant.likely@linaro.org>, <rob.herring@calxeda.com>,
	<sameo@linux.intel.com>, <ch.naveen@samsung.com>,
	<poeschel@lemonage.de>, <milo.kim@ti.com>, <balajitk@ti.com>,
	<gg@slimlogic.co.uk>, <linux-arm-kernel@lists.infradead.org>,
	<linux-kernel@vger.kernel.org>, <linux-iio@vger.kernel.org>,
	<devicetree-discuss@lists.ozlabs.org>,
	<linux-omap@vger.kernel.org>
Subject: Re: [PATCH v3 2/2] iio: twl6030-gpadc: TWL6030, TWL6032 GPADC driver
Date: Mon, 15 Jul 2013 14:56:18 +0300	[thread overview]
Message-ID: <51E3E362.6090903@ti.com> (raw)
In-Reply-To: <51E05F6C.1060506@metafoo.de>

Hi All,

I have a question regarding this patch and IIO in general
- Does IIO provide sync mechanism with system wide suspend/resume or 
this should be handled by each driver itself?

What if during system suspend iio_read_channel_raw() (or any other 
consumer API) will be called after gpadc driver have been suspended 
already? (I did some investigation and seems it's possible - Am I right?)

If no, could "info_exist_lock" be reused for such purposes?

Regards,
-grygorii


On 07/12/2013 10:56 PM, Lars-Peter Clausen wrote:
>
> A couple of comments inline.
>
> On 07/12/2013 09:18 AM, Oleksandr Kozaruk wrote:
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index ab0767e6..87d699e 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -157,4 +157,12 @@ config VIPERBOARD_ADC
>>         Say yes here to access the ADC part of the Nano River
>>         Technologies Viperboard.
>>
>> +config TWL6030_GPADC
>> +    tristate "TWL6030 GPADC (General Purpose A/D Convertor) Support"
>> +    depends on TWL4030_CORE
>> +    default n
>> +    help
>> +      Say yes here if you want support for the TWL6030 General Purpose
>> +      A/D Convertor.
>> +
>
> Keep it in alphabetical order
>
>>   endmenu
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 0a825be..8b05633 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -17,3 +17,4 @@ obj-$(CONFIG_MAX1363) += max1363.o
>>   obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
>>   obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
>>   obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
>> +obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
>
> Same here.
>
>> diff --git a/drivers/iio/adc/twl6030-gpadc.c
>> b/drivers/iio/adc/twl6030-gpadc.c
>> new file mode 100644
>> index 0000000..6ceb789
>> --- /dev/null
>> +++ b/drivers/iio/adc/twl6030-gpadc.c
>> @@ -0,0 +1,1019 @@
> [...]
>> +static u8 twl6032_channel_to_reg(int channel)
>> +{
>> +    return TWL6032_GPADC_GPCH0_LSB;
>
> There is more than one channel, isn't there?
>
> [...]
>  > +static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
>  > +                 const struct iio_chan_spec *chan,
>  > +                 int *val, int *val2, long mask)
>  > +{
>  > +    struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
>  > +    int ret = -EINVAL;
>  > +
>  > +    mutex_lock(&gpadc->lock);
>  > +
>  > +    ret = gpadc->pdata->start_conversion(chan->channel);
>  > +    if (ret) {
>  > +        dev_err(gpadc->dev, "failed to start conversion\n");
>  > +        goto err;
>  > +    }
>  > +    /* wait for conversion to complete */
>  > +    wait_for_completion_interruptible_timeout(&gpadc->irq_complete,
>  > +                        msecs_to_jiffies(5000));
>
> wait_for_completion_interruptible_timeout() can return either a negative
> error code if it was interrupted, 0 if it timed out, or a positive value
> if it was successfully completed. You need to handle all three cases.
> Have a look at other existing drivers to see how to do this properly.
>
>  > +
>  > +    switch (mask) {
>  > +    case IIO_CHAN_INFO_RAW:
>  > +        ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    case IIO_CHAN_INFO_PROCESSED:
>  > +        ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    default:
>  > +        break;
>  > +    }
>  > +err:
>  > +    mutex_unlock(&gpadc->lock);
>  > +
>  > +    return ret;
>  > +}
>
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_probe(struct platform_device *pdev)
>> +{
>> +    struct device *dev = &pdev->dev;
>> +    struct twl6030_gpadc_data *gpadc;
>> +    const struct twl6030_gpadc_platform_data *pdata;
>> +    const struct of_device_id *match;
>> +    struct iio_dev *indio_dev;
>> +    int irq;
>> +    int ret = 0;
>> +
>> +    match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev);
>> +    pdata = match ? match->data : dev->platform_data;
>> +
>> +    if (!pdata)
>> +        return -EINVAL;
>> +
>> +    indio_dev = iio_device_alloc(sizeof(struct twl6030_gpadc_data));
>
> sizeof(*gpadc)
>
>> +    if (!indio_dev) {
>> +        dev_err(dev, "failed allocating iio device\n");
>> +        ret = -ENOMEM;
>> +    }
>> +
>> +    gpadc = iio_priv(indio_dev);
>> +
>> +    gpadc->twl6030_cal_tbl = devm_kzalloc(dev,
>> +                    sizeof(struct twl6030_chnl_calib) *
>> +                    pdata->nchannels, GFP_KERNEL);
>> +    if (!gpadc->twl6030_cal_tbl)
>> +        goto err;
>> +
>> +    gpadc->dev = dev;
>> +    gpadc->pdata = pdata;
>> +
>> +    platform_set_drvdata(pdev, indio_dev);
>> +    mutex_init(&gpadc->lock);
>> +    init_completion(&gpadc->irq_complete);
>> +
>> +    ret = pdata->calibrate(gpadc);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to read calibration registers\n");
>> +        goto err;
>> +    }
>> +
>> +    irq = platform_get_irq(pdev, 0);
>> +    if (irq < 0) {
>> +        dev_err(&pdev->dev, "failed to get irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = devm_request_threaded_irq(dev, irq, NULL,
>> +                    twl6030_gpadc_irq_handler,
>> +                    IRQF_ONESHOT, "twl6030_gpadc", gpadc);
>
> You access memory in the interrupt handler which is freed before the
> interrupt handler is freed.
>
>> +    if (ret) {
>> +        dev_dbg(&pdev->dev, "could not request irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
>> +        goto err;
>> +    }
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                    TWL6030_REG_TOGGLE1);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC module\n");
>> +        goto err;
>> +    }
>> +
>> +    indio_dev->name = DRIVER_NAME;
>> +    indio_dev->dev.parent = dev;
>> +    indio_dev->info = &twl6030_gpadc_iio_info;
>> +    indio_dev->modes = INDIO_DIRECT_MODE;
>> +    indio_dev->channels = pdata->iio_channels;
>> +    indio_dev->num_channels = pdata->nchannels;
>> +
>> +    ret = iio_device_register(indio_dev);
>> +    if (ret)
>> +        goto err;
>> +
>> +    return ret;
>> +err:
>> +    iio_device_free(indio_dev);
>> +    return ret;
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_suspend(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error reseting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static int twl6030_gpadc_resume(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error setting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static const struct dev_pm_ops twl6030_gpadc_pm_ops = {
>> +    .suspend = twl6030_gpadc_suspend,
>> +    .resume = twl6030_gpadc_resume,
>> +};
>
> SIMPLE_DEV_PM_OPS?
>
> [...]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


WARNING: multiple messages have this Message-ID (diff)
From: Grygorii Strashko <grygorii.strashko-l0cyMroinI0@public.gmane.org>
To: Lars-Peter Clausen <lars-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>
Cc: Oleksandr Kozaruk
	<oleksandr.kozaruk-l0cyMroinI0@public.gmane.org>,
	tony-4v6yS6AI5VpBDgjK7y7TUQ@public.gmane.org,
	benoit.cousson-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	rnayak-l0cyMroinI0@public.gmane.org,
	peter.ujfalusi-l0cyMroinI0@public.gmane.org,
	kishon-l0cyMroinI0@public.gmane.org,
	jic23-KWPb1pKIrIJaa/9Udqfwiw@public.gmane.org,
	grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org,
	rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org,
	sameo-VuQAYsv1563Yd54FQh9/CA@public.gmane.org,
	ch.naveen-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org,
	poeschel-Xtl8qvBWbHwb1SvskN2V4Q@public.gmane.org,
	milo.kim-l0cyMroinI0@public.gmane.org,
	balajitk-l0cyMroinI0@public.gmane.org,
	gg-kDsPt+C1G03kYMGBc/C6ZA@public.gmane.org,
	linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	linux-iio-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org,
	linux-omap-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [PATCH v3 2/2] iio: twl6030-gpadc: TWL6030, TWL6032 GPADC driver
Date: Mon, 15 Jul 2013 14:56:18 +0300	[thread overview]
Message-ID: <51E3E362.6090903@ti.com> (raw)
In-Reply-To: <51E05F6C.1060506-Qo5EllUWu/uELgA04lAiVw@public.gmane.org>

Hi All,

I have a question regarding this patch and IIO in general
- Does IIO provide sync mechanism with system wide suspend/resume or 
this should be handled by each driver itself?

What if during system suspend iio_read_channel_raw() (or any other 
consumer API) will be called after gpadc driver have been suspended 
already? (I did some investigation and seems it's possible - Am I right?)

If no, could "info_exist_lock" be reused for such purposes?

Regards,
-grygorii


On 07/12/2013 10:56 PM, Lars-Peter Clausen wrote:
>
> A couple of comments inline.
>
> On 07/12/2013 09:18 AM, Oleksandr Kozaruk wrote:
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index ab0767e6..87d699e 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -157,4 +157,12 @@ config VIPERBOARD_ADC
>>         Say yes here to access the ADC part of the Nano River
>>         Technologies Viperboard.
>>
>> +config TWL6030_GPADC
>> +    tristate "TWL6030 GPADC (General Purpose A/D Convertor) Support"
>> +    depends on TWL4030_CORE
>> +    default n
>> +    help
>> +      Say yes here if you want support for the TWL6030 General Purpose
>> +      A/D Convertor.
>> +
>
> Keep it in alphabetical order
>
>>   endmenu
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 0a825be..8b05633 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -17,3 +17,4 @@ obj-$(CONFIG_MAX1363) += max1363.o
>>   obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
>>   obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
>>   obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
>> +obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
>
> Same here.
>
>> diff --git a/drivers/iio/adc/twl6030-gpadc.c
>> b/drivers/iio/adc/twl6030-gpadc.c
>> new file mode 100644
>> index 0000000..6ceb789
>> --- /dev/null
>> +++ b/drivers/iio/adc/twl6030-gpadc.c
>> @@ -0,0 +1,1019 @@
> [...]
>> +static u8 twl6032_channel_to_reg(int channel)
>> +{
>> +    return TWL6032_GPADC_GPCH0_LSB;
>
> There is more than one channel, isn't there?
>
> [...]
>  > +static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
>  > +                 const struct iio_chan_spec *chan,
>  > +                 int *val, int *val2, long mask)
>  > +{
>  > +    struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
>  > +    int ret = -EINVAL;
>  > +
>  > +    mutex_lock(&gpadc->lock);
>  > +
>  > +    ret = gpadc->pdata->start_conversion(chan->channel);
>  > +    if (ret) {
>  > +        dev_err(gpadc->dev, "failed to start conversion\n");
>  > +        goto err;
>  > +    }
>  > +    /* wait for conversion to complete */
>  > +    wait_for_completion_interruptible_timeout(&gpadc->irq_complete,
>  > +                        msecs_to_jiffies(5000));
>
> wait_for_completion_interruptible_timeout() can return either a negative
> error code if it was interrupted, 0 if it timed out, or a positive value
> if it was successfully completed. You need to handle all three cases.
> Have a look at other existing drivers to see how to do this properly.
>
>  > +
>  > +    switch (mask) {
>  > +    case IIO_CHAN_INFO_RAW:
>  > +        ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    case IIO_CHAN_INFO_PROCESSED:
>  > +        ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    default:
>  > +        break;
>  > +    }
>  > +err:
>  > +    mutex_unlock(&gpadc->lock);
>  > +
>  > +    return ret;
>  > +}
>
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_probe(struct platform_device *pdev)
>> +{
>> +    struct device *dev = &pdev->dev;
>> +    struct twl6030_gpadc_data *gpadc;
>> +    const struct twl6030_gpadc_platform_data *pdata;
>> +    const struct of_device_id *match;
>> +    struct iio_dev *indio_dev;
>> +    int irq;
>> +    int ret = 0;
>> +
>> +    match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev);
>> +    pdata = match ? match->data : dev->platform_data;
>> +
>> +    if (!pdata)
>> +        return -EINVAL;
>> +
>> +    indio_dev = iio_device_alloc(sizeof(struct twl6030_gpadc_data));
>
> sizeof(*gpadc)
>
>> +    if (!indio_dev) {
>> +        dev_err(dev, "failed allocating iio device\n");
>> +        ret = -ENOMEM;
>> +    }
>> +
>> +    gpadc = iio_priv(indio_dev);
>> +
>> +    gpadc->twl6030_cal_tbl = devm_kzalloc(dev,
>> +                    sizeof(struct twl6030_chnl_calib) *
>> +                    pdata->nchannels, GFP_KERNEL);
>> +    if (!gpadc->twl6030_cal_tbl)
>> +        goto err;
>> +
>> +    gpadc->dev = dev;
>> +    gpadc->pdata = pdata;
>> +
>> +    platform_set_drvdata(pdev, indio_dev);
>> +    mutex_init(&gpadc->lock);
>> +    init_completion(&gpadc->irq_complete);
>> +
>> +    ret = pdata->calibrate(gpadc);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to read calibration registers\n");
>> +        goto err;
>> +    }
>> +
>> +    irq = platform_get_irq(pdev, 0);
>> +    if (irq < 0) {
>> +        dev_err(&pdev->dev, "failed to get irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = devm_request_threaded_irq(dev, irq, NULL,
>> +                    twl6030_gpadc_irq_handler,
>> +                    IRQF_ONESHOT, "twl6030_gpadc", gpadc);
>
> You access memory in the interrupt handler which is freed before the
> interrupt handler is freed.
>
>> +    if (ret) {
>> +        dev_dbg(&pdev->dev, "could not request irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
>> +        goto err;
>> +    }
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                    TWL6030_REG_TOGGLE1);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC module\n");
>> +        goto err;
>> +    }
>> +
>> +    indio_dev->name = DRIVER_NAME;
>> +    indio_dev->dev.parent = dev;
>> +    indio_dev->info = &twl6030_gpadc_iio_info;
>> +    indio_dev->modes = INDIO_DIRECT_MODE;
>> +    indio_dev->channels = pdata->iio_channels;
>> +    indio_dev->num_channels = pdata->nchannels;
>> +
>> +    ret = iio_device_register(indio_dev);
>> +    if (ret)
>> +        goto err;
>> +
>> +    return ret;
>> +err:
>> +    iio_device_free(indio_dev);
>> +    return ret;
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_suspend(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error reseting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static int twl6030_gpadc_resume(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error setting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static const struct dev_pm_ops twl6030_gpadc_pm_ops = {
>> +    .suspend = twl6030_gpadc_suspend,
>> +    .resume = twl6030_gpadc_resume,
>> +};
>
> SIMPLE_DEV_PM_OPS?
>
> [...]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

WARNING: multiple messages have this Message-ID (diff)
From: grygorii.strashko@ti.com (Grygorii Strashko)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH v3 2/2] iio: twl6030-gpadc: TWL6030, TWL6032 GPADC driver
Date: Mon, 15 Jul 2013 14:56:18 +0300	[thread overview]
Message-ID: <51E3E362.6090903@ti.com> (raw)
In-Reply-To: <51E05F6C.1060506@metafoo.de>

Hi All,

I have a question regarding this patch and IIO in general
- Does IIO provide sync mechanism with system wide suspend/resume or 
this should be handled by each driver itself?

What if during system suspend iio_read_channel_raw() (or any other 
consumer API) will be called after gpadc driver have been suspended 
already? (I did some investigation and seems it's possible - Am I right?)

If no, could "info_exist_lock" be reused for such purposes?

Regards,
-grygorii


On 07/12/2013 10:56 PM, Lars-Peter Clausen wrote:
>
> A couple of comments inline.
>
> On 07/12/2013 09:18 AM, Oleksandr Kozaruk wrote:
>> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
>> index ab0767e6..87d699e 100644
>> --- a/drivers/iio/adc/Kconfig
>> +++ b/drivers/iio/adc/Kconfig
>> @@ -157,4 +157,12 @@ config VIPERBOARD_ADC
>>         Say yes here to access the ADC part of the Nano River
>>         Technologies Viperboard.
>>
>> +config TWL6030_GPADC
>> +    tristate "TWL6030 GPADC (General Purpose A/D Convertor) Support"
>> +    depends on TWL4030_CORE
>> +    default n
>> +    help
>> +      Say yes here if you want support for the TWL6030 General Purpose
>> +      A/D Convertor.
>> +
>
> Keep it in alphabetical order
>
>>   endmenu
>> diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
>> index 0a825be..8b05633 100644
>> --- a/drivers/iio/adc/Makefile
>> +++ b/drivers/iio/adc/Makefile
>> @@ -17,3 +17,4 @@ obj-$(CONFIG_MAX1363) += max1363.o
>>   obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
>>   obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
>>   obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
>> +obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
>
> Same here.
>
>> diff --git a/drivers/iio/adc/twl6030-gpadc.c
>> b/drivers/iio/adc/twl6030-gpadc.c
>> new file mode 100644
>> index 0000000..6ceb789
>> --- /dev/null
>> +++ b/drivers/iio/adc/twl6030-gpadc.c
>> @@ -0,0 +1,1019 @@
> [...]
>> +static u8 twl6032_channel_to_reg(int channel)
>> +{
>> +    return TWL6032_GPADC_GPCH0_LSB;
>
> There is more than one channel, isn't there?
>
> [...]
>  > +static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev,
>  > +                 const struct iio_chan_spec *chan,
>  > +                 int *val, int *val2, long mask)
>  > +{
>  > +    struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev);
>  > +    int ret = -EINVAL;
>  > +
>  > +    mutex_lock(&gpadc->lock);
>  > +
>  > +    ret = gpadc->pdata->start_conversion(chan->channel);
>  > +    if (ret) {
>  > +        dev_err(gpadc->dev, "failed to start conversion\n");
>  > +        goto err;
>  > +    }
>  > +    /* wait for conversion to complete */
>  > +    wait_for_completion_interruptible_timeout(&gpadc->irq_complete,
>  > +                        msecs_to_jiffies(5000));
>
> wait_for_completion_interruptible_timeout() can return either a negative
> error code if it was interrupted, 0 if it timed out, or a positive value
> if it was successfully completed. You need to handle all three cases.
> Have a look at other existing drivers to see how to do this properly.
>
>  > +
>  > +    switch (mask) {
>  > +    case IIO_CHAN_INFO_RAW:
>  > +        ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    case IIO_CHAN_INFO_PROCESSED:
>  > +        ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val);
>  > +        ret = ret ? -EIO : IIO_VAL_INT;
>  > +        break;
>  > +
>  > +    default:
>  > +        break;
>  > +    }
>  > +err:
>  > +    mutex_unlock(&gpadc->lock);
>  > +
>  > +    return ret;
>  > +}
>
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_probe(struct platform_device *pdev)
>> +{
>> +    struct device *dev = &pdev->dev;
>> +    struct twl6030_gpadc_data *gpadc;
>> +    const struct twl6030_gpadc_platform_data *pdata;
>> +    const struct of_device_id *match;
>> +    struct iio_dev *indio_dev;
>> +    int irq;
>> +    int ret = 0;
>> +
>> +    match = of_match_device(of_match_ptr(of_twl6030_match_tbl), dev);
>> +    pdata = match ? match->data : dev->platform_data;
>> +
>> +    if (!pdata)
>> +        return -EINVAL;
>> +
>> +    indio_dev = iio_device_alloc(sizeof(struct twl6030_gpadc_data));
>
> sizeof(*gpadc)
>
>> +    if (!indio_dev) {
>> +        dev_err(dev, "failed allocating iio device\n");
>> +        ret = -ENOMEM;
>> +    }
>> +
>> +    gpadc = iio_priv(indio_dev);
>> +
>> +    gpadc->twl6030_cal_tbl = devm_kzalloc(dev,
>> +                    sizeof(struct twl6030_chnl_calib) *
>> +                    pdata->nchannels, GFP_KERNEL);
>> +    if (!gpadc->twl6030_cal_tbl)
>> +        goto err;
>> +
>> +    gpadc->dev = dev;
>> +    gpadc->pdata = pdata;
>> +
>> +    platform_set_drvdata(pdev, indio_dev);
>> +    mutex_init(&gpadc->lock);
>> +    init_completion(&gpadc->irq_complete);
>> +
>> +    ret = pdata->calibrate(gpadc);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to read calibration registers\n");
>> +        goto err;
>> +    }
>> +
>> +    irq = platform_get_irq(pdev, 0);
>> +    if (irq < 0) {
>> +        dev_err(&pdev->dev, "failed to get irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = devm_request_threaded_irq(dev, irq, NULL,
>> +                    twl6030_gpadc_irq_handler,
>> +                    IRQF_ONESHOT, "twl6030_gpadc", gpadc);
>
> You access memory in the interrupt handler which is freed before the
> interrupt handler is freed.
>
>> +    if (ret) {
>> +        dev_dbg(&pdev->dev, "could not request irq\n");
>> +        goto err;
>> +    }
>> +
>> +    ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC interrupt\n");
>> +        goto err;
>> +    }
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                    TWL6030_REG_TOGGLE1);
>> +    if (ret < 0) {
>> +        dev_err(&pdev->dev, "failed to enable GPADC module\n");
>> +        goto err;
>> +    }
>> +
>> +    indio_dev->name = DRIVER_NAME;
>> +    indio_dev->dev.parent = dev;
>> +    indio_dev->info = &twl6030_gpadc_iio_info;
>> +    indio_dev->modes = INDIO_DIRECT_MODE;
>> +    indio_dev->channels = pdata->iio_channels;
>> +    indio_dev->num_channels = pdata->nchannels;
>> +
>> +    ret = iio_device_register(indio_dev);
>> +    if (ret)
>> +        goto err;
>> +
>> +    return ret;
>> +err:
>> +    iio_device_free(indio_dev);
>> +    return ret;
>> +}
>> +
> [...]
>> +static int twl6030_gpadc_suspend(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error reseting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static int twl6030_gpadc_resume(struct device *pdev)
>> +{
>> +    int ret;
>> +
>> +    ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS,
>> +                TWL6030_REG_TOGGLE1);
>> +    if (ret)
>> +        dev_err(pdev, "error setting GPADC (%d)!\n", ret);
>> +
>> +    return 0;
>> +};
>> +
>> +static const struct dev_pm_ops twl6030_gpadc_pm_ops = {
>> +    .suspend = twl6030_gpadc_suspend,
>> +    .resume = twl6030_gpadc_resume,
>> +};
>
> SIMPLE_DEV_PM_OPS?
>
> [...]
> --
> To unsubscribe from this list: send the line "unsubscribe linux-omap" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

  parent reply	other threads:[~2013-07-15 11:58 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-12  7:18 [PATCH v3 0/2] TWL6030, TWL6032 GPADC driver Oleksandr Kozaruk
2013-07-12  7:18 ` Oleksandr Kozaruk
2013-07-12  7:18 ` Oleksandr Kozaruk
2013-07-12  7:18 ` [PATCH v3 1/2] ARM: dts: twl: Add GPADC data to device tree Oleksandr Kozaruk
2013-07-12  7:18   ` Oleksandr Kozaruk
2013-07-12  7:18   ` Oleksandr Kozaruk
2013-07-12  7:18 ` [PATCH v3 2/2] iio: twl6030-gpadc: TWL6030, TWL6032 GPADC driver Oleksandr Kozaruk
2013-07-12  7:18   ` Oleksandr Kozaruk
2013-07-12  7:18   ` Oleksandr Kozaruk
2013-07-12 19:42   ` Jonathan Cameron
2013-07-12 19:42     ` Jonathan Cameron
2013-07-12 19:42     ` Jonathan Cameron
2013-07-15 13:30     ` Kozaruk, Oleksandr
2013-07-15 13:30       ` Kozaruk, Oleksandr
2013-07-15 13:30       ` Kozaruk, Oleksandr
2013-07-15 13:30       ` Kozaruk, Oleksandr
2013-07-15 14:05       ` Graeme Gregory
2013-07-15 14:05         ` Graeme Gregory
2013-07-15 14:05         ` Graeme Gregory
2013-07-12 19:56   ` Lars-Peter Clausen
2013-07-12 19:56     ` Lars-Peter Clausen
2013-07-12 19:56     ` Lars-Peter Clausen
2013-07-15 11:09     ` Kozaruk, Oleksandr
2013-07-15 11:09       ` Kozaruk, Oleksandr
2013-07-15 11:09       ` Kozaruk, Oleksandr
2013-07-15 11:33       ` Lars-Peter Clausen
2013-07-15 11:33         ` Lars-Peter Clausen
2013-07-15 11:33         ` Lars-Peter Clausen
2013-07-17 13:45         ` Oleksandr Kozaruk
2013-07-17 13:45           ` Oleksandr Kozaruk
2013-07-17 13:45           ` Oleksandr Kozaruk
2013-07-17 14:47           ` Lars-Peter Clausen
2013-07-17 14:47             ` Lars-Peter Clausen
2013-07-17 14:47             ` Lars-Peter Clausen
2013-07-15 11:56     ` Grygorii Strashko [this message]
2013-07-15 11:56       ` Grygorii Strashko
2013-07-15 11:56       ` Grygorii Strashko
2013-07-15 12:33       ` Lars-Peter Clausen
2013-07-15 12:33         ` Lars-Peter Clausen
2013-07-15 12:33         ` Lars-Peter Clausen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=51E3E362.6090903@ti.com \
    --to=grygorii.strashko@ti.com \
    --cc=balajitk@ti.com \
    --cc=benoit.cousson@linaro.org \
    --cc=ch.naveen@samsung.com \
    --cc=devicetree-discuss@lists.ozlabs.org \
    --cc=gg@slimlogic.co.uk \
    --cc=grant.likely@linaro.org \
    --cc=jic23@cam.ac.uk \
    --cc=kishon@ti.com \
    --cc=lars@metafoo.de \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=milo.kim@ti.com \
    --cc=oleksandr.kozaruk@ti.com \
    --cc=peter.ujfalusi@ti.com \
    --cc=poeschel@lemonage.de \
    --cc=rnayak@ti.com \
    --cc=rob.herring@calxeda.com \
    --cc=sameo@linux.intel.com \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.