On Sun, 31 Dec 2023 22:42:37 +0530
Jishnu Prakash <quic_jprakash@xxxxxxxxxxx> wrote:
The ADC architecture on PMIC5 Gen3 is similar to that on PMIC5 Gen2,
with all SW communication to ADC going through PMK8550 which
communicates with other PMICs through PBS.
+
+ for (i = 0; i < adc->nchannels; i++) {
+ bool upper_set = false, lower_set = false;
+ int temp, offset;
+ u16 code = 0;
+
+ chan_prop = &adc->chan_props[i];
+ offset = chan_prop->tm_chan_index;
+
+ if (!chan_prop->adc_tm)
+ continue;
+
+ mutex_lock(&adc->lock);
+ if (chan_prop->sdam_index != sdam_index) {
Perhaps factor this block out as indent already high and adding scoped_guard would
make it worse.
+ sdam_index = chan_prop->sdam_index;
+ ret = adc5_gen3_read(adc, sdam_index, ADC5_GEN3_TM_HIGH_STS,
+ tm_status, 2);
+ if (ret) {
+ dev_err(adc->dev, "adc read TM status failed with %d\n", ret);
+ goto out;
+ }
+If this is required before the place where a simple
+static void adc5_gen3_disable(void *data)
+{
+ struct adc5_chip *adc = data;
+ int i;
+
+ if (adc->n_tm_channels)
+ cancel_work_sync(&adc->tm_handler_work);
devm_request_irq() will result in the irqs being cleaned up
them register this callback earlier to avoid problems there.
+
+ for (i = 0; i < adc->num_sdams; i++)
+ free_irq(adc->base[i].irq, adc);
+
+ mutex_lock(&adc->lock);
+ /* Disable all available TM channels */
+ for (i = 0; i < adc->nchannels; i++) {
+ if (!adc->chan_props[i].adc_tm)
+ continue;
+ adc5_gen3_poll_wait_hs(adc, adc->chan_props[i].sdam_index);
+ _adc_tm5_gen3_disable_channel(&adc->chan_props[i]);
+ }
+
+ mutex_unlock(&adc->lock);
+}
+
+ prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
I'd prefer to see you has through the value that maps to this after qcom_adc5_hw_settle_time_from_dt
so then you can just set a default in value and call the rest of the code unconditionally.
Same for the cases that follow.
+ ret = fwnode_property_read_u32(fwnode, "qcom,hw-settle-time", &value);
+ if (!ret) {
+ ret = qcom_adc5_hw_settle_time_from_dt(value,
+ data->hw_settle_1);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "%#x invalid hw-settle-time %d us\n",
+ chan, value);
+ prop->hw_settle_time = ret;
+ }
+
+
+ chan_props = adc->chan_props;
+ adc->n_tm_channels = 0;
+ iio_chan = adc->iio_chans;
+ adc->data = device_get_match_data(adc->dev);
+ if (!adc->data)
+ adc->data = &adc5_gen3_data_pmic;
Why do you need a default? Add a comment so we remember the reasoning.
+
+ device_for_each_child_node(adc->dev, child) {
+ ret = adc5_gen3_get_fw_channel_data(adc, chan_props, child, adc->data);
+ if (ret < 0) {
+
+ ret = platform_get_irq_byname(pdev, adc->base[i].irq_name);
+ if (ret < 0) {
+ kfree(reg);
+ dev_err(dev, "Getting IRQ %d by name failed, ret = %d\n",
+ adc->base[i].irq, ret);
+ goto err_irq;
+ }
+ adc->base[i].irq = ret;
+
+ ret = request_irq(adc->base[i].irq, adc5_gen3_isr, 0, adc->base[i].irq_name, adc);
Don't mix devm and non dev calls. And don't group up multiple things in one devm callback
as it almost always leads to bugs where for example only some irqs are allocated.
+ if (ret < 0) {
+ kfree(reg);
+ dev_err(dev, "Failed to request SDAM%d irq, ret = %d\n", i, ret);
+ goto err_irq;
+ }
+ }
+ kfree(reg);
I would factor out this code and allocation of reg so you can easily use scope
based cleanup (see linux/cleanup.h) to avoid the kfree(reg) entries that
make for awkward code flow.
+As above, this action does multiple things. Also use devm_add_action_or_reset() to cleanup
+ ret = devm_add_action(dev, adc5_gen3_disable, adc);
if the devm registration fails without needing to do it manually.
+ if (ret < 0) {
+ dev_err(dev, "failed to register adc disablement devm action, %d\n", ret);
+ goto err_irq;
+ }
+
+
+ if (adc->n_tm_channels)
+ INIT_WORK(&adc->tm_handler_work, tm_handler_work);
Until this init work seems unlikely you should be calling the cancel
work in gen3_disable()
+Please keep error conditions as the out of line path.
+ indio_dev->name = pdev->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &adc5_gen3_info;
+ indio_dev->channels = adc->iio_chans;
+ indio_dev->num_channels = adc->nchannels;
+
+ ret = devm_iio_device_register(dev, indio_dev);
+ if (!ret)
+ return 0;
if (ret)
goto err_irq;
return 0;
+
+err_irq:
+ for (i = 0; i < adc->num_sdams; i++)
+ free_irq(adc->base[i].irq, adc);
Already freed by a devm cleanup handler.
+
+ return ret;
+}