Hi Hans, Thank you for the review comments. > On 11/09/2016 04:44 PM, Ramesh Shanmugasundaram wrote: > > This patch adds driver support for MAX2175 chip. This is Maxim > > Integrated's RF to Bits tuner front end chip designed for > > software-defined radio solutions. This driver exposes the tuner as a > > sub-device instance with standard and custom controls to configure the > device. > > > > Signed-off-by: Ramesh Shanmugasundaram > > <ramesh.shanmugasundaram@xxxxxxxxxxxxxx> > > --- > > .../devicetree/bindings/media/i2c/max2175.txt | 61 + > > drivers/media/i2c/Kconfig | 4 + > > drivers/media/i2c/Makefile | 2 + > > drivers/media/i2c/max2175/Kconfig | 8 + > > drivers/media/i2c/max2175/Makefile | 4 + > > drivers/media/i2c/max2175/max2175.c | 1558 > ++++++++++++++++++++ > > drivers/media/i2c/max2175/max2175.h | 108 ++ > > 7 files changed, 1745 insertions(+) > > create mode 100644 > > Documentation/devicetree/bindings/media/i2c/max2175.txt > > create mode 100644 drivers/media/i2c/max2175/Kconfig create mode > > 100644 drivers/media/i2c/max2175/Makefile > > create mode 100644 drivers/media/i2c/max2175/max2175.c > > create mode 100644 drivers/media/i2c/max2175/max2175.h > > > > <snip> > > > diff --git a/drivers/media/i2c/max2175/max2175.c > > b/drivers/media/i2c/max2175/max2175.c > > new file mode 100644 > > index 0000000..ec45b52 > > --- /dev/null > > +++ b/drivers/media/i2c/max2175/max2175.c > > @@ -0,0 +1,1558 @@ > > <snip> > > > +/* Read/Write bit(s) on top of regmap */ static int > > +max2175_read(struct max2175 *ctx, u8 idx, u8 *val) { > > + u32 regval; > > + int ret = regmap_read(ctx->regmap, idx, ®val); > > + > > + if (ret) > > + v4l2_err(ctx->client, "read ret(%d): idx 0x%02x\n", ret, idx); > > + > > + *val = regval; > > Does regmap_read initialize regval even if it returns an error? If not, > then I would initialize regval to 0 to prevent *val being uninitialized. Agreed. > > > + return ret; > > +} > > + > > +static int max2175_write(struct max2175 *ctx, u8 idx, u8 val) { > > + int ret = regmap_write(ctx->regmap, idx, val); > > + > > + if (ret) > > + v4l2_err(ctx->client, "write ret(%d): idx 0x%02x val > 0x%02x\n", > > + ret, idx, val); > > + return ret; > > +} > > + > > +static u8 max2175_read_bits(struct max2175 *ctx, u8 idx, u8 msb, u8 > > +lsb) { > > + u8 val; > > + > > + if (max2175_read(ctx, idx, &val)) > > + return 0; > > + > > + return max2175_get_bitval(val, msb, lsb); } > > + > > +static bool max2175_read_bit(struct max2175 *ctx, u8 idx, u8 bit) { > > + return !!max2175_read_bits(ctx, idx, bit, bit); } > > + > > +static int max2175_write_bits(struct max2175 *ctx, u8 idx, > > + u8 msb, u8 lsb, u8 newval) > > +{ > > + int ret = regmap_update_bits(ctx->regmap, idx, GENMASK(msb, lsb), > > + newval << lsb); > > + > > + if (ret) > > + v4l2_err(ctx->client, "wbits ret(%d): idx 0x%02x\n", ret, > idx); > > + > > + return ret; > > +} > > + > > +static int max2175_write_bit(struct max2175 *ctx, u8 idx, u8 bit, u8 > > +newval) { > > + return max2175_write_bits(ctx, idx, bit, bit, newval); } > > + > > +/* Checks expected pattern every msec until timeout */ static int > > +max2175_poll_timeout(struct max2175 *ctx, u8 idx, u8 msb, u8 lsb, > > + u8 exp_bitval, u32 timeout_ms) > > +{ > > + unsigned int val; > > + > > + return regmap_read_poll_timeout(ctx->regmap, idx, val, > > + (max2175_get_bitval(val, msb, lsb) == exp_bitval), > > + 1000, timeout_ms * 1000); > > +} > > + > > +static int max2175_poll_csm_ready(struct max2175 *ctx) { > > + int ret; > > + > > + ret = max2175_poll_timeout(ctx, 69, 1, 1, 0, 50); > > + if (ret) > > + v4l2_err(ctx->client, "csm not ready\n"); > > + > > + return ret; > > +} > > + > > +#define MAX2175_IS_BAND_AM(ctx) \ > > + (max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_AM) > > + > > +#define MAX2175_IS_BAND_VHF(ctx) \ > > + (max2175_read_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF) > > + > > +#define MAX2175_IS_FM_MODE(ctx) \ > > + (max2175_read_bits(ctx, 12, 5, 4) == 0) > > + > > +#define MAX2175_IS_FMHD_MODE(ctx) \ > > + (max2175_read_bits(ctx, 12, 5, 4) == 1) > > + > > +#define MAX2175_IS_DAB_MODE(ctx) \ > > + (max2175_read_bits(ctx, 12, 5, 4) == 2) > > + > > +static int max2175_band_from_freq(u32 freq) { > > + if (freq >= 144000 && freq <= 26100000) > > + return MAX2175_BAND_AM; > > + else if (freq >= 65000000 && freq <= 108000000) > > + return MAX2175_BAND_FM; > > + else > > No need for these 'else' keywords. Agreed. > > > + return MAX2175_BAND_VHF; > > +} > > + > > +static int max2175_update_i2s_mode(struct max2175 *ctx, u32 rx_mode, > > + u32 i2s_mode) > > +{ > > + max2175_write_bits(ctx, 29, 2, 0, i2s_mode); > > + > > + /* Based on I2S mode value I2S_WORD_CNT values change */ > > + switch (i2s_mode) { > > + case MAX2175_I2S_MODE3: > > + max2175_write_bits(ctx, 30, 6, 0, 1); > > + break; > > + case MAX2175_I2S_MODE2: > > + case MAX2175_I2S_MODE4: > > + max2175_write_bits(ctx, 30, 6, 0, 0); > > + break; > > + case MAX2175_I2S_MODE0: > > + max2175_write_bits(ctx, 30, 6, 0, > > + ctx->rx_modes[rx_mode].i2s_word_size); > > + break; > > + } > > + mxm_dbg(ctx, "update_i2s_mode %u, rx_mode %u\n", i2s_mode, rx_mode); > > + return 0; > > +} [snip] > > + > > +static int max2175_enum_freq_bands(struct v4l2_subdev *sd, > > + struct v4l2_frequency_band *band) { > > + struct max2175 *ctx = max2175_from_sd(sd); > > + > > + if (band->tuner == 0 && band->index == 0) > > + *band = *ctx->bands_rf; > > + else > > + return -EINVAL; > > This is a bit ugly. I would invert the condition and return -EINVAL. > Then assign *band and return 0. Agreed. > > > + > > + return 0; > > +} > > + > > +static int max2175_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner > > +*vt) { > > + struct max2175 *ctx = max2175_from_sd(sd); > > + > > + if (vt->index > 0) > > + return -EINVAL; > > + > > + strlcpy(vt->name, "RF", sizeof(vt->name)); > > + vt->type = V4L2_TUNER_RF; > > + vt->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; > > + vt->rangelow = ctx->bands_rf->rangelow; > > + vt->rangehigh = ctx->bands_rf->rangehigh; > > + return 0; > > +} > > + > > +static int max2175_s_tuner(struct v4l2_subdev *sd, const struct > > +v4l2_tuner *vt) { > > + /* Check tuner index is valid */ > > + if (vt->index > 0) > > + return -EINVAL; > > + > > + return 0; > > +} > > + > > +static const struct v4l2_subdev_tuner_ops max2175_tuner_ops = { > > + .s_frequency = max2175_s_frequency, > > + .g_frequency = max2175_g_frequency, > > + .enum_freq_bands = max2175_enum_freq_bands, > > + .g_tuner = max2175_g_tuner, > > + .s_tuner = max2175_s_tuner, > > +}; > > + > > +static const struct v4l2_subdev_ops max2175_ops = { > > + .tuner = &max2175_tuner_ops, > > +}; > > + > > +static const struct v4l2_ctrl_ops max2175_ctrl_ops = { > > + .s_ctrl = max2175_s_ctrl, > > + .g_volatile_ctrl = max2175_g_volatile_ctrl, }; > > + > > +static const struct v4l2_ctrl_config max2175_i2s_en = { > > + .ops = &max2175_ctrl_ops, > > + .id = V4L2_CID_MAX2175_I2S_ENABLE, > > + .name = "I2S Enable", > > + .type = V4L2_CTRL_TYPE_BOOLEAN, > > + .min = 0, > > + .max = 1, > > + .step = 1, > > + .def = 1, > > +}; > > + > > +static const char * const max2175_ctrl_i2s_modes[] = { > > + [MAX2175_I2S_MODE0] = "i2s mode 0", > > + [MAX2175_I2S_MODE1] = "i2s mode 1 (skipped)", > > + [MAX2175_I2S_MODE2] = "i2s mode 2", > > + [MAX2175_I2S_MODE3] = "i2s mode 3", > > + [MAX2175_I2S_MODE4] = "i2s mode 4", > > +}; > > + > > +static const struct v4l2_ctrl_config max2175_i2s_mode = { > > + .ops = &max2175_ctrl_ops, > > + .id = V4L2_CID_MAX2175_I2S_MODE, > > + .name = "I2S MODE value", > > + .type = V4L2_CTRL_TYPE_MENU, > > + .max = ARRAY_SIZE(max2175_ctrl_i2s_modes) - 1, > > + .def = 0, > > + .menu_skip_mask = 0x02, > > + .qmenu = max2175_ctrl_i2s_modes, > > +}; > > Is this something that is changed dynamically? It looks more like a device > tree thing (it's not clear what it does, so obviously I can't be sure). Yes. It can be changed dynamically. > > > + > > +static const struct v4l2_ctrl_config max2175_hsls = { > > + .ops = &max2175_ctrl_ops, > > + .id = V4L2_CID_MAX2175_HSLS, > > + .name = "HSLS above/below desired", > > + .type = V4L2_CTRL_TYPE_INTEGER, > > + .min = 0, > > + .max = 1, > > + .step = 1, > > + .def = 1, > > +}; > > + > > +static const char * const max2175_ctrl_eu_rx_modes[] = { > > + [MAX2175_EU_FM_1_2] = "EU FM 1.2", > > + [MAX2175_DAB_1_2] = "DAB 1.2", > > +}; > > + > > +static const char * const max2175_ctrl_na_rx_modes[] = { > > + [MAX2175_NA_FM_1_0] = "NA FM 1.0", > > + [MAX2175_NA_FM_2_0] = "NA FM 2.0", > > +}; > > + > > +static const struct v4l2_ctrl_config max2175_eu_rx_mode = { > > + .ops = &max2175_ctrl_ops, > > + .id = V4L2_CID_MAX2175_RX_MODE, > > + .name = "RX MODE", > > + .type = V4L2_CTRL_TYPE_MENU, > > + .max = ARRAY_SIZE(max2175_ctrl_eu_rx_modes) - 1, > > + .def = 0, > > + .qmenu = max2175_ctrl_eu_rx_modes, > > +}; > > + > > +static const struct v4l2_ctrl_config max2175_na_rx_mode = { > > + .ops = &max2175_ctrl_ops, > > + .id = V4L2_CID_MAX2175_RX_MODE, > > + .name = "RX MODE", > > + .type = V4L2_CTRL_TYPE_MENU, > > + .max = ARRAY_SIZE(max2175_ctrl_na_rx_modes) - 1, > > + .def = 0, > > + .qmenu = max2175_ctrl_na_rx_modes, > > +}; > > Please document all these controls better. This is part of the public API, > so you need to give more information what this means exactly. Thanks. Now, I have added a one-liner and a bit descriptive explanation at Documentation/media/v4l-drivers dir as you & Laurent concluded. Thanks, Ramesh ��.n��������+%������w��{.n����z�{��ܨ}���Ơz�j:+v�����w����ޙ��&�)ߡ�a����z�ޗ���ݢj��w�f