Re: [PATCH v3 1/2] iio: vadc: Qualcomm SPMI PMIC voltage ADC driver

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




On 10/13/2014 01:07 AM, Hartmut Knaack wrote:
> Stanimir Varbanov schrieb am 24.09.2014 14:56:
>> The voltage ADC is peripheral of Qualcomm SPMI PMIC chips. It has
>> 15bits resolution and register space inside PMIC accessible across
>> SPMI bus.
>>
>> The vadc driver registers itself through IIO interface.
> Quite a lot of changes. Please see my comments inline.
>>
>> Signed-off-by: Stanimir Varbanov <svarbanov@xxxxxxxxxx>
>> Signed-off-by: Ivan T. Ivanov <iivanov@xxxxxxxxxx>
>> ---
>>  drivers/iio/adc/Kconfig                       |   10 +
>>  drivers/iio/adc/Makefile                      |    1 +
>>  drivers/iio/adc/qcom-spmi-vadc.c              | 1029 +++++++++++++++++++++++++
>>  include/dt-bindings/iio/qcom,spmi-pmic-vadc.h |  119 +++
>>  4 files changed, 1159 insertions(+), 0 deletions(-)
>>  create mode 100644 drivers/iio/adc/qcom-spmi-vadc.c
>>  create mode 100644 include/dt-bindings/iio/qcom,spmi-pmic-vadc.h
>>

<snip>

>> +
>> +static int vadc_reset(struct vadc_priv *vadc)
>> +{
>> +	u8 data;
>> +	int ret;
>> +
>> +	ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = vadc_read(vadc, VADC_PERH_RESET_CTL3, &data);
>> +	if (ret)
>> +		return ret;
>> +
>> +	ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
>> +	if (ret)
>> +		return ret;
>> +
>> +	data |= VADC_FOLLOW_WARM_RB;
>> +
>> +	return vadc_write(vadc, VADC_PERH_RESET_CTL3, data);
>> +}
>> +
>> +static int vadc_enable(struct vadc_priv *vadc, bool state)
>> +{
>> +	return vadc_write(vadc, VADC_EN_CTL1, state ? VADC_EN_CTL1_SET : 0);
>> +}
>> +
>> +#ifdef DEBUG
>> +static void vadc_show_status(struct vadc_priv *vadc)
>> +{
> You could also move the #ifdef in here...
>> +	u8 mode, sta1, chan, dig, en, req;
>> +	int ret;
>> +
>> +	ret = vadc_read(vadc, VADC_MODE_CTL, &mode);
>> +	if (ret)
>> +		return;
>> +
>> +	ret = vadc_read(vadc, VADC_ADC_DIG_PARAM, &dig);
>> +	if (ret)
>> +		return;
>> +
>> +	ret = vadc_read(vadc, VADC_ADC_CH_SEL_CTL, &chan);
>> +	if (ret)
>> +		return;
>> +
>> +	ret = vadc_read(vadc, VADC_CONV_REQ, &req);
>> +	if (ret)
>> +		return;
>> +
>> +	ret = vadc_read(vadc, VADC_STATUS1, &sta1);
>> +	if (ret)
>> +		return;
>> +
>> +	ret = vadc_read(vadc, VADC_EN_CTL1, &en);
>> +	if (ret)
>> +		return;
>> +
>> +	dev_dbg(vadc->dev,
>> +		"mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
>> +		mode, en, chan, dig, req, sta1);
> ...and the #endif here. Saves 2 lines of code ;-)

I don't like #ifdefs in function body, it makes code unreadable at least
for me :)

>> +}
>> +#else
>> +static void vadc_show_status(struct vadc_priv *vadc) {}
>> +#endif
>> +

<snip>

>> +
>> +static int vadc_get_dt_channel_data(struct device *dev,
>> +				    struct vadc_channel_prop *prop,
>> +				    struct device_node *node)
>> +{
>> +	const char *name = node->name;
>> +	u32 chan, value, varr[2];
>> +	int ret;
>> +
>> +	ret = of_property_read_u32(node, "reg", &chan);
>> +	if (ret) {
>> +		dev_dbg(dev, "invalid channel number %s\n", name);
>> +		return ret;
>> +	}
>> +
>> +	if (chan > VADC_CHAN_MAX || chan < VADC_CHAN_MIN) {
>> +		dev_dbg(dev, "%s invalid channel number %d\n", name, chan);
>> +		return -EINVAL;
>> +	}
>> +
>> +	/* the channel has DT description */
>> +	prop->channel = chan;
>> +
>> +	ret = of_property_read_u32(node, "qcom,decimation", &value);
>> +	if (!ret) {
>> +		ret = vadc_decimation_from_dt(value);
>> +		if (ret < 0) {
>> +			dev_dbg(dev, "%02x invalid decimation %d\n",
>> +				chan, value);
>> +			return ret;
>> +		}
>> +		prop->decimation = ret;
>> +	} else {
>> +		prop->decimation = VADC_DEF_DECIMATION;
>> +	}
>> +
>> +	ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
>> +	if (!ret) {
>> +		ret = vadc_prescaling_from_dt(varr[0], varr[1]);
>> +		if (ret < 0) {
>> +			dev_dbg(dev, "%02x invalid pre-scaling <%d %d>\n",
>> +				chan, varr[0], varr[1]);
>> +			return ret;
>> +		}
>> +		prop->prescale = ret;
>> +	} else {
>> +		prop->prescale = vadc_chans[prop->channel].prescale_index;
>> +	}
>> +
>> +	ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
>> +	if (!ret) {
>> +		ret = vadc_hw_settle_time_from_dt(value);
>> +		if (ret < 0) {
>> +			dev_dbg(dev, "%02x invalid hw-settle-time %d, us\n",
> The colon inside the string is probably an unintended leftover?

correct.

>> +				chan, value);
>> +			return ret;
>> +		}
>> +		prop->hw_settle_time = ret;
>> +	} else {
>> +		prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
>> +	}
>> +
>> +	ret = of_property_read_u32(node, "qcom,avg-samples", &value);
>> +	if (!ret) {
>> +		ret = vadc_avg_samples_from_dt(value);
>> +		if (ret < 0) {
>> +			dev_dbg(dev, "%02x invalid avg-samples %d\n",
>> +				chan, value);
>> +			return ret;
>> +		}
>> +		prop->avg_samples = ret;
>> +	} else {
>> +		prop->avg_samples = VADC_DEF_AVG_SAMPLES;
>> +	}
>> +
>> +	if (of_property_read_bool(node, "qcom,ratiometric"))
>> +		prop->calibration = VADC_CALIB_RATIOMETRIC;
>> +	else
>> +		prop->calibration = VADC_CALIB_ABSOLUTE;
>> +
>> +	dev_dbg(dev, "%02x name %s\n", chan, name);
>> +
>> +	return 0;
>> +}
>> +
>> +static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
>> +{
>> +	struct iio_chan_spec *iio_chan = vadc->iio_chans;
>> +	const struct vadc_channels *vadc_chan;
>> +	struct vadc_channel_prop prop;
>> +	struct device_node *child;
>> +	int ret, index = 0;
> index could be defined unsigned, as it should only carry unsigned values.

makes sense.

>> +
>> +	for_each_available_child_of_node(node, child) {
>> +		ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
>> +		if (ret)
>> +			return ret;
>> +
>> +		vadc->chan_props[index] = prop;
>> +
>> +		vadc_chan = &vadc_chans[prop.channel];
>> +
>> +		iio_chan->channel = prop.channel;
>> +		iio_chan->datasheet_name = vadc_chan->datasheet_name;
>> +		iio_chan->info_mask_separate = vadc_chan->info_mask;
>> +		iio_chan->type = vadc_chan->type;
>> +		iio_chan->indexed = 1;
>> +		iio_chan->scan_type.sign = 's';
>> +		iio_chan->scan_type.realbits = 15;
>> +		iio_chan->scan_type.storagebits = 16;
>> +		iio_chan->address = index++;
>> +
>> +		iio_chan++;
>> +	}
>> +
>> +	return 0;
>> +}
>> +

<snip>

>> +
>> +static int vadc_probe(struct platform_device *pdev)
>> +{
>> +	struct device_node *node = pdev->dev.of_node;
>> +	struct device *dev = &pdev->dev;
>> +	struct iio_dev *indio_dev;
>> +	struct vadc_priv *vadc;
>> +	struct resource *res;
>> +	struct regmap *regmap;
>> +	int ret, irq_eoc;
>> +
>> +	regmap = dev_get_regmap(dev->parent, NULL);
>> +	if (!regmap)
>> +		return -ENODEV;
>> +
>> +	res = platform_get_resource(pdev, IORESOURCE_REG, 0);
>> +	if (!res)
>> +		return -ENODEV;
>> +
>> +	indio_dev = devm_iio_device_alloc(dev, sizeof(*vadc));
>> +	if (!indio_dev)
>> +		return -ENOMEM;
>> +
>> +	vadc = iio_priv(indio_dev);
>> +	vadc->regmap = regmap;
>> +	vadc->dev = dev;
>> +	vadc->base = res->start;
>> +	vadc->are_ref_measured = false;
>> +	init_completion(&vadc->complete);
>> +
>> +	ret = vadc_check_revision(vadc);
>> +	if (ret)
>> +		return ret;
>> +
>> +	vadc->nchannels = of_get_available_child_count(node);
>> +	if (!vadc->nchannels)
>> +		return -EINVAL;
>> +
>> +	vadc->iio_chans = devm_kcalloc(dev, vadc->nchannels,
>> +				       sizeof(*vadc->iio_chans), GFP_KERNEL);
>> +	if (!vadc->iio_chans)
>> +		return -ENOMEM;
>> +
>> +	vadc->chan_props = devm_kcalloc(dev, vadc->nchannels,
>> +					sizeof(*vadc->chan_props), GFP_KERNEL);
>> +	if (!vadc->chan_props)
>> +		return -ENOMEM;
>> +
>> +	ret = vadc_get_dt_data(vadc, node);
>> +	if (ret)
>> +		return ret;
>> +
>> +	irq_eoc = platform_get_irq(pdev, 0);
>> +	if (irq_eoc < 0) {
>> +		if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
>> +			return irq_eoc;
>> +		vadc->poll_eoc = true;
>> +	}
>> +
> Isn't the part below actually the else section of the part above (and device_init_wakeup() belonging up there)?

you are right, might be I wanted to avoid indentation issues. Will see
how to make it better.

>> +	if (!vadc->poll_eoc) {
>> +		ret = devm_request_irq(dev, irq_eoc, vadc_isr,
>> +				       IRQF_TRIGGER_RISING, "spmi-vadc", vadc);
>> +		if (!ret)
>> +			enable_irq_wake(irq_eoc);
>> +		else
>> +			return ret;
> Usually this is done this way:

yes, I know just oversight it.

> 		if (ret)
> 			return ret;
> 
> 		enable_irq_wake(irq_eoc);
>> +	} else {
>> +		device_init_wakeup(vadc->dev, true);
>> +	}
>> +
>> +	ret = vadc_reset(vadc);
>> +	if (ret) {
>> +		dev_dbg(dev, "reset failed\n");
>> +		return ret;
>> +	}
>> +
>> +	platform_set_drvdata(pdev, vadc);
> Why bother to call platform_set_drvdata()?

Seems leftover, will delete.

-- 
regards,
Stan
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux