From: Andy Shevchenko <andriy.shevchenko@intel.com>
To: "Nuno Sá" <nuno.sa@analog.com>
Cc: linux-iio@vger.kernel.org, devicetree@vger.kernel.org,
Rob Herring <robh+dt@kernel.org>,
Jonathan Cameron <jic23@kernel.org>,
Lars-Peter Clausen <lars@metafoo.de>,
Michael Hennerich <Michael.Hennerich@analog.com>
Subject: Re: [PATCH v3 1/3] iio: dac: add support for ltc2688
Date: Sat, 5 Feb 2022 19:29:39 +0200 [thread overview]
Message-ID: <Yf60A1UkbBtQ68qv@smile.fi.intel.com> (raw)
In-Reply-To: <20220121142501.151-2-nuno.sa@analog.com>
On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:
> The LTC2688 is a 16 channel, 16 bit, +-15V DAC with an integrated
> precision reference. It is guaranteed monotonic and has built in
> rail-to-rail output buffers that can source or sink up to 20 mA.
...
> +#include <linux/of.h>
property.h please/
...
> +static int ltc2688_spi_read(void *context, const void *reg, size_t reg_size,
> + void *val, size_t val_size)
> +{
> + struct ltc2688_state *st = context;
> + struct spi_transfer xfers[] = {
> + {
> + .tx_buf = st->tx_data,
> + .bits_per_word = 8,
> + .len = 3,
> + .cs_change = 1,
> + }, {
> + .tx_buf = st->tx_data + 3,
> + .rx_buf = st->rx_data,
> + .bits_per_word = 8,
> + .len = 3,
> + },
> + };
> + int ret;
> + memcpy(st->tx_data, reg, reg_size);
> +
> + ret = spi_sync_transfer(st->spi, xfers, ARRAY_SIZE(xfers));
> + if (ret)
> + return ret;
> +
> + memcpy(val, &st->rx_data[1], val_size);
> +
> + return 0;
> +}
First of all, yuo have fixed len in transfer sizes, so what the purpose of the reg_size / val_size?
Second, why do you need this specific function instead of regmap bulk ops against be24/le24?
...
> +unlock:
out_unlock: ?
(And in similar cases)
...
> + if (ret)
> + return ret;
> +
> + return len;
In some cases the return ret ?: len; is used, in some like above. Maybe a bit
of consistency?
...
> + if (private == LTC2688_INPUT_B_AVAIL)
> + return sysfs_emit(buf, "[%u %u %u]\n", ltc2688_raw_range[0],
> + ltc2688_raw_range[1],
> + ltc2688_raw_range[2] / 4);
Is it standard form "[A B C]" for ranges in IIO? I haven't looked into the code
deeply (and datasheet at all) to understand meaning. To me range is usually out
of two numbers.
> + if (private == LTC2688_DITHER_OFF)
> + return sysfs_emit(buf, "0\n");
> + ret = ltc2688_dac_code_read(st, chan->channel, private, &val);
> + if (ret)
> + return ret;
> +
> + return sysfs_emit(buf, "%u\n", val);
These three types of output for one sysfs node? Seems it's not align with the
idea behind sysfs. It maybe that I missed something.
...
> + ret = kstrtou16(buf, 10, &val);
In other function you have long, here u16. I would expect that the types are of
the same class, e.g. if here you have u16, then there something like s32 / s64.
Or here something like unsigned short.
A bit of elaboration why u16 is chosen here?
...
> + .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW), \
> + .ext_info = ltc2688_ext_info \
+ Comma
...
> +static int ltc2688_tgp_clk_setup(struct ltc2688_state *st,
> + struct ltc2688_chan *chan,
> + struct device_node *np, int tgp)
> +{
> + unsigned long rate;
> + struct clk *clk;
> + int ret, f;
> +
> + clk = devm_get_clk_from_child(&st->spi->dev, np, NULL);
> + if (IS_ERR(clk))
Make it optional for non-OF, can be done as easy as
if (IS_ERR(clk)) {
if (PTR_ERR(clk) == -ENOENT)
clk = NULL;
else
return dev_err_probe(...);
}
> + return dev_err_probe(&st->spi->dev, PTR_ERR(clk),
> + "failed to get tgp clk.\n");
> +
> + ret = clk_prepare_enable(clk);
> + if (ret)
> + return dev_err_probe(&st->spi->dev, ret,
> + "failed to enable tgp clk.\n");
> +
> + ret = devm_add_action_or_reset(&st->spi->dev, ltc2688_clk_disable, clk);
> + if (ret)
> + return ret;
> +
> + if (chan->toggle_chan)
> + return 0;
> +
> + /* calculate available dither frequencies */
> + rate = clk_get_rate(clk);
> + for (f = 0; f < ARRAY_SIZE(chan->dither_frequency); f++)
> + chan->dither_frequency[f] = DIV_ROUND_CLOSEST(rate, ltc2688_period[f]);
> +
> + return 0;
> +}
...
> +static int ltc2688_channel_config(struct ltc2688_state *st)
> +{
> + struct device *dev = &st->spi->dev;
> + struct device_node *child;
> + u32 reg, clk_input, val, tmp[2];
> + int ret, span;
> +
> + for_each_available_child_of_node(dev->of_node, child) {
device_for_each_child_node()
> + struct ltc2688_chan *chan;
> +
> + ret = of_property_read_u32(child, "reg", ®);
> + if (ret) {
> + of_node_put(child);
> + return dev_err_probe(dev, ret,
> + "Failed to get reg property\n");
> + }
> +
> + if (reg >= LTC2688_DAC_CHANNELS) {
> + of_node_put(child);
> + return dev_err_probe(dev, -EINVAL,
> + "reg bigger than: %d\n",
> + LTC2688_DAC_CHANNELS);
> + }
> +
> + val = 0;
> + chan = &st->channels[reg];
> + if (of_property_read_bool(child, "adi,toggle-mode")) {
> + chan->toggle_chan = true;
> + /* assume sw toggle ABI */
> + st->iio_chan[reg].ext_info = ltc2688_toggle_sym_ext_info;
> + /*
> + * Clear IIO_CHAN_INFO_RAW bit as toggle channels expose
> + * out_voltage_raw{0|1} files.
> + */
> + clear_bit(IIO_CHAN_INFO_RAW,
> + &st->iio_chan[reg].info_mask_separate);
Do you need atomic operation here?
> + }
> +
> + ret = of_property_read_u32_array(child, "adi,output-range-microvolt",
> + tmp, ARRAY_SIZE(tmp));
> + if (!ret) {
> + span = ltc2688_span_lookup(st, (int)tmp[0] / 1000,
> + tmp[1] / 1000);
> + if (span < 0) {
> + of_node_put(child);
> + return dev_err_probe(dev, -EINVAL,
> + "output range not valid:[%d %d]\n",
> + tmp[0], tmp[1]);
> + }
> +
> + val |= FIELD_PREP(LTC2688_CH_SPAN_MSK, span);
> + }
> +
> + ret = of_property_read_u32(child, "adi,toggle-dither-input",
> + &clk_input);
> + if (!ret) {
> + if (clk_input >= LTC2688_CH_TGP_MAX) {
> + of_node_put(child);
> + return dev_err_probe(dev, -EINVAL,
> + "toggle-dither-input inv value(%d)\n",
> + clk_input);
> + }
> +
> + ret = ltc2688_tgp_clk_setup(st, chan, child, clk_input);
> + if (ret) {
> + of_node_put(child);
> + return ret;
> + }
> +
> + /*
> + * 0 means software toggle which is the default mode.
> + * Hence the +1.
> + */
> + val |= FIELD_PREP(LTC2688_CH_TD_SEL_MSK, clk_input + 1);
> +
> + /*
> + * If a TGPx is given, we automatically assume a dither
> + * capable channel (unless toggle is already enabled).
> + * On top of this we just set here the dither bit in the
> + * channel settings. It won't have any effect until the
> + * global toggle/dither bit is enabled.
> + */
> + if (!chan->toggle_chan) {
> + val |= FIELD_PREP(LTC2688_CH_MODE_MSK, 1);
> + st->iio_chan[reg].ext_info = ltc2688_dither_ext_info;
> + } else {
> + /* wait, no sw toggle after all */
> + st->iio_chan[reg].ext_info = ltc2688_toggle_ext_info;
> + }
> + }
> +
> + if (of_property_read_bool(child, "adi,overrange")) {
> + chan->overrange = true;
> + val |= LTC2688_CH_OVERRANGE_MSK;
> + }
> +
> + if (!val)
> + continue;
> +
> + ret = regmap_write(st->regmap, LTC2688_CMD_CH_SETTING(reg),
> + val);
> + if (ret) {
> + of_node_put(child);
> + return dev_err_probe(dev, -EINVAL,
> + "failed to set chan settings\n");
> + }
> + }
> +
> + return 0;
> +}
...
> +struct regmap_bus ltc2688_regmap_bus = {
> + .read = ltc2688_spi_read,
> + .write = ltc2688_spi_write,
> + .read_flag_mask = LTC2688_READ_OPERATION,
> + .reg_format_endian_default = REGMAP_ENDIAN_BIG,
> + .val_format_endian_default = REGMAP_ENDIAN_BIG
+ Comma.
> +};
> +
> +static const struct regmap_config ltc2688_regmap_config = {
> + .reg_bits = 8,
> + .val_bits = 16,
> + .readable_reg = ltc2688_reg_readable,
> + .writeable_reg = ltc2688_reg_writable,
> + /* ignoring the no op command */
> + .max_register = LTC2688_CMD_UPDATE_ALL
Ditto.
> +};
...
> + vref_reg = devm_regulator_get_optional(dev, "vref");
> + if (!IS_ERR(vref_reg)) {
Why not positive conditional check (and hence standard pattern -- error
handling first)?
> + ret = regulator_enable(vref_reg);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to enable vref regulators\n");
> +
> + ret = devm_add_action_or_reset(dev, ltc2688_disable_regulator,
> + vref_reg);
> + if (ret)
> + return ret;
> +
> + ret = regulator_get_voltage(vref_reg);
> + if (ret < 0)
> + return dev_err_probe(dev, ret, "Failed to get vref\n");
> +
> + st->vref = ret / 1000;
> + } else {
> + if (PTR_ERR(vref_reg) != -ENODEV)
> + return dev_err_probe(dev, PTR_ERR(vref_reg),
> + "Failed to get vref regulator");
> +
> + vref_reg = NULL;
> + /* internal reference */
> + st->vref = 4096;
> + }
--
With Best Regards,
Andy Shevchenko
next prev parent reply other threads:[~2022-02-05 17:30 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-21 14:24 [PATCH v3 0/3] Add support for LTC2688 Nuno Sá
2022-01-21 14:24 ` [PATCH v3 1/3] iio: dac: add support for ltc2688 Nuno Sá
2022-01-24 9:57 ` [RFC PATCH] iio: dac: ltc2688_regmap_bus can be static kernel test robot
2022-01-24 9:58 ` [PATCH v3 1/3] iio: dac: add support for ltc2688 kernel test robot
2022-02-05 17:29 ` Andy Shevchenko [this message]
2022-02-05 18:44 ` Jonathan Cameron
2022-02-05 18:50 ` Andy Shevchenko
2022-02-05 18:58 ` Andy Shevchenko
2022-02-06 15:16 ` Jonathan Cameron
2022-02-07 10:52 ` Andy Shevchenko
2022-02-06 13:19 ` Sa, Nuno
2022-02-07 11:09 ` Andy Shevchenko
2022-02-07 20:19 ` Nuno Sá
2022-02-14 13:23 ` Nuno Sá
2022-02-14 13:50 ` Andy Shevchenko
2022-02-18 13:40 ` Nuno Sá
2022-02-14 13:49 ` Andy Shevchenko
2022-02-18 13:51 ` Nuno Sá
2022-02-18 16:03 ` Jonathan Cameron
2022-02-20 11:32 ` Andy Shevchenko
2022-02-21 12:48 ` Nuno Sá
2022-02-21 17:04 ` Andy Shevchenko
2022-02-21 17:30 ` Jonathan Cameron
2022-02-21 18:49 ` Andy Shevchenko
2022-02-22 16:21 ` Jonathan Cameron
2022-02-19 12:57 ` Nuno Sá
2022-01-21 14:25 ` [PATCH v3 2/3] iio: ABI: add ABI file for the LTC2688 DAC Nuno Sá
2022-02-05 16:25 ` Andy Shevchenko
2022-01-21 14:25 ` [PATCH v3 3/3] dt-bindings: iio: Add ltc2688 documentation Nuno Sá
2022-02-05 2:28 ` Rob Herring
2022-01-22 17:27 ` [PATCH v3 0/3] Add support for LTC2688 Jonathan Cameron
2022-02-05 16:24 ` Andy Shevchenko
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=Yf60A1UkbBtQ68qv@smile.fi.intel.com \
--to=andriy.shevchenko@intel.com \
--cc=Michael.Hennerich@analog.com \
--cc=devicetree@vger.kernel.org \
--cc=jic23@kernel.org \
--cc=lars@metafoo.de \
--cc=linux-iio@vger.kernel.org \
--cc=nuno.sa@analog.com \
--cc=robh+dt@kernel.org \
/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.