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.shanmugasunda...@bp.renesas.com>
> > ---
> >  .../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, &regval);
> > +
> > +   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

Reply via email to