mbox series

[v3,0/3] Add support for LTC2688

Message ID 20220121142501.151-1-nuno.sa@analog.com
Headers show
Series Add support for LTC2688 | expand

Message

Nuno Sa Jan. 21, 2022, 2:24 p.m. UTC
The ABI defined for this driver has some subtleties that were previously
discussed in this RFC [1]. This might not be the final state but,
hopefully, we are close to it:

toggle mode channels:

 * out_voltageY_toggle_en
 * out_voltageY_raw0
 * out_voltageY_raw1
 * out_voltageY_symbol

dither mode channels:

 * out_voltageY_dither_en
 * out_voltageY_dither_raw
 * out_voltageY_dither_raw_available
 * out_voltageY_dither_offset
 * out_voltageY_dither_frequency
 * out_voltageY_dither_frequency_available
 * out_voltageY_dither_phase
 * out_voltageY_dither_phase_available

Default channels won't have any of the above ABIs. A channel is toggle
capable if the devicetree 'adi,toggle-mode' flag is set. For dither, the
assumption is more silent. If 'adi,toggle-mode' is not given and a
channel is associated with a TGPx pin through 'adi,toggle-dither-input',
then the channel is assumed to be dither capable (there's no point in
having a dither capable channel without an input clock).

changes in v2:

 ltc2688:
  * Use local buffer for regmap read. Do not assume that reg is part of
larger buffer;
  * Renamed GPIO to "clr" so that is consistent with the datasheet;
  * Renamed 'mask' and 'm' to info. 'mask' is a thing from the past;
  * Removed 'LTC2688_CHAN_TOGGLE()' and defined to static ext_info arrays;
  * Use 'regmap_set_bits' to set external ref;
  * Use FIELD_{PREP|GET} for dither amplitude and channel calibbias where
only 13bits are used;
  * Use 'regmap_write()' instead of update_bits for channels settings;
  * Init 'val' at the beginning of the channel configuration loop
(and drop mask);
  * Comment 'ltc2688_reg_writable()' to account for the special condition;
  * Kmemdup default channels so that it can be safely changed per probed
device;
  * Replace extended info multiplexer functions by individual functions;
  * Use raw0 ABI for toggle channels;
  * Use dedicated offset ABI for dither channels;
  * Misc changes (spell fixes, blank lines...);
  * Have a clock property per channel. Note that we this I moved to OF
since we now have to use 'devm_get_clk_from_child()' which is using
device_node. Note that I could use 'to_of_node()' but mixing of.h and
property.h does not feel like a good idea.

 ABI:
  * Added out_voltageY_raw0 ABI for toggle mode;
  * Added out_voltageY_dither_offset.

 Bindings:
  * Use standard microvolt unit;
  * Added constrains for adi,output-range-microvolt and removed negative
values from the dts example;
  * Moved clocks to the channel object;
  * Dropped clock-names;
  * Add a dependency between 'adi,toggle-dither-input' and 'clocks'.

Changes in v3:

 ltc2688:
  * Fix mismatch between functions and function pointers detected by kernel
test bot; 
  * Always use if (ret) when ret > 0 has no meaning;
  * Rename ltc2688_bulk_disable -> ltc2688_disable_regulators;
  * Report dither phase in radians rather than degrees.

 ABI:
  * Specify units for dither_phase and dither_freqency; 
  * Say why its useful to have dither_en and toggle_en;
  * Combine out_voltageY_raw0 and out_voltageY_raw1;
  * Fix some description issues in out_voltageY_raw{0|1} and
out_voltageY_symbol.

 Bindings:
  * Remove mentions to ABI (linux specifix);
  * Slightly rephrased VREF and adi,toggle-dither-input properties and
suggested.
   
[1]: https://marc.info/?l=linux-iio&m=163662843603265&w=2

Nuno Sá (3):
  iio: dac: add support for ltc2688
  iio: ABI: add ABI file for the LTC2688 DAC
  dt-bindings: iio: Add ltc2688 documentation

 .../ABI/testing/sysfs-bus-iio-dac-ltc2688     |   86 ++
 .../bindings/iio/dac/adi,ltc2688.yaml         |  146 +++
 MAINTAINERS                                   |    9 +
 drivers/iio/dac/Kconfig                       |   11 +
 drivers/iio/dac/Makefile                      |    1 +
 drivers/iio/dac/ltc2688.c                     | 1070 +++++++++++++++++
 6 files changed, 1323 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688
 create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml
 create mode 100644 drivers/iio/dac/ltc2688.c

Comments

Jonathan Cameron Jan. 22, 2022, 5:27 p.m. UTC | #1
On Fri, 21 Jan 2022 15:24:58 +0100
Nuno Sá <nuno.sa@analog.com> wrote:

> The ABI defined for this driver has some subtleties that were previously
> discussed in this RFC [1]. This might not be the final state but,
> hopefully, we are close to it:
> 
> toggle mode channels:
> 
>  * out_voltageY_toggle_en
>  * out_voltageY_raw0
>  * out_voltageY_raw1
>  * out_voltageY_symbol
> 
> dither mode channels:
> 
>  * out_voltageY_dither_en
>  * out_voltageY_dither_raw
>  * out_voltageY_dither_raw_available
>  * out_voltageY_dither_offset
>  * out_voltageY_dither_frequency
>  * out_voltageY_dither_frequency_available
>  * out_voltageY_dither_phase
>  * out_voltageY_dither_phase_available
> 
> Default channels won't have any of the above ABIs. A channel is toggle
> capable if the devicetree 'adi,toggle-mode' flag is set. For dither, the
> assumption is more silent. If 'adi,toggle-mode' is not given and a
> channel is associated with a TGPx pin through 'adi,toggle-dither-input',
> then the channel is assumed to be dither capable (there's no point in
> having a dither capable channel without an input clock).
> 
> changes in v2:
> 
>  ltc2688:
>   * Use local buffer for regmap read. Do not assume that reg is part of
> larger buffer;
>   * Renamed GPIO to "clr" so that is consistent with the datasheet;
>   * Renamed 'mask' and 'm' to info. 'mask' is a thing from the past;
>   * Removed 'LTC2688_CHAN_TOGGLE()' and defined to static ext_info arrays;
>   * Use 'regmap_set_bits' to set external ref;
>   * Use FIELD_{PREP|GET} for dither amplitude and channel calibbias where
> only 13bits are used;
>   * Use 'regmap_write()' instead of update_bits for channels settings;
>   * Init 'val' at the beginning of the channel configuration loop
> (and drop mask);
>   * Comment 'ltc2688_reg_writable()' to account for the special condition;
>   * Kmemdup default channels so that it can be safely changed per probed
> device;
>   * Replace extended info multiplexer functions by individual functions;
>   * Use raw0 ABI for toggle channels;
>   * Use dedicated offset ABI for dither channels;
>   * Misc changes (spell fixes, blank lines...);
>   * Have a clock property per channel. Note that we this I moved to OF
> since we now have to use 'devm_get_clk_from_child()' which is using
> device_node. Note that I could use 'to_of_node()' but mixing of.h and
> property.h does not feel like a good idea.
> 
>  ABI:
>   * Added out_voltageY_raw0 ABI for toggle mode;
>   * Added out_voltageY_dither_offset.
> 
>  Bindings:
>   * Use standard microvolt unit;
>   * Added constrains for adi,output-range-microvolt and removed negative
> values from the dts example;
>   * Moved clocks to the channel object;
>   * Dropped clock-names;
>   * Add a dependency between 'adi,toggle-dither-input' and 'clocks'.
> 
> Changes in v3:
> 
>  ltc2688:
>   * Fix mismatch between functions and function pointers detected by kernel
> test bot; 
>   * Always use if (ret) when ret > 0 has no meaning;
>   * Rename ltc2688_bulk_disable -> ltc2688_disable_regulators;
>   * Report dither phase in radians rather than degrees.
> 
>  ABI:
>   * Specify units for dither_phase and dither_freqency; 
>   * Say why its useful to have dither_en and toggle_en;
>   * Combine out_voltageY_raw0 and out_voltageY_raw1;
>   * Fix some description issues in out_voltageY_raw{0|1} and
> out_voltageY_symbol.
> 
>  Bindings:
>   * Remove mentions to ABI (linux specifix);
>   * Slightly rephrased VREF and adi,toggle-dither-input properties and
> suggested.
>    
> [1]: https://marc.info/?l=linux-iio&m=163662843603265&w=2

Series looks good to me, but will have to wait a little longer for DT and
any other review before I apply it.

Thanks,

Jonathan

> 
> Nuno Sá (3):
>   iio: dac: add support for ltc2688
>   iio: ABI: add ABI file for the LTC2688 DAC
>   dt-bindings: iio: Add ltc2688 documentation
> 
>  .../ABI/testing/sysfs-bus-iio-dac-ltc2688     |   86 ++
>  .../bindings/iio/dac/adi,ltc2688.yaml         |  146 +++
>  MAINTAINERS                                   |    9 +
>  drivers/iio/dac/Kconfig                       |   11 +
>  drivers/iio/dac/Makefile                      |    1 +
>  drivers/iio/dac/ltc2688.c                     | 1070 +++++++++++++++++
>  6 files changed, 1323 insertions(+)
>  create mode 100644 Documentation/ABI/testing/sysfs-bus-iio-dac-ltc2688
>  create mode 100644 Documentation/devicetree/bindings/iio/dac/adi,ltc2688.yaml
>  create mode 100644 drivers/iio/dac/ltc2688.c
>
Andy Shevchenko Feb. 5, 2022, 4:24 p.m. UTC | #2
On Sat, Jan 22, 2022 at 05:27:06PM +0000, Jonathan Cameron wrote:
> On Fri, 21 Jan 2022 15:24:58 +0100
> Nuno Sá <nuno.sa@analog.com> wrote:

...

> Series looks good to me, but will have to wait a little longer for DT and
> any other review before I apply it.

Thanks! I have comments.
Andy Shevchenko Feb. 5, 2022, 4:25 p.m. UTC | #3
On Fri, Jan 21, 2022 at 03:25:00PM +0100, Nuno Sá wrote:
> Define the sysfs interface for toggle or dither capable channels. Dither
> capable channels will have the extended interface:
> 
>  * out_voltageY_dither_en
>  * out_voltageY_dither_raw
>  * out_voltageY_dither_offset
>  * out_voltageY_dither_raw_available
>  * out_voltageY_dither_frequency
>  * out_voltageY_dither_frequency_available
>  * out_voltageY_dither_phase
>  * out_voltageY_dither_phase_available
> 
> Toggle enabled channels will have:
> 
>  * out_voltageY_toggle_en
>  * out_voltageY_raw0
>  * out_voltageY_raw1
>  * out_voltageY_symbol
> 
> The common interface present in all channels is:
> 
>  * out_voltageY_raw (not present in toggle enabled channels)
>  * out_voltageY_raw_available
>  * out_voltageY_powerdown
>  * out_voltageY_scale
>  * out_voltageY_offset
>  * out_voltageY_calibbias
>  * out_voltageY_calibscale

...

> +KernelVersion:	5.17

v5.17 alredy gone for new features.
Andy Shevchenko Feb. 5, 2022, 5:29 p.m. UTC | #4
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", &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;
> +	}
Jonathan Cameron Feb. 5, 2022, 6:44 p.m. UTC | #5
On Sat, 5 Feb 2022 19:29:39 +0200
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:

A few comments from me, mostly because I couldn't resist jumping in ;)
Note this is only some of the things Andy raised....

Jonathan

> 
> > +	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.

https://elixir.bootlin.com/linux/latest/source/Documentation/ABI/testing/sysfs-bus-iio#L105
Yes, [Min Step Max]

> 
> > +	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.

Different sysfs nodes.  Though it's a fair question on whether this would be
better done as a bunch of separate callbacks, rather than one with a lookup
on the private parameter.


> 
> > +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(...);
> 	}

Interesting.  We should probably look at where else this
is appropriate.

> 
> > +		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()

This is the old issue with missing
device_for_each_available_child_node()
though can just add a check on whether it's available inside the loop.
> 
> > +		struct ltc2688_chan *chan;
> > +

...
Andy Shevchenko Feb. 5, 2022, 6:50 p.m. UTC | #6
On Sat, Feb 05, 2022 at 06:44:59PM +0000, Jonathan Cameron wrote:
> On Sat, 5 Feb 2022 19:29:39 +0200
> Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> 
> A few comments from me, mostly because I couldn't resist jumping in ;)
> Note this is only some of the things Andy raised....

...

> > > +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()
> 
> This is the old issue with missing
> device_for_each_available_child_node()
> though can just add a check on whether it's available inside the loop.

Didn't we discuss this with Rob and he told that device_for_each_child_node()
is already for available only?

> > > +		struct ltc2688_chan *chan;
> > > +
Andy Shevchenko Feb. 5, 2022, 6:58 p.m. UTC | #7
On Sat, Feb 05, 2022 at 08:50:31PM +0200, Andy Shevchenko wrote:
> On Sat, Feb 05, 2022 at 06:44:59PM +0000, Jonathan Cameron wrote:
> > On Sat, 5 Feb 2022 19:29:39 +0200
> > Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> > 
> > A few comments from me, mostly because I couldn't resist jumping in ;)
> > Note this is only some of the things Andy raised....
> 
> ...
> 
> > > > +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()
> > 
> > This is the old issue with missing
> > device_for_each_available_child_node()
> > though can just add a check on whether it's available inside the loop.
> 
> Didn't we discuss this with Rob and he told that device_for_each_child_node()
> is already for available only?

https://lore.kernel.org/lkml/20211205190101.26de4a57@jic23-huawei/T/#u

So, the fwnode has a correct implementation, and we may use it here.
Nuno Sa Feb. 6, 2022, 1:19 p.m. UTC | #8
> From: Andy Shevchenko <andriy.shevchenko@intel.com>
> Sent: Saturday, February 5, 2022 6:30 PM
> To: Sa, Nuno <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>;
> Hennerich, Michael <Michael.Hennerich@analog.com>
> Subject: Re: [PATCH v3 1/3] iio: dac: add support for ltc2688
> 
> [External]
> 
> 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/

That probably means property and of both included. See below in the
clock_get comments...

> ...
> 
> > +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?

Well, reg_size is 1 byte and val_size is 2 as defined in the regmap_bus
struct. And that is what it must be used for the transfer to work. I 
could also hardcode 1 and 2 but I preferred to use the parameters. I guess
you can argue (and probably this is why you are complaining about this)
for me to use reg_size + val_size in the transfer length for consistency.
That's fair but I do not think this is __that__ bad... Can make that change
though.

> Second, why do you need this specific function instead of regmap bulk
> ops against be24/le24?
>

Not sure I'm following this one... If you mean why am I using a custom 
regmap_bus implementation, that was already explained in the RFC patch.
And IIRC, you were the one already asking 😉.
 
> ...
> 
> > +unlock:
> 
> out_unlock: ?
> (And in similar cases)

Well, why not? can do that...

> ...
> 
> > +	if (ret)
> > +		return ret;
> > +
> > +	return len;
> 
> In some cases the return ret ?: len; is used, in some like above. Maybe
> a bit
> of consistency?

That's fair... At this point, I will go with the one that evolves less changes
unless noted otherwise.
 
> ...
> 
> > +	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?

Well, I never really saw any enforcement here to be honest (rather than using
stdint types...). So I pretty much just use these in unsigned types because
I'm lazy and u16 is faster to type than unsigned short... In this case, unless Jonathan
really asks for it, I prefer not to go all over the driver and change this...

> ...
> 
> > +	.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");

Well, I might be missing the point but I think this is not so straight....
We will only get here if the property " adi,toggle-dither-input" is given
in which case having the associated clocks is __mandatory__. Hence,
once we are here, this can never be optional. That said, we need
device_node and hence of.h to be included and this was the main reason
why I changed from property.h to of.h (once I started to use
'devm_get_clk_from_child()'. I don’t really think that using both of and
property is a good idea and I raised this in the previous version of this series
and no one made it clear that using both of and property would be acceptable
so I kept my move to of in the current version. 

> > +	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", &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?

Not really, but I still prefer to use 'clear_bit()' rather than doing it
by hand... Is there another utility for this?

> > +		}
> > +
> > +		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)?
> 

No reason.. I can flip the logic...

- Nuno Sá
Jonathan Cameron Feb. 6, 2022, 3:16 p.m. UTC | #9
On Sat, 5 Feb 2022 20:58:12 +0200
Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:

> On Sat, Feb 05, 2022 at 08:50:31PM +0200, Andy Shevchenko wrote:
> > On Sat, Feb 05, 2022 at 06:44:59PM +0000, Jonathan Cameron wrote:  
> > > On Sat, 5 Feb 2022 19:29:39 +0200
> > > Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> > > 
> > > A few comments from me, mostly because I couldn't resist jumping in ;)
> > > Note this is only some of the things Andy raised....  
> > 
> > ...
> >   
> > > > > +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()  
> > > 
> > > This is the old issue with missing
> > > device_for_each_available_child_node()
> > > though can just add a check on whether it's available inside the loop.  
> > 
> > Didn't we discuss this with Rob and he told that device_for_each_child_node()
> > is already for available only?  
> 
> https://lore.kernel.org/lkml/20211205190101.26de4a57@jic23-huawei/T/#u
> 
> So, the fwnode has a correct implementation, and we may use it here.
> 
I wasn't totally sure of the conclusion of that discussion.
a) Fine to just use device_for_each_child_node() for this case and not worry about it.
b) Worth adding device_for_each_available_child_node() with the same implementation
c) (possibly workaround / avoid the issue) Use device_for_each_child_node() but also
check validity (hopefully compiler would remove the check) in order to act
as documentation.

I'm fine with any of the above.

J
Andy Shevchenko Feb. 7, 2022, 10:52 a.m. UTC | #10
On Sun, Feb 06, 2022 at 03:16:24PM +0000, Jonathan Cameron wrote:
> On Sat, 5 Feb 2022 20:58:12 +0200
> Andy Shevchenko <andriy.shevchenko@linux.intel.com> wrote:
> > On Sat, Feb 05, 2022 at 08:50:31PM +0200, Andy Shevchenko wrote:

...

> > https://lore.kernel.org/lkml/20211205190101.26de4a57@jic23-huawei/T/#u
> > 
> > So, the fwnode has a correct implementation, and we may use it here.
> > 
> I wasn't totally sure of the conclusion of that discussion.
> a) Fine to just use device_for_each_child_node() for this case and not worry
> about it.

Yes. As he mentioned the device_for_each_child_node() is implemented correctly
from day 1.

> b) Worth adding device_for_each_available_child_node() with the same
> implementation

I believe it's an opposite prospective, i.e. drop
of_for_each_available_child_node() and use the of_for_each_child_node()
everywhere.

> c) (possibly workaround / avoid the issue) Use device_for_each_child_node()
> but also check validity (hopefully compiler would remove the check)
> in order to act as documentation.

Makes no sense because implementation does it already.

> I'm fine with any of the above.
Andy Shevchenko Feb. 7, 2022, 11:09 a.m. UTC | #11
On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > Sent: Saturday, February 5, 2022 6:30 PM
> > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:

...

> > > +#include <linux/of.h>
> > 
> > property.h please/
> 
> That probably means property and of both included. See below in the
> clock_get comments...

Why? OF won't be used at all.

...

> > > +	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?
> 
> Well, reg_size is 1 byte and val_size is 2 as defined in the regmap_bus
> struct. And that is what it must be used for the transfer to work. I 
> could also hardcode 1 and 2 but I preferred to use the parameters. I guess
> you can argue (and probably this is why you are complaining about this)
> for me to use reg_size + val_size in the transfer length for consistency.
> That's fair but I do not think this is __that__ bad...

It's not bad, but I think that division between register and value is a good
thing to have.

> Can make that change though.

Would be nice!

...

> > Second, why do you need this specific function instead of regmap bulk
> > ops against be24/le24?
> 
> Not sure I'm following this one... If you mean why am I using a custom 
> regmap_bus implementation, that was already explained in the RFC patch.
> And IIRC, you were the one already asking 😉.

Hmm... It was some time I have looked there. Any message ID to share, so
I can find it quickly?

...

> > > +	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?
> 
> Well, I never really saw any enforcement here to be honest (rather than using
> stdint types...). So I pretty much just use these in unsigned types because
> I'm lazy and u16 is faster to type than unsigned short... In this case, unless Jonathan
> really asks for it, I prefer not to go all over the driver and change this...

This is about consistency. It may work as is, but it feels not good when for
int (or unsigned int) one uses fixed-width types. Also it's non-written advice
to use fixed-width variables when it's about programming registers or so, for
the rest, use POD types.

...

> > > +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");
> 
> Well, I might be missing the point but I think this is not so straight....
> We will only get here if the property " adi,toggle-dither-input" is given
> in which case having the associated clocks is __mandatory__.

Ah, okay, would be a limitation for non-OF platforms.

> Hence,
> once we are here, this can never be optional. That said, we need
> device_node 

That's fine, since CCF is OF-centric API.

> and hence of.h

Why? This header doesn't bring anything you will use here.

> to be included and this was the main reason
> why I changed from property.h to of.h (once I started to use
> 'devm_get_clk_from_child()'. I don’t really think that using both of and
> property is a good idea and I raised this in the previous version of this series
> and no one made it clear that using both of and property would be acceptable
> so I kept my move to of in the current version.

It's a good idea for sensors to be able to use them outside of OF platforms.
CCF is PITA, but at least with the conversion to device property API, this
become the only one (and it has a few possible workarounds).

> > > +	ret = clk_prepare_enable(clk);
> > > +	if (ret)
> > > +		return dev_err_probe(&st->spi->dev, ret,
> > > +				     "failed to enable tgp clk.\n");

...

> > > +			clear_bit(IIO_CHAN_INFO_RAW,
> > > +				  &st-
> > >iio_chan[reg].info_mask_separate);
> > 
> > Do you need atomic operation here?
> 
> Not really, but I still prefer to use 'clear_bit()' rather than doing it
> by hand... Is there another utility for this?

__clear_bit().
Nuno Sá Feb. 7, 2022, 8:19 p.m. UTC | #12
On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > Sent: Saturday, February 5, 2022 6:30 PM
> > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:
> 
> ...
> 
> > > > +#include <linux/of.h>
> > > 
> > > property.h please/
> > 
> > That probably means property and of both included. See below in the
> > clock_get comments...
> 
> Why? OF won't be used at all.
> 
see below on the clock function...
> 
> ...
> 
> > > > +       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?
> > 
> > Well, reg_size is 1 byte and val_size is 2 as defined in the
> > regmap_bus
> > struct. And that is what it must be used for the transfer to work.
> > I 
> > could also hardcode 1 and 2 but I preferred to use the parameters.
> > I guess
> > you can argue (and probably this is why you are complaining about
> > this)
> > for me to use reg_size + val_size in the transfer length for
> > consistency.
> > That's fair but I do not think this is __that__ bad...
> 
> It's not bad, but I think that division between register and value is
> a good
> thing to have.
> 
> > Can make that change though.
> 
> Would be nice!
> 
> ...
> 
> > > Second, why do you need this specific function instead of regmap
> > > bulk
> > > ops against be24/le24?
> > 
> > Not sure I'm following this one... If you mean why am I using a
> > custom 
> > regmap_bus implementation, that was already explained in the RFC
> > patch.
> > And IIRC, you were the one already asking 😉.
> 
> Hmm... It was some time I have looked there. Any message ID to share,
> so
> I can find it quickly?
> 

https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/

> ...
> 
> > > > +       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?
> > 
> > Well, I never really saw any enforcement here to be honest (rather
> > than using
> > stdint types...). So I pretty much just use these in unsigned types
> > because
> > I'm lazy and u16 is faster to type than unsigned short... In this
> > case, unless Jonathan
> > really asks for it, I prefer not to go all over the driver and
> > change this...
> 
> This is about consistency. It may work as is, but it feels not good
> when for
> int (or unsigned int) one uses fixed-width types. Also it's non-
> written advice
> to use fixed-width variables when it's about programming registers or
> so, for
> the rest, use POD types.
> 
> ...

I can understand your reasoning but again this is something that
I never really saw being enforced. So, I'm more than ok to change it
if it really becomes something that we will try to "enforce" in IIO.
Otherwise it just feels as a random nitpick :).

> 
> > > > +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");
> > 
> > Well, I might be missing the point but I think this is not so
> > straight....
> > We will only get here if the property " adi,toggle-dither-input" is
> > given
> > in which case having the associated clocks is __mandatory__.
> 
> Ah, okay, would be a limitation for non-OF platforms.
> 
> > Hence,
> > once we are here, this can never be optional. That said, we need
> > device_node 
> 
> That's fine, since CCF is OF-centric API.
> 
> > and hence of.h
> 
> Why? This header doesn't bring anything you will use here.

Correct me if Im missing something. AFAIU, the idea is to use
'device_for_each_child_node()' which returns a fwnode_handle. That
means, that we will have to pass that to this function and use
'to_of_node()' to pass a device_node to 'devm_get_clk_from_child()'.

This means, we need of.h for 'to_of_node()'...


- Nuno Sá
Nuno Sá Feb. 14, 2022, 1:23 p.m. UTC | #13
On Mon, 2022-02-07 at 21:19 +0100, Nuno Sá wrote:
> On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:
> > 
> > ...
> > 
> > > > > +#include <linux/of.h>
> > > > 
> > > > property.h please/
> > > 
> > > That probably means property and of both included. See below in
> > > the
> > > clock_get comments...
> > 
> > Why? OF won't be used at all.
> > 
> see below on the clock function...
> > 
> > ...
> > 
> > > > > +       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?
> > > 
> > > Well, reg_size is 1 byte and val_size is 2 as defined in the
> > > regmap_bus
> > > struct. And that is what it must be used for the transfer to
> > > work.
> > > I 
> > > could also hardcode 1 and 2 but I preferred to use the
> > > parameters.
> > > I guess
> > > you can argue (and probably this is why you are complaining about
> > > this)
> > > for me to use reg_size + val_size in the transfer length for
> > > consistency.
> > > That's fair but I do not think this is __that__ bad...
> > 
> > It's not bad, but I think that division between register and value
> > is
> > a good
> > thing to have.
> > 
> > > Can make that change though.
> > 
> > Would be nice!
> > 
> > ...
> > 
> > > > Second, why do you need this specific function instead of
> > > > regmap
> > > > bulk
> > > > ops against be24/le24?
> > > 
> > > Not sure I'm following this one... If you mean why am I using a
> > > custom 
> > > regmap_bus implementation, that was already explained in the RFC
> > > patch.
> > > And IIRC, you were the one already asking 😉.
> > 
> > Hmm... It was some time I have looked there. Any message ID to
> > share,
> > so
> > I can find it quickly?
> > 
> 
> https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/
> 
> > ...
> > 
> > > > > +       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?
> > > 
> > > Well, I never really saw any enforcement here to be honest
> > > (rather
> > > than using
> > > stdint types...). So I pretty much just use these in unsigned
> > > types
> > > because
> > > I'm lazy and u16 is faster to type than unsigned short... In this
> > > case, unless Jonathan
> > > really asks for it, I prefer not to go all over the driver and
> > > change this...
> > 
> > This is about consistency. It may work as is, but it feels not good
> > when for
> > int (or unsigned int) one uses fixed-width types. Also it's non-
> > written advice
> > to use fixed-width variables when it's about programming registers
> > or
> > so, for
> > the rest, use POD types.
> > 
> > ...
> 
> I can understand your reasoning but again this is something that
> I never really saw being enforced. So, I'm more than ok to change it
> if it really becomes something that we will try to "enforce" in IIO.
> Otherwise it just feels as a random nitpick :).
> 
> > 
> > > > > +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");
> > > 
> > > Well, I might be missing the point but I think this is not so
> > > straight....
> > > We will only get here if the property " adi,toggle-dither-input"
> > > is
> > > given
> > > in which case having the associated clocks is __mandatory__.
> > 
> > Ah, okay, would be a limitation for non-OF platforms.
> > 
> > > Hence,
> > > once we are here, this can never be optional. That said, we need
> > > device_node 
> > 
> > That's fine, since CCF is OF-centric API.
> > 
> > > and hence of.h
> > 
> > Why? This header doesn't bring anything you will use here.
> 
> Correct me if Im missing something. AFAIU, the idea is to use
> 'device_for_each_child_node()' which returns a fwnode_handle. That
> means, that we will have to pass that to this function and use
> 'to_of_node()' to pass a device_node to 'devm_get_clk_from_child()'.
> 
> This means, we need of.h for 'to_of_node()'...
> 
> 

Andy, Jonathan,

I would definetly like to have some settlement on the above (before
sending a v4). It kind of was discussed a bit already in [1] where I
felt we had to live with OF for this driver (that is why I kept OF in
v3. With the above, I cannot
really see how we can have device API with also including OF... If I
missing something please let me know :)


[1]: https://lore.kernel.org/all/CAHp75VczFs8QpsY7tuB-h4X=H54nyjABA4qDSmpQ+FRYAHZdrA@mail.gmail.com/
- Nuno Sá
Andy Shevchenko Feb. 14, 2022, 1:49 p.m. UTC | #14
On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:
> On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:

...

> > > > Second, why do you need this specific function instead of regmap
> > > > bulk
> > > > ops against be24/le24?
> > > 
> > > Not sure I'm following this one... If you mean why am I using a
> > > custom 
> > > regmap_bus implementation, that was already explained in the RFC
> > > patch.
> > > And IIRC, you were the one already asking 😉.
> > 
> > Hmm... It was some time I have looked there. Any message ID to share,
> > so
> > I can find it quickly?

> https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/

Thanks!

So, it's all about cs_change, right?
But doesn't bulk operation work exactly as we need here?

Looking again to the RFC code, it seems like we can still do it

First, you call _gather_write() followed by _read(). It will show exactly what
you do, i.e. you send command first with the value 0x0000, followed by sending
command and reading back the value at the same time.

Would it work?

...

> > > > > +       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?
> > > 
> > > Well, I never really saw any enforcement here to be honest (rather
> > > than using
> > > stdint types...). So I pretty much just use these in unsigned types
> > > because
> > > I'm lazy and u16 is faster to type than unsigned short... In this
> > > case, unless Jonathan
> > > really asks for it, I prefer not to go all over the driver and
> > > change this...
> > 
> > This is about consistency. It may work as is, but it feels not good
> > when for
> > int (or unsigned int) one uses fixed-width types. Also it's non-
> > written advice
> > to use fixed-width variables when it's about programming registers or
> > so, for
> > the rest, use POD types.

> I can understand your reasoning but again this is something that
> I never really saw being enforced. So, I'm more than ok to change it
> if it really becomes something that we will try to "enforce" in IIO.
> Otherwise it just feels as a random nitpick :).

No, this is about consistency and common sense. If you define type uXX,
we have an API for that exact type. It's confusing why POD type APIs
are used with fixed-width types or vise versa.

Moreover (which is pure theoretical, though) some architectures might
have no (mutual) equivalency between these types.

...

> > > > > +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");
> > > 
> > > Well, I might be missing the point but I think this is not so
> > > straight....
> > > We will only get here if the property " adi,toggle-dither-input" is
> > > given
> > > in which case having the associated clocks is __mandatory__.
> > 
> > Ah, okay, would be a limitation for non-OF platforms.
> > 
> > > Hence,
> > > once we are here, this can never be optional. That said, we need
> > > device_node 
> > 
> > That's fine, since CCF is OF-centric API.
> > 
> > > and hence of.h
> > 
> > Why? This header doesn't bring anything you will use here.
> 
> Correct me if Im missing something. AFAIU, the idea is to use
> 'device_for_each_child_node()' which returns a fwnode_handle. That
> means, that we will have to pass that to this function and use
> 'to_of_node()' to pass a device_node to 'devm_get_clk_from_child()'.
> 
> This means, we need of.h for 'to_of_node()'...

Yeah, you are right, but it would be still better since it narrows
the problem to the CCF calls only.
Andy Shevchenko Feb. 14, 2022, 1:50 p.m. UTC | #15
On Mon, Feb 14, 2022 at 02:23:01PM +0100, Nuno Sá wrote:
> On Mon, 2022-02-07 at 21:19 +0100, Nuno Sá wrote:

> I would definetly like to have some settlement on the above (before
> sending a v4). It kind of was discussed a bit already in [1] where I
> felt we had to live with OF for this driver (that is why I kept OF in
> v3. With the above, I cannot
> really see how we can have device API with also including OF... If I
> missing something please let me know :)

Sorry for the delay, answered to your previous message.

> [1]: https://lore.kernel.org/all/CAHp75VczFs8QpsY7tuB-h4X=H54nyjABA4qDSmpQ+FRYAHZdrA@mail.gmail.com/
Nuno Sá Feb. 18, 2022, 1:40 p.m. UTC | #16
On Mon, 2022-02-14 at 15:50 +0200, Andy Shevchenko wrote:
> On Mon, Feb 14, 2022 at 02:23:01PM +0100, Nuno Sá wrote:
> > On Mon, 2022-02-07 at 21:19 +0100, Nuno Sá wrote:
> 
> > I would definetly like to have some settlement on the above (before
> > sending a v4). It kind of was discussed a bit already in [1] where
> > I
> > felt we had to live with OF for this driver (that is why I kept OF
> > in
> > v3. With the above, I cannot
> > really see how we can have device API with also including OF... If
> > I
> > missing something please let me know :)
> 
> Sorry for the delay, answered to your previous message.

No worries. As I already said, I'm not doing much till the end of the
month but I definetly wanted the device vs OF question settled before
starting v4.

- Nuno Sá
>
Nuno Sá Feb. 18, 2022, 1:51 p.m. UTC | #17
On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:
> On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:
> > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:
> 
> ...
> 
> > > > > Second, why do you need this specific function instead of
> > > > > regmap
> > > > > bulk
> > > > > ops against be24/le24?
> > > > 
> > > > Not sure I'm following this one... If you mean why am I using a
> > > > custom 
> > > > regmap_bus implementation, that was already explained in the
> > > > RFC
> > > > patch.
> > > > And IIRC, you were the one already asking 😉.
> > > 
> > > Hmm... It was some time I have looked there. Any message ID to
> > > share,
> > > so
> > > I can find it quickly?
> 
> > https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/
> 
> Thanks!
> 
> So, it's all about cs_change, right?
> But doesn't bulk operation work exactly as we need here?
> 

Yes... that and we need to send the NOOP command in the second TX
transfer.

> Looking again to the RFC code, it seems like we can still do it
> 
> First, you call _gather_write() followed by _read(). It will show
> exactly what
> you do, i.e. you send command first with the value 0x0000, followed
> by sending
> command and reading back the value at the same time.
> 
> Would it work?

Well, _gather_write() are 2 spi transfers only with TX set. That means
that only on the _read() (which will be another spi_message) we will
ask for the data. Im not really sure this would work being it on a
different message. This would also mean, one extra dummy transfer. To
me that already feels that a custom bus implementation is not a bad
idea...
> 
> ...
> 
> > > > > > +       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?
> > > > 
> > > > Well, I never really saw any enforcement here to be honest
> > > > (rather
> > > > than using
> > > > stdint types...). So I pretty much just use these in unsigned
> > > > types
> > > > because
> > > > I'm lazy and u16 is faster to type than unsigned short... In
> > > > this
> > > > case, unless Jonathan
> > > > really asks for it, I prefer not to go all over the driver and
> > > > change this...
> > > 
> > > This is about consistency. It may work as is, but it feels not
> > > good
> > > when for
> > > int (or unsigned int) one uses fixed-width types. Also it's non-
> > > written advice
> > > to use fixed-width variables when it's about programming
> > > registers or
> > > so, for
> > > the rest, use POD types.
> 

Ok, going a bit back in the discussion, you argued that in one place I
was using long while here u16. Well, in the place I'm using long, that
was on purpose because that value is to be compared against an array of
longs (which has to be long because it depends on CCF rates). I guess I
can als0 use s64, but there is also a reason why long was used.

In the u16 case, we really want to have 2 bytes because I'm going to
use that value to write the dac code which is 2 bytes.

> > I can understand your reasoning but again this is something that
> > I never really saw being enforced. So, I'm more than ok to change
> > it
> > if it really becomes something that we will try to "enforce" in
> > IIO.
> > Otherwise it just feels as a random nitpick :).
> 
> No, this is about consistency and common sense. If you define type
> uXX,
> we have an API for that exact type. It's confusing why POD type APIs
> are used with fixed-width types or vise versa.
> 
> Moreover (which is pure theoretical, though) some architectures might
> have no (mutual) equivalency between these types.
> 
> ...
> 
> > > > > > +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");
> > > > 
> > > > Well, I might be missing the point but I think this is not so
> > > > straight....
> > > > We will only get here if the property " adi,toggle-dither-
> > > > input" is
> > > > given
> > > > in which case having the associated clocks is __mandatory__.
> > > 
> > > Ah, okay, would be a limitation for non-OF platforms.
> > > 
> > > > Hence,
> > > > once we are here, this can never be optional. That said, we
> > > > need
> > > > device_node 
> > > 
> > > That's fine, since CCF is OF-centric API.
> > > 
> > > > and hence of.h
> > > 
> > > Why? This header doesn't bring anything you will use here.
> > 
> > Correct me if Im missing something. AFAIU, the idea is to use
> > 'device_for_each_child_node()' which returns a fwnode_handle. That
> > means, that we will have to pass that to this function and use
> > 'to_of_node()' to pass a device_node to
> > 'devm_get_clk_from_child()'.
> > 
> > This means, we need of.h for 'to_of_node()'...
> 
> Yeah, you are right, but it would be still better since it narrows
> the problem to the CCF calls only.
> 

So, to clear....

In your opinion, you are fine whith using device properties and just
have 'to_of_node()' in this CCF call? I'm fine with it, so if Jonathan
does not have any complain about it, will do like this in v4,

Jonathan, any comment on this one?

- Nuno Sá
Jonathan Cameron Feb. 18, 2022, 4:03 p.m. UTC | #18
On Fri, 18 Feb 2022 14:51:28 +0100
Nuno Sá <noname.nuno@gmail.com> wrote:

> On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:
> > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:  
> > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:  
> > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:  
> > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:  
> > 
> > ...
> >   
> > > > > > Second, why do you need this specific function instead of
> > > > > > regmap
> > > > > > bulk
> > > > > > ops against be24/le24?  
> > > > > 
> > > > > Not sure I'm following this one... If you mean why am I using a
> > > > > custom 
> > > > > regmap_bus implementation, that was already explained in the
> > > > > RFC
> > > > > patch.
> > > > > And IIRC, you were the one already asking 😉.  
> > > > 
> > > > Hmm... It was some time I have looked there. Any message ID to
> > > > share,
> > > > so
> > > > I can find it quickly?  
> >   
> > > https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/  
> > 
> > Thanks!
> > 
> > So, it's all about cs_change, right?
> > But doesn't bulk operation work exactly as we need here?
> >   
> 
> Yes... that and we need to send the NOOP command in the second TX
> transfer.
> 
> > Looking again to the RFC code, it seems like we can still do it
> > 
> > First, you call _gather_write() followed by _read(). It will show
> > exactly what
> > you do, i.e. you send command first with the value 0x0000, followed
> > by sending
> > command and reading back the value at the same time.
> > 
> > Would it work?  
> 
> Well, _gather_write() are 2 spi transfers only with TX set. That means
> that only on the _read() (which will be another spi_message) we will
> ask for the data. Im not really sure this would work being it on a
> different message. This would also mean, one extra dummy transfer. To
> me that already feels that a custom bus implementation is not a bad
> idea...
> > 
> > ...
> >   
> > > > > > > +       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?  
> > > > > 
> > > > > Well, I never really saw any enforcement here to be honest
> > > > > (rather
> > > > > than using
> > > > > stdint types...). So I pretty much just use these in unsigned
> > > > > types
> > > > > because
> > > > > I'm lazy and u16 is faster to type than unsigned short... In
> > > > > this
> > > > > case, unless Jonathan
> > > > > really asks for it, I prefer not to go all over the driver and
> > > > > change this...  
> > > > 
> > > > This is about consistency. It may work as is, but it feels not
> > > > good
> > > > when for
> > > > int (or unsigned int) one uses fixed-width types. Also it's non-
> > > > written advice
> > > > to use fixed-width variables when it's about programming
> > > > registers or
> > > > so, for
> > > > the rest, use POD types.  
> >   
> 
> Ok, going a bit back in the discussion, you argued that in one place I
> was using long while here u16. Well, in the place I'm using long, that
> was on purpose because that value is to be compared against an array of
> longs (which has to be long because it depends on CCF rates). I guess I
> can als0 use s64, but there is also a reason why long was used.
> 
> In the u16 case, we really want to have 2 bytes because I'm going to
> use that value to write the dac code which is 2 bytes.
> 
> > > I can understand your reasoning but again this is something that
> > > I never really saw being enforced. So, I'm more than ok to change
> > > it
> > > if it really becomes something that we will try to "enforce" in
> > > IIO.
> > > Otherwise it just feels as a random nitpick :).  
> > 
> > No, this is about consistency and common sense. If you define type
> > uXX,
> > we have an API for that exact type. It's confusing why POD type APIs
> > are used with fixed-width types or vise versa.
> > 
> > Moreover (which is pure theoretical, though) some architectures might
> > have no (mutual) equivalency between these types.
> > 
> > ...
> >   
> > > > > > > +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");  
> > > > > 
> > > > > Well, I might be missing the point but I think this is not so
> > > > > straight....
> > > > > We will only get here if the property " adi,toggle-dither-
> > > > > input" is
> > > > > given
> > > > > in which case having the associated clocks is __mandatory__.  
> > > > 
> > > > Ah, okay, would be a limitation for non-OF platforms.
> > > >   
> > > > > Hence,
> > > > > once we are here, this can never be optional. That said, we
> > > > > need
> > > > > device_node   
> > > > 
> > > > That's fine, since CCF is OF-centric API.
> > > >   
> > > > > and hence of.h  
> > > > 
> > > > Why? This header doesn't bring anything you will use here.  
> > > 
> > > Correct me if Im missing something. AFAIU, the idea is to use
> > > 'device_for_each_child_node()' which returns a fwnode_handle. That
> > > means, that we will have to pass that to this function and use
> > > 'to_of_node()' to pass a device_node to
> > > 'devm_get_clk_from_child()'.
> > > 
> > > This means, we need of.h for 'to_of_node()'...  
> > 
> > Yeah, you are right, but it would be still better since it narrows
> > the problem to the CCF calls only.
> >   
> 
> So, to clear....
> 
> In your opinion, you are fine whith using device properties and just
> have 'to_of_node()' in this CCF call? I'm fine with it, so if Jonathan
> does not have any complain about it, will do like this in v4,
> 
> Jonathan, any comment on this one?

Whilst it's less than ideal, I'm fine with it being all generic except
for the clock part and using to_of_node() which I think is what Andy
is suggesting.

Thanks,

Jonathan


> 
> - Nuno Sá
>
Nuno Sá Feb. 19, 2022, 12:57 p.m. UTC | #19
On Sat, 2022-02-05 at 19:29 +0200, Andy Shevchenko wrote:
> 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?
> 

Hmm, when doing some changes for v4 I realized why I used the ternary
operator here (typically I'm not a fan). The thing is that we already
check the error condition after calling regmap_update_bits() which is
not the last code executed. Hence, I didn't want to do again

if (ret)
	return ret

after unlocking the mutex.

In the other places the error check is always on the last lines where
nothing else will happen (either return error or len). 

Alternatively, to remove the ternary operator, I would prefer to
actually remove the label and goto and after regmap_update_bits(), do:

if (ret) {
	mutex_unlock();
	return ret;
}

It might be not consistent with other places were goto is used but this
function also has it's differencies...

- Nuno Sá

> ...
> 
> > +       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", &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;
> > +       }
>
Andy Shevchenko Feb. 20, 2022, 11:32 a.m. UTC | #20
On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:
> On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:
> > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:
> > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:

...

> > > > > > Second, why do you need this specific function instead of
> > > > > > regmap
> > > > > > bulk
> > > > > > ops against be24/le24?
> > > > > 
> > > > > Not sure I'm following this one... If you mean why am I using a
> > > > > custom 
> > > > > regmap_bus implementation, that was already explained in the
> > > > > RFC
> > > > > patch.
> > > > > And IIRC, you were the one already asking 😉.
> > > > 
> > > > Hmm... It was some time I have looked there. Any message ID to
> > > > share,
> > > > so
> > > > I can find it quickly?
> > 
> > > https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/
> > 
> > Thanks!
> > 
> > So, it's all about cs_change, right?
> > But doesn't bulk operation work exactly as we need here?
> > 
> 
> Yes... that and we need to send the NOOP command in the second TX
> transfer.
> 
> > Looking again to the RFC code, it seems like we can still do it
> > 
> > First, you call _gather_write() followed by _read(). It will show
> > exactly what
> > you do, i.e. you send command first with the value 0x0000, followed
> > by sending
> > command and reading back the value at the same time.
> > 
> > Would it work?
> 
> Well, _gather_write() are 2 spi transfers only with TX set. That means
> that only on the _read() (which will be another spi_message) we will
> ask for the data. Im not really sure this would work being it on a
> different message. This would also mean, one extra dummy transfer. To
> me that already feels that a custom bus implementation is not a bad
> idea...

I see, okay, what Jonothan decides then. Still I'm not convinced.

...

> > > > > > > +       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?
> > > > > 
> > > > > Well, I never really saw any enforcement here to be honest
> > > > > (rather
> > > > > than using
> > > > > stdint types...). So I pretty much just use these in unsigned
> > > > > types
> > > > > because
> > > > > I'm lazy and u16 is faster to type than unsigned short... In
> > > > > this
> > > > > case, unless Jonathan
> > > > > really asks for it, I prefer not to go all over the driver and
> > > > > change this...
> > > > 
> > > > This is about consistency. It may work as is, but it feels not
> > > > good
> > > > when for
> > > > int (or unsigned int) one uses fixed-width types. Also it's non-
> > > > written advice
> > > > to use fixed-width variables when it's about programming
> > > > registers or
> > > > so, for
> > > > the rest, use POD types.
> 
> Ok, going a bit back in the discussion, you argued that in one place I
> was using long while here u16. Well, in the place I'm using long, that
> was on purpose because that value is to be compared against an array of
> longs (which has to be long because it depends on CCF rates). I guess I
> can als0 use s64, but there is also a reason why long was used.
> 
> In the u16 case, we really want to have 2 bytes because I'm going to
> use that value to write the dac code which is 2 bytes.

Okay, that's what I want to hear. If it's indeed goes to be a value to the
register, then it's fine.

Perhaps a comment?

> > > I can understand your reasoning but again this is something that
> > > I never really saw being enforced. So, I'm more than ok to change
> > > it
> > > if it really becomes something that we will try to "enforce" in
> > > IIO.
> > > Otherwise it just feels as a random nitpick :).
> > 
> > No, this is about consistency and common sense. If you define type
> > uXX,
> > we have an API for that exact type. It's confusing why POD type APIs
> > are used with fixed-width types or vise versa.
> > 
> > Moreover (which is pure theoretical, though) some architectures might
> > have no (mutual) equivalency between these types.

...

> > > > > > > +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");
> > > > > 
> > > > > Well, I might be missing the point but I think this is not so
> > > > > straight....
> > > > > We will only get here if the property " adi,toggle-dither-
> > > > > input" is
> > > > > given
> > > > > in which case having the associated clocks is __mandatory__.
> > > > 
> > > > Ah, okay, would be a limitation for non-OF platforms.
> > > > 
> > > > > Hence,
> > > > > once we are here, this can never be optional. That said, we
> > > > > need
> > > > > device_node 
> > > > 
> > > > That's fine, since CCF is OF-centric API.
> > > > 
> > > > > and hence of.h
> > > > 
> > > > Why? This header doesn't bring anything you will use here.
> > > 
> > > Correct me if Im missing something. AFAIU, the idea is to use
> > > 'device_for_each_child_node()' which returns a fwnode_handle. That
> > > means, that we will have to pass that to this function and use
> > > 'to_of_node()' to pass a device_node to
> > > 'devm_get_clk_from_child()'.
> > > 
> > > This means, we need of.h for 'to_of_node()'...
> > 
> > Yeah, you are right, but it would be still better since it narrows
> > the problem to the CCF calls only.
> 
> So, to clear....
> 
> In your opinion, you are fine whith using device properties and just
> have 'to_of_node()' in this CCF call? I'm fine with it, so if Jonathan
> does not have any complain about it, will do like this in v4,

Yes, that will show that only CCF is missing the fwnode APIs.
Nuno Sá Feb. 21, 2022, 12:48 p.m. UTC | #21
On Sun, 2022-02-20 at 13:32 +0200, Andy Shevchenko wrote:
> On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:
> > On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:
> > > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:
> > > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:
> 
> ...
> 
> > > > > > > Second, why do you need this specific function instead of
> > > > > > > regmap
> > > > > > > bulk
> > > > > > > ops against be24/le24?
> > > > > > 
> > > > > > Not sure I'm following this one... If you mean why am I
> > > > > > using a
> > > > > > custom 
> > > > > > regmap_bus implementation, that was already explained in
> > > > > > the
> > > > > > RFC
> > > > > > patch.
> > > > > > And IIRC, you were the one already asking 😉.
> > > > > 
> > > > > Hmm... It was some time I have looked there. Any message ID
> > > > > to
> > > > > share,
> > > > > so
> > > > > I can find it quickly?
> > > 
> > > > https://lore.kernel.org/all/20211112152235.12fdcc49@jic23-huawei/
> > > 
> > > Thanks!
> > > 
> > > So, it's all about cs_change, right?
> > > But doesn't bulk operation work exactly as we need here?
> > > 
> > 
> > Yes... that and we need to send the NOOP command in the second TX
> > transfer.
> > 
> > > Looking again to the RFC code, it seems like we can still do it
> > > 
> > > First, you call _gather_write() followed by _read(). It will show
> > > exactly what
> > > you do, i.e. you send command first with the value 0x0000,
> > > followed
> > > by sending
> > > command and reading back the value at the same time.
> > > 
> > > Would it work?
> > 
> > Well, _gather_write() are 2 spi transfers only with TX set. That
> > means
> > that only on the _read() (which will be another spi_message) we
> > will
> > ask for the data. Im not really sure this would work being it on a
> > different message. This would also mean, one extra dummy transfer.
> > To
> > me that already feels that a custom bus implementation is not a bad
> > idea...
> 
> I see, okay, what Jonothan decides then. Still I'm not convinced.
> 
> ...
> 
> > > > > > > > +       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?
> > > > > > 
> > > > > > Well, I never really saw any enforcement here to be honest
> > > > > > (rather
> > > > > > than using
> > > > > > stdint types...). So I pretty much just use these in
> > > > > > unsigned
> > > > > > types
> > > > > > because
> > > > > > I'm lazy and u16 is faster to type than unsigned short...
> > > > > > In
> > > > > > this
> > > > > > case, unless Jonathan
> > > > > > really asks for it, I prefer not to go all over the driver
> > > > > > and
> > > > > > change this...
> > > > > 
> > > > > This is about consistency. It may work as is, but it feels
> > > > > not
> > > > > good
> > > > > when for
> > > > > int (or unsigned int) one uses fixed-width types. Also it's
> > > > > non-
> > > > > written advice
> > > > > to use fixed-width variables when it's about programming
> > > > > registers or
> > > > > so, for
> > > > > the rest, use POD types.
> > 
> > Ok, going a bit back in the discussion, you argued that in one
> > place I
> > was using long while here u16. Well, in the place I'm using long,
> > that
> > was on purpose because that value is to be compared against an
> > array of
> > longs (which has to be long because it depends on CCF rates). I
> > guess I
> > can als0 use s64, but there is also a reason why long was used.
> > 
> > In the u16 case, we really want to have 2 bytes because I'm going
> > to
> > use that value to write the dac code which is 2 bytes.
> 
> Okay, that's what I want to hear. If it's indeed goes to be a value
> to the
> register, then it's fine.
> 
> Perhaps a comment?
> 

I guess you mean to have a comment to state that here we have fixed
size type (as opposed to long, used in another place), because we
directly use the value on a register write?

Asking it because I'm not planning to add comments in all the places
where I have fixed size types for register read/writes...

> > > > I can understand your reasoning but again this is something
> > > > that
> > > > I never really saw being enforced. So, I'm more than ok to
> > > > change
> > > > it
> > > > if it really becomes something that we will try to "enforce" in
> > > > IIO.
> > > > Otherwise it just feels as a random nitpick :).
> > > 
> > > No, this is about consistency and common sense. If you define
> > > type
> > > uXX,
> > > we have an API for that exact type. It's confusing why POD type
> > > APIs
> > > are used with fixed-width types or vise versa.
> > > 
> > > Moreover (which is pure theoretical, though) some architectures
> > > might
> > > have no (mutual) equivalency between these types.
> 
> ...
> 
> > > > > > > > +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");
> > > > > > 
> > > > > > Well, I might be missing the point but I think this is not
> > > > > > so
> > > > > > straight....
> > > > > > We will only get here if the property " adi,toggle-dither-
> > > > > > input" is
> > > > > > given
> > > > > > in which case having the associated clocks is
> > > > > > __mandatory__.
> > > > > 
> > > > > Ah, okay, would be a limitation for non-OF platforms.
> > > > > 
> > > > > > Hence,
> > > > > > once we are here, this can never be optional. That said, we
> > > > > > need
> > > > > > device_node 
> > > > > 
> > > > > That's fine, since CCF is OF-centric API.
> > > > > 
> > > > > > and hence of.h
> > > > > 
> > > > > Why? This header doesn't bring anything you will use here.
> > > > 
> > > > Correct me if Im missing something. AFAIU, the idea is to use
> > > > 'device_for_each_child_node()' which returns a fwnode_handle.
> > > > That
> > > > means, that we will have to pass that to this function and use
> > > > 'to_of_node()' to pass a device_node to
> > > > 'devm_get_clk_from_child()'.
> > > > 
> > > > This means, we need of.h for 'to_of_node()'...
> > > 
> > > Yeah, you are right, but it would be still better since it
> > > narrows
> > > the problem to the CCF calls only.
> > 
> > So, to clear....
> > 
> > In your opinion, you are fine whith using device properties and
> > just
> > have 'to_of_node()' in this CCF call? I'm fine with it, so if
> > Jonathan
> > does not have any complain about it, will do like this in v4,
> 
> Yes, that will show that only CCF is missing the fwnode APIs.
> 

Ok, it's settled then...

- Nuno Sá
Andy Shevchenko Feb. 21, 2022, 5:04 p.m. UTC | #22
On Mon, Feb 21, 2022 at 01:48:12PM +0100, Nuno Sá wrote:
> On Sun, 2022-02-20 at 13:32 +0200, Andy Shevchenko wrote:
> > On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:
> > > On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:
> > > > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:
> > > > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:
> > > > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:
> > > > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:

...

> > > > > > > > > +       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?
> > > > > > > 
> > > > > > > Well, I never really saw any enforcement here to be honest
> > > > > > > (rather than using stdint types...). So I pretty much just use
> > > > > > > these in unsigned types because I'm lazy and u16 is faster to
> > > > > > > type than unsigned short...  In this case, unless Jonathan really
> > > > > > > asks for it, I prefer not to go all over the driver and change
> > > > > > > this...
> > > > > > 
> > > > > > This is about consistency. It may work as is, but it feels not good
> > > > > > when for int (or unsigned int) one uses fixed-width types. Also
> > > > > > it's non- written advice to use fixed-width variables when it's
> > > > > > about programming registers or so, for the rest, use POD types.
> > > 
> > > Ok, going a bit back in the discussion, you argued that in one place I
> > > was using long while here u16. Well, in the place I'm using long, that
> > > was on purpose because that value is to be compared against an array of
> > > longs (which has to be long because it depends on CCF rates). I guess I
> > > can als0 use s64, but there is also a reason why long was used.
> > > 
> > > In the u16 case, we really want to have 2 bytes because I'm going to use
> > > that value to write the dac code which is 2 bytes.
> > 
> > Okay, that's what I want to hear. If it's indeed goes to be a value to the
> > register, then it's fine.
> > 
> > Perhaps a comment?
> 
> I guess you mean to have a comment to state that here we have fixed
> size type (as opposed to long, used in another place), because we
> directly use the value on a register write?
> 
> Asking it because I'm not planning to add comments in all the places
> where I have fixed size types for register read/writes...

Thinking more about it and now I'm convinced that using the value that goes to
the register in ABI is bad idea (means that user space must not care about the
size or contents of the hardware register and should be abstract representation
of the HW).

OTOH this seems to be "raw" value of something. So, I maybe missed the convention
in IIO about this kind of values WRT the variable types used on ABI side.

That said, I leave it to Jonathan since I'm not convinced that u16 is a proper
choice here.

> > > > > I can understand your reasoning but again this is something that I
> > > > > never really saw being enforced. So, I'm more than ok to change it if
> > > > > it really becomes something that we will try to "enforce" in IIO.
> > > > > Otherwise it just feels as a random nitpick :).
> > > > 
> > > > No, this is about consistency and common sense. If you define type uXX,
> > > > we have an API for that exact type. It's confusing why POD type APIs
> > > > are used with fixed-width types or vise versa.
> > > > 
> > > > Moreover (which is pure theoretical, though) some architectures might
> > > > have no (mutual) equivalency between these types.
Jonathan Cameron Feb. 21, 2022, 5:30 p.m. UTC | #23
On Mon, 21 Feb 2022 19:04:38 +0200
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:

> On Mon, Feb 21, 2022 at 01:48:12PM +0100, Nuno Sá wrote:
> > On Sun, 2022-02-20 at 13:32 +0200, Andy Shevchenko wrote:  
> > > On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:  
> > > > On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:  
> > > > > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:  
> > > > > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:  
> > > > > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:  
> > > > > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:  
> 
> ...
> 
> > > > > > > > > > +       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?  
> > > > > > > > 
> > > > > > > > Well, I never really saw any enforcement here to be honest
> > > > > > > > (rather than using stdint types...). So I pretty much just use
> > > > > > > > these in unsigned types because I'm lazy and u16 is faster to
> > > > > > > > type than unsigned short...  In this case, unless Jonathan really
> > > > > > > > asks for it, I prefer not to go all over the driver and change
> > > > > > > > this...  
> > > > > > > 
> > > > > > > This is about consistency. It may work as is, but it feels not good
> > > > > > > when for int (or unsigned int) one uses fixed-width types. Also
> > > > > > > it's non- written advice to use fixed-width variables when it's
> > > > > > > about programming registers or so, for the rest, use POD types.  
> > > > 
> > > > Ok, going a bit back in the discussion, you argued that in one place I
> > > > was using long while here u16. Well, in the place I'm using long, that
> > > > was on purpose because that value is to be compared against an array of
> > > > longs (which has to be long because it depends on CCF rates). I guess I
> > > > can als0 use s64, but there is also a reason why long was used.
> > > > 
> > > > In the u16 case, we really want to have 2 bytes because I'm going to use
> > > > that value to write the dac code which is 2 bytes.  
> > > 
> > > Okay, that's what I want to hear. If it's indeed goes to be a value to the
> > > register, then it's fine.
> > > 
> > > Perhaps a comment?  
> > 
> > I guess you mean to have a comment to state that here we have fixed
> > size type (as opposed to long, used in another place), because we
> > directly use the value on a register write?
> > 
> > Asking it because I'm not planning to add comments in all the places
> > where I have fixed size types for register read/writes...  
> 
> Thinking more about it and now I'm convinced that using the value that goes to
> the register in ABI is bad idea (means that user space must not care about the
> size or contents of the hardware register and should be abstract representation
> of the HW).
> 
> OTOH this seems to be "raw" value of something. So, I maybe missed the convention
> in IIO about this kind of values WRT the variable types used on ABI side.
> 
> That said, I leave it to Jonathan since I'm not convinced that u16 is a proper
> choice here.

From a userspace point of view it doesn't care as it's writing a string.
In this particular case the string only has valid values that from 0-(2^16-1)
(i.e. 16 bits).  So if it writes outside of that range it is an error.
You could read it into an unsigned long and then check against the range,
but there is little point given you'd still return an error if it was out of
range.  The fact that kstrto16() does that for you really just a shortcut
though it will return -ERANGE rather than perhaps -EINVAL which might be used
for a more generic "not this value".

Userspace can also read the range that is acceptable from
out_voltage0_raw_available [0 1 2^16-1] and hence not write an invalid value
in the first place - which is obviously preferred to getting an error.
Scaling etc is also expressed to userspace so it it wants to write a particular
voltage it can perform the appropriate scaling. Note that moving linear scaling
like this to userspace allows easy use of floating point + may be a significant
performance advantage if using the chrdev interface which uses the same
approach (and values) as the sysfs interface.

Jonathan


 
> 
> > > > > > I can understand your reasoning but again this is something that I
> > > > > > never really saw being enforced. So, I'm more than ok to change it if
> > > > > > it really becomes something that we will try to "enforce" in IIO.
> > > > > > Otherwise it just feels as a random nitpick :).  
> > > > > 
> > > > > No, this is about consistency and common sense. If you define type uXX,
> > > > > we have an API for that exact type. It's confusing why POD type APIs
> > > > > are used with fixed-width types or vise versa.
> > > > > 
> > > > > Moreover (which is pure theoretical, though) some architectures might
> > > > > have no (mutual) equivalency between these types.  
>
Andy Shevchenko Feb. 21, 2022, 6:49 p.m. UTC | #24
On Mon, Feb 21, 2022 at 05:30:45PM +0000, Jonathan Cameron wrote:
> On Mon, 21 Feb 2022 19:04:38 +0200
> Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> 
> > On Mon, Feb 21, 2022 at 01:48:12PM +0100, Nuno Sá wrote:
> > > On Sun, 2022-02-20 at 13:32 +0200, Andy Shevchenko wrote:  
> > > > On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:  
> > > > > On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:  
> > > > > > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:  
> > > > > > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:  
> > > > > > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:  
> > > > > > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:  
> > 
> > ...
> > 
> > > > > > > > > > > +       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?  
> > > > > > > > > 
> > > > > > > > > Well, I never really saw any enforcement here to be honest
> > > > > > > > > (rather than using stdint types...). So I pretty much just use
> > > > > > > > > these in unsigned types because I'm lazy and u16 is faster to
> > > > > > > > > type than unsigned short...  In this case, unless Jonathan really
> > > > > > > > > asks for it, I prefer not to go all over the driver and change
> > > > > > > > > this...  
> > > > > > > > 
> > > > > > > > This is about consistency. It may work as is, but it feels not good
> > > > > > > > when for int (or unsigned int) one uses fixed-width types. Also
> > > > > > > > it's non- written advice to use fixed-width variables when it's
> > > > > > > > about programming registers or so, for the rest, use POD types.  
> > > > > 
> > > > > Ok, going a bit back in the discussion, you argued that in one place I
> > > > > was using long while here u16. Well, in the place I'm using long, that
> > > > > was on purpose because that value is to be compared against an array of
> > > > > longs (which has to be long because it depends on CCF rates). I guess I
> > > > > can als0 use s64, but there is also a reason why long was used.
> > > > > 
> > > > > In the u16 case, we really want to have 2 bytes because I'm going to use
> > > > > that value to write the dac code which is 2 bytes.  
> > > > 
> > > > Okay, that's what I want to hear. If it's indeed goes to be a value to the
> > > > register, then it's fine.
> > > > 
> > > > Perhaps a comment?  
> > > 
> > > I guess you mean to have a comment to state that here we have fixed
> > > size type (as opposed to long, used in another place), because we
> > > directly use the value on a register write?
> > > 
> > > Asking it because I'm not planning to add comments in all the places
> > > where I have fixed size types for register read/writes...  
> > 
> > Thinking more about it and now I'm convinced that using the value that goes to
> > the register in ABI is bad idea (means that user space must not care about the
> > size or contents of the hardware register and should be abstract representation
> > of the HW).
> > 
> > OTOH this seems to be "raw" value of something. So, I maybe missed the convention
> > in IIO about this kind of values WRT the variable types used on ABI side.
> > 
> > That said, I leave it to Jonathan since I'm not convinced that u16 is a proper
> > choice here.
> 
> From a userspace point of view it doesn't care as it's writing a string.
> In this particular case the string only has valid values that from 0-(2^16-1)
> (i.e. 16 bits).  So if it writes outside of that range it is an error.
> You could read it into an unsigned long and then check against the range,
> but there is little point given you'd still return an error if it was out of
> range.  The fact that kstrto16() does that for you really just a shortcut
> though it will return -ERANGE rather than perhaps -EINVAL which might be used
> for a more generic "not this value".
> 
> Userspace can also read the range that is acceptable from
> out_voltage0_raw_available [0 1 2^16-1] and hence not write an invalid value
> in the first place - which is obviously preferred to getting an error.
> Scaling etc is also expressed to userspace so it it wants to write a particular
> voltage it can perform the appropriate scaling. Note that moving linear scaling
> like this to userspace allows easy use of floating point + may be a significant
> performance advantage if using the chrdev interface which uses the same
> approach (and values) as the sysfs interface.

With the same logic it can be unsigned short, no?

The point is to use u16 when it's indeed fixed-width value that goes to
hardware or being used as part of a protocol. And thus mentioning of the
IOCTL protocols may justify the choice. Then the question to the other
values, shouldn't they be also fixed-width ones?

> > > > > > > I can understand your reasoning but again this is something that I
> > > > > > > never really saw being enforced. So, I'm more than ok to change it if
> > > > > > > it really becomes something that we will try to "enforce" in IIO.
> > > > > > > Otherwise it just feels as a random nitpick :).  
> > > > > > 
> > > > > > No, this is about consistency and common sense. If you define type uXX,
> > > > > > we have an API for that exact type. It's confusing why POD type APIs
> > > > > > are used with fixed-width types or vise versa.
> > > > > > 
> > > > > > Moreover (which is pure theoretical, though) some architectures might
> > > > > > have no (mutual) equivalency between these types.
Jonathan Cameron Feb. 22, 2022, 4:21 p.m. UTC | #25
On Mon, 21 Feb 2022 20:49:48 +0200
Andy Shevchenko <andriy.shevchenko@intel.com> wrote:

> On Mon, Feb 21, 2022 at 05:30:45PM +0000, Jonathan Cameron wrote:
> > On Mon, 21 Feb 2022 19:04:38 +0200
> > Andy Shevchenko <andriy.shevchenko@intel.com> wrote:
> >   
> > > On Mon, Feb 21, 2022 at 01:48:12PM +0100, Nuno Sá wrote:  
> > > > On Sun, 2022-02-20 at 13:32 +0200, Andy Shevchenko wrote:    
> > > > > On Fri, Feb 18, 2022 at 02:51:28PM +0100, Nuno Sá wrote:    
> > > > > > On Mon, 2022-02-14 at 15:49 +0200, Andy Shevchenko wrote:    
> > > > > > > On Mon, Feb 07, 2022 at 09:19:46PM +0100, Nuno Sá wrote:    
> > > > > > > > On Mon, 2022-02-07 at 13:09 +0200, Andy Shevchenko wrote:    
> > > > > > > > > On Sun, Feb 06, 2022 at 01:19:59PM +0000, Sa, Nuno wrote:    
> > > > > > > > > > > From: Andy Shevchenko <andriy.shevchenko@intel.com>
> > > > > > > > > > > Sent: Saturday, February 5, 2022 6:30 PM
> > > > > > > > > > > On Fri, Jan 21, 2022 at 03:24:59PM +0100, Nuno Sá wrote:    
> > > 
> > > ...
> > >   
> > > > > > > > > > > > +       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?    
> > > > > > > > > > 
> > > > > > > > > > Well, I never really saw any enforcement here to be honest
> > > > > > > > > > (rather than using stdint types...). So I pretty much just use
> > > > > > > > > > these in unsigned types because I'm lazy and u16 is faster to
> > > > > > > > > > type than unsigned short...  In this case, unless Jonathan really
> > > > > > > > > > asks for it, I prefer not to go all over the driver and change
> > > > > > > > > > this...    
> > > > > > > > > 
> > > > > > > > > This is about consistency. It may work as is, but it feels not good
> > > > > > > > > when for int (or unsigned int) one uses fixed-width types. Also
> > > > > > > > > it's non- written advice to use fixed-width variables when it's
> > > > > > > > > about programming registers or so, for the rest, use POD types.    
> > > > > > 
> > > > > > Ok, going a bit back in the discussion, you argued that in one place I
> > > > > > was using long while here u16. Well, in the place I'm using long, that
> > > > > > was on purpose because that value is to be compared against an array of
> > > > > > longs (which has to be long because it depends on CCF rates). I guess I
> > > > > > can als0 use s64, but there is also a reason why long was used.
> > > > > > 
> > > > > > In the u16 case, we really want to have 2 bytes because I'm going to use
> > > > > > that value to write the dac code which is 2 bytes.    
> > > > > 
> > > > > Okay, that's what I want to hear. If it's indeed goes to be a value to the
> > > > > register, then it's fine.
> > > > > 
> > > > > Perhaps a comment?    
> > > > 
> > > > I guess you mean to have a comment to state that here we have fixed
> > > > size type (as opposed to long, used in another place), because we
> > > > directly use the value on a register write?
> > > > 
> > > > Asking it because I'm not planning to add comments in all the places
> > > > where I have fixed size types for register read/writes...    
> > > 
> > > Thinking more about it and now I'm convinced that using the value that goes to
> > > the register in ABI is bad idea (means that user space must not care about the
> > > size or contents of the hardware register and should be abstract representation
> > > of the HW).
> > > 
> > > OTOH this seems to be "raw" value of something. So, I maybe missed the convention
> > > in IIO about this kind of values WRT the variable types used on ABI side.
> > > 
> > > That said, I leave it to Jonathan since I'm not convinced that u16 is a proper
> > > choice here.  
> > 
> > From a userspace point of view it doesn't care as it's writing a string.
> > In this particular case the string only has valid values that from 0-(2^16-1)
> > (i.e. 16 bits).  So if it writes outside of that range it is an error.
> > You could read it into an unsigned long and then check against the range,
> > but there is little point given you'd still return an error if it was out of
> > range.  The fact that kstrto16() does that for you really just a shortcut
> > though it will return -ERANGE rather than perhaps -EINVAL which might be used
> > for a more generic "not this value".
> > 
> > Userspace can also read the range that is acceptable from
> > out_voltage0_raw_available [0 1 2^16-1] and hence not write an invalid value
> > in the first place - which is obviously preferred to getting an error.
> > Scaling etc is also expressed to userspace so it it wants to write a particular
> > voltage it can perform the appropriate scaling. Note that moving linear scaling
> > like this to userspace allows easy use of floating point + may be a significant
> > performance advantage if using the chrdev interface which uses the same
> > approach (and values) as the sysfs interface.  
> 
> With the same logic it can be unsigned short, no?

It could be any integer as long as it is at least as large as a u16.
But it it is larger than a u16 you'll need an additional check on the
maximum.

> 
> The point is to use u16 when it's indeed fixed-width value that goes to
> hardware or being used as part of a protocol. And thus mentioning of the
> IOCTL protocols may justify the choice. Then the question to the other
> values, shouldn't they be also fixed-width ones?

If we had a fixed width type that took the values 0-4 sure using such
a magic type would make sense, but we don't.

Note that internally kstrtou16 is just strtoull and a range check.
The one other case we have here does pretty much the same thing.

Jonathan

> 
> > > > > > > > I can understand your reasoning but again this is something that I
> > > > > > > > never really saw being enforced. So, I'm more than ok to change it if
> > > > > > > > it really becomes something that we will try to "enforce" in IIO.
> > > > > > > > Otherwise it just feels as a random nitpick :).    
> > > > > > > 
> > > > > > > No, this is about consistency and common sense. If you define type uXX,
> > > > > > > we have an API for that exact type. It's confusing why POD type APIs
> > > > > > > are used with fixed-width types or vise versa.
> > > > > > > 
> > > > > > > Moreover (which is pure theoretical, though) some architectures might
> > > > > > > have no (mutual) equivalency between these types.    
>