From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
To: Ramesh Shanmugasundaram <ramesh.shanmugasundaram@bp.renesas.com>
Cc: robh+dt@kernel.org, mark.rutland@arm.com, mchehab@kernel.org,
hverkuil@xs4all.nl, sakari.ailus@linux.intel.com, crope@iki.fi,
chris.paterson2@renesas.com, geert@linux-m68k.org,
linux-media@vger.kernel.org, devicetree@vger.kernel.org,
linux-renesas-soc@vger.kernel.org
Subject: Re: [RFC 1/5] media: i2c: max2175: Add MAX2175 support
Date: Tue, 18 Oct 2016 22:25:45 +0300 [thread overview]
Message-ID: <2034831.3otZHvJ6bZ@avalon> (raw)
In-Reply-To: <1476281429-27603-2-git-send-email-ramesh.shanmugasundaram@bp.renesas.com>
Hi Ramesh,
Thank you for the patch.
On Wednesday 12 Oct 2016 15:10:25 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@bp.renesas.com> ---
> .../devicetree/bindings/media/i2c/max2175.txt | 60 +
> 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 | 1624 +++++++++++++++++
> drivers/media/i2c/max2175/max2175.h | 124 ++
> 7 files changed, 1826 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
>
> diff --git a/Documentation/devicetree/bindings/media/i2c/max2175.txt
> b/Documentation/devicetree/bindings/media/i2c/max2175.txt new file mode
> 100644
> index 0000000..2250d5f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/i2c/max2175.txt
> @@ -0,0 +1,60 @@
> +Maxim Integrated MAX2175 RF to Bits tuner
> +-----------------------------------------
> +
> +The MAX2175 IC is an advanced analog/digital hybrid-radio receiver with
> +RF to Bits® front-end designed for software-defined radio solutions.
> +
> +Required properties:
> +--------------------
> +- compatible: "maxim,max2175" for MAX2175 RF-to-bits tuner.
> +- clocks: phandle to the fixed xtal clock.
> +- clock-names: name of the fixed xtal clock.
> +- port: video interface child port node of a tuner that defines the local
As Rob pointed out in his review of patch 3/5, this isn't video.
> + and remote endpoints. The remote endpoint is assumed to be an SDR device
> + that is capable of receiving the digital samples from the tuner.
> +
> +Optional properties:
> +--------------------
> +- maxim,slave : empty property indicates this is a slave of
another
> + master tuner. This is used to define two tuners in
> + diversity mode (1 master, 1 slave). By default each
> + tuner is an individual master.
Would it be useful to make that property a phandle to the master tuner, to
give drivers a way to access the master ? I haven't checked whether there
could be use cases for that.
> +- maxim,refout-load: load capacitance value (in pF) on reference output
> + drive level. The mapping of these load values to
> + respective bit values are given below.
> + 0 - Reference output disabled
> + 1 - 10pF load
> + 2 - 20pF load
> + 3 - 30pF load
> + 4 - 40pF load
> + 5 - 60pF load
> + 6 - 70pF load
As Geert pointed out, you can simply specify the value in pF.
> +
> +Example:
> +--------
> +
> +Board specific DTS file
> +
> +/* Fixed XTAL clock node */
> +maxim_xtal: maximextal {
> + compatible = "fixed-clock";
> + #clock-cells = <0>;
> + clock-frequency = <36864000>;
> +};
> +
> +/* A tuner device instance under i2c bus */
> +max2175_0: tuner@60 {
> + #clock-cells = <0>;
Is the tuner a clock provider ? If it isn't you don't need this property.
> + compatible = "maxim,max2175";
> + reg = <0x60>;
> + clocks = <&maxim_xtal>;
> + clock-names = "xtal";
> + maxim,refout-load = <10>;
> +
> + port {
> + max2175_0_ep: endpoint {
> + remote-endpoint = <&slave_rx_v4l2_sdr_device>;
> + };
> + };
> +
> +};
[snip]
> diff --git a/drivers/media/i2c/max2175/Makefile
> b/drivers/media/i2c/max2175/Makefile new file mode 100644
> index 0000000..9bb46ac
> --- /dev/null
> +++ b/drivers/media/i2c/max2175/Makefile
> @@ -0,0 +1,4 @@
> +#
> +# Makefile for Maxim RF to Bits tuner device
> +#
> +obj-$(CONFIG_SDR_MAX2175) += max2175.o
If there's a single source file you might want to move it to
drivers/media/i2c/.
> diff --git a/drivers/media/i2c/max2175/max2175.c
> b/drivers/media/i2c/max2175/max2175.c new file mode 100644
> index 0000000..71b60c2
> --- /dev/null
> +++ b/drivers/media/i2c/max2175/max2175.c
> @@ -0,0 +1,1624 @@
> +/*
> + * Maxim Integrated MAX2175 RF to Bits tuner driver
> + *
> + * This driver & most of the hard coded values are based on the reference
> + * application delivered by Maxim for this chip.
> + *
> + * Copyright (C) 2016 Maxim Integrated Products
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/errno.h>
> +#include <linux/i2c.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
You can move delay.h right below clk.h and everything will be in alphabetical
order :-)
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-device.h>
> +#include <media/v4l2-of.h>
> +
> +#include "max2175.h"
> +
> +#define DRIVER_NAME "max2175"
> +
> +static unsigned int max2175_debug;
> +module_param(max2175_debug, uint, 0644);
> +MODULE_PARM_DESC(max2175_debug, "activate debug info");
You can name the parameter "debug".
> +#define mxm_dbg(ctx, fmt, arg...) \
> + v4l2_dbg(1, max2175_debug, &ctx->sd, fmt, ## arg)
[snip]
> +/* Preset values:
> + * Based on Maxim MAX2175 Register Table revision: 130p10
> + */
The preferred multi-line comment style is
/*
* foo
* bar
*/
[snip]
> +struct max2175_ctx {
Nitpicking, such a structure would usually be named max2175 or max2175_device.
Context seems to imply that you can have multiple of them per device.
> + struct v4l2_subdev sd;
> + struct i2c_client *client;
> + struct device *dev;
> +
> + /* Cached configuration */
> + u8 regs[256];
If you want to cache register values you should use regmap.
> + enum max2175_modetag mode; /* Receive mode tag */
> + u32 freq; /* In Hz */
> + struct max2175_rxmode *rx_modes;
> +
> + /* Device settings */
> + bool master;
> + u32 decim_ratio;
> + u64 xtal_freq;
> +
> + /* ROM values */
> + u8 rom_bbf_bw_am;
> + u8 rom_bbf_bw_fm;
> + u8 rom_bbf_bw_dab;
> +
> + /* Local copy of old settings */
> + u8 i2s_test;
> +
> + u8 nbd_gain;
> + u8 nbd_threshold;
> + u8 wbd_gain;
> + u8 wbd_threshold;
> + u8 bbd_threshold;
> + u8 bbdclip_threshold;
> + u8 lt_wbd_threshold;
> + u8 lt_wbd_gain;
> +
> + /* Controls */
> + struct v4l2_ctrl_handler ctrl_hdl;
> + struct v4l2_ctrl *lna_gain; /* LNA gain value */
> + struct v4l2_ctrl *if_gain; /* I/F gain value */
> + struct v4l2_ctrl *pll_lock; /* PLL lock */
> + struct v4l2_ctrl *i2s_en; /* I2S output enable */
> + struct v4l2_ctrl *i2s_mode; /* I2S mode value */
> + struct v4l2_ctrl *am_hiz; /* AM High impledance input */
> + struct v4l2_ctrl *hsls; /* High-side/Low-side polarity */
> + struct v4l2_ctrl *rx_mode; /* Receive mode */
> +
> + /* Driver private variables */
> + bool mode_resolved; /* Flag to sanity check settings */
> +};
[snip]
> +/* Local store bitops helpers */
> +static u8 max2175_get_bits(struct max2175_ctx *ctx, u8 idx, u8 msb, u8 lsb)
> +{
> + if (max2175_debug >= 2)
> + mxm_dbg(ctx, "get_bits: idx:%u msb:%u lsb:%u\n",
> + idx, msb, lsb);
Do we really need such detailed debugging ?
> + return __max2175_get_bits(ctx->regs[idx], msb, lsb);
> +}
> +
> +static bool max2175_get_bit(struct max2175_ctx *ctx, u8 idx, u8 bit)
> +{
> + return !!max2175_get_bits(ctx, idx, bit, bit);
> +}
> +
> +static void max2175_set_bits(struct max2175_ctx *ctx, u8 idx,
> + u8 msb, u8 lsb, u8 newval)
> +{
> + if (max2175_debug >= 2)
> + mxm_dbg(ctx, "set_bits: idx:%u msb:%u lsb:%u newval:%u\n",
> + idx, msb, lsb, newval);
> + ctx->regs[idx] = __max2175_set_bits(ctx->regs[idx], msb, lsb,
> + newval);
> +}
> +
> +static void max2175_set_bit(struct max2175_ctx *ctx, u8 idx, u8 bit, u8
> newval)
> +{
> + max2175_set_bits(ctx, idx, bit, bit, newval);
> +}
> +
> +/* Device register bitops helpers */
> +static u8 max2175_read_bits(struct max2175_ctx *ctx, u8 idx, u8 msb, u8
> lsb)
> +{
> + return __max2175_get_bits(max2175_reg_read(ctx, idx), msb, lsb);
> +}
> +
> +static void max2175_write_bits(struct max2175_ctx *ctx, u8 idx, u8 msb,
> + u8 lsb, u8 newval)
> +{
> + /* Update local copy & write to device */
> + max2175_set_bits(ctx, idx, msb, lsb, newval);
> + max2175_reg_write(ctx, idx, ctx->regs[idx]);
> +}
> +
> +static void max2175_write_bit(struct max2175_ctx *ctx, u8 idx, u8 bit,
> + u8 newval)
> +{
> + if (max2175_debug >= 2)
> + mxm_dbg(ctx, "idx %u, bit %u, newval %u\n", idx, bit, newval);
> + max2175_write_bits(ctx, idx, bit, bit, newval);
> +}
Really, please use regmap :-)
> +static int max2175_poll_timeout(struct max2175_ctx *ctx, u8 idx, u8 msb, u8
> lsb,
> + u8 exp_val, u32 timeout)
> +{
> + unsigned long end = jiffies + msecs_to_jiffies(timeout);
> + int ret;
> +
> + do {
> + ret = max2175_read_bits(ctx, idx, msb, lsb);
> + if (ret < 0)
> + return ret;
> + if (ret == exp_val)
> + return 0;
> +
> + usleep_range(1000, 1500);
> + } while (time_is_after_jiffies(end));
> +
> + return -EBUSY;
> +}
> +
> +static int max2175_poll_csm_ready(struct max2175_ctx *ctx)
> +{
> + return max2175_poll_timeout(ctx, 69, 1, 1, 0, 50);
Please define macros for register addresses and values, this is just
unreadable.
> +}
[snip]
> +
> +#define MAX2175_IS_BAND_AM(ctx) \
> + (max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_AM)
> +
> +#define MAX2175_IS_FM_MODE(ctx) \
> + (max2175_get_bits(ctx, 12, 5, 4) == 0)
> +
> +#define MAX2175_IS_FMHD_MODE(ctx) \
> + (max2175_get_bits(ctx, 12, 5, 4) == 1)
> +
> +#define MAX2175_IS_DAB_MODE(ctx) \
> + (max2175_get_bits(ctx, 12, 5, 4) == 2)
> +
> +static int max2175_band_from_freq(u64 freq)
> +{
> + if (freq >= 144000 && freq <= 26100000)
> + return MAX2175_BAND_AM;
> + else if (freq >= 65000000 && freq <= 108000000)
> + return MAX2175_BAND_FM;
> + else if (freq >= 160000000 && freq <= 240000000)
> + return MAX2175_BAND_VHF;
> +
> + /* Add other bands on need basis */
> + return -ENOTSUPP;
> +}
> +
> +static int max2175_update_i2s_mode(struct max2175_ctx *ctx, u32 i2s_mode)
> +{
> + /* Only change if it's new */
> + if (max2175_read_bits(ctx, 29, 2, 0) == i2s_mode)
> + return 0;
> +
> + max2175_write_bits(ctx, 29, 2, 0, i2s_mode);
> +
> + /* Based on I2S mode value I2S_WORD_CNT values change */
> + if (i2s_mode == MAX2175_I2S_MODE3) {
> + max2175_write_bits(ctx, 30, 6, 0, 1);
> + } else if (i2s_mode == MAX2175_I2S_MODE2 ||
> + i2s_mode == MAX2175_I2S_MODE4) {
> + max2175_write_bits(ctx, 30, 6, 0, 0);
> + } else if (i2s_mode == MAX2175_I2S_MODE0) {
> + max2175_write_bits(ctx, 30, 6, 0,
> + ctx->rx_modes[ctx->mode].i2s_word_size);
> + } else {
> + v4l2_err(ctx->client,
> + "failed: i2s_mode %u unsupported\n", i2s_mode);
This should never happen as the control framework will validate control
values.
> + return 1;
Error codes should be negative.
> + }
> + mxm_dbg(ctx, "updated i2s_mode %u\n", i2s_mode);
> + return 0;
> +}
[snip]
> +static void max2175_load_dab_1p2(struct max2175_ctx *ctx)
> +{
> + u32 i;
unsigned int will do, no need for an explicitly sized type.
> +
> + /* Master is already set on init */
> + for (i = 0; i < ARRAY_SIZE(dab12_map); i++)
> + max2175_reg_write(ctx, dab12_map[i].idx, dab12_map[i].val);
> +
> + /* The default settings assume master */
> + if (!ctx->master)
> + max2175_write_bit(ctx, 30, 7, 1);
> +
> + /* Cache i2s_test value at this point */
> + ctx->i2s_test = max2175_get_bits(ctx, 104, 3, 0);
> + ctx->decim_ratio = 1;
> +
> + /* Load the Channel Filter Coefficients into channel filter bank #2 */
> + max2175_set_filter_coeffs(ctx, MAX2175_CH_MSEL, 2, ch_coeff_dab1);
> +}
[snip]
> +static bool max2175_set_csm_mode(struct max2175_ctx *ctx,
> + enum max2175_csm_mode new_mode)
> +{
> + int ret = max2175_poll_csm_ready(ctx);
> +
> + if (ret) {
> + v4l2_err(ctx->client, "csm not ready: new mode %d\n",
new_mode);
> + return ret;
> + }
> +
> + mxm_dbg(ctx, "set csm mode: new mode %d\n", new_mode);
> +
> + max2175_write_bits(ctx, 0, 2, 0, new_mode);
> +
> + /* Wait for a fixed settle down time depending on new mode and band */
> + switch (new_mode) {
> + case MAX2175_CSM_MODE_JUMP_FAST_TUNE:
> + if (MAX2175_IS_BAND_AM(ctx)) {
> + usleep_range(1250, 1500); /* 1.25ms */
> + } else {
> + if (MAX2175_IS_DAB_MODE(ctx))
> + usleep_range(3000, 3500); /* 3ms */
> + else
> + usleep_range(1250, 1500); /* 1.25ms */
> + }
You can write this as
if (MAX2175_IS_BAND_AM(ctx))
usleep_range(1250, 1500); /* 1.25ms */
else if (MAX2175_IS_DAB_MODE(ctx))
usleep_range(3000, 3500); /* 3ms */
else
usleep_range(1250, 1500); /* 1.25ms */
> + break;
> +
> + /* Other mode switches can be added in the future if needed */
> + default:
> + break;
> + }
> +
> + ret = max2175_poll_csm_ready(ctx);
> + if (ret) {
> + v4l2_err(ctx->client, "csm did not settle: new mode %d\n",
> + new_mode);
> + return ret;
> + }
> + return ret;
> +}
[snip]
> +
> +static int max2175_csm_action(struct max2175_ctx *ctx,
> + enum max2175_csm_mode action)
> +{
> + int ret;
> + int load_buffer = MAX2175_CSM_MODE_LOAD_TO_BUFFER;
> +
> + mxm_dbg(ctx, "csm action: %d\n", action);
> +
> + /* Perform one or two CSM mode commands. */
> + switch (action) {
> + case MAX2175_CSM_MODE_NO_ACTION:
> + /* Take no FSM Action. */
> + return 0;
> + case MAX2175_CSM_MODE_LOAD_TO_BUFFER:
> + case MAX2175_CSM_MODE_PRESET_TUNE:
> + case MAX2175_CSM_MODE_SEARCH:
> + case MAX2175_CSM_MODE_AF_UPDATE:
> + case MAX2175_CSM_MODE_JUMP_FAST_TUNE:
> + case MAX2175_CSM_MODE_CHECK:
> + case MAX2175_CSM_MODE_LOAD_AND_SWAP:
> + case MAX2175_CSM_MODE_END:
> + ret = max2175_set_csm_mode(ctx, action);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_PRESET_TUNE:
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
> + ret = max2175_set_csm_mode(ctx, MAX2175_CSM_MODE_PRESET_TUNE);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_SEARCH:
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
Don't duplicate the error messages, move them after the switch statement.
> + ret = max2175_set_csm_mode(ctx, MAX2175_CSM_MODE_SEARCH);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_AF_UPDATE:
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
> + ret = max2175_set_csm_mode(ctx, MAX2175_CSM_MODE_AF_UPDATE);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_JUMP_FAST_TUNE:
This function is only called with action set to
MAX2175_CSM_MODE_BUFFER_PLUS_JUMP_FAST_TUNE. I'd remove the rest of the code
for now, unless you have a plan to use it soon.
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
> + ret = max2175_set_csm_mode(ctx,
> + MAX2175_CSM_MODE_JUMP_FAST_TUNE);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_CHECK:
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
> + ret = max2175_set_csm_mode(ctx, MAX2175_CSM_MODE_CHECK);
> + break;
> + case MAX2175_CSM_MODE_BUFFER_PLUS_LOAD_AND_SWAP:
> + ret = max2175_set_csm_mode(ctx, load_buffer);
> + if (ret) {
> + v4l2_err(ctx->client, "csm action %d load buf
failed\n",
> + action);
> + break;
> + }
> + ret = max2175_set_csm_mode(ctx,
MAX2175_CSM_MODE_LOAD_AND_SWAP);
> + break;
> + default:
> + ret = max2175_set_csm_mode(ctx, MAX2175_CSM_MODE_NO_ACTION);
> + break;
> + }
> + return ret;
> +}
> +
> +static int max2175_set_lo_freq(struct max2175_ctx *ctx, u64 lo_freq)
> +{
> + int ret;
> + u32 lo_mult;
> + u64 scaled_lo_freq;
> + const u64 scale_factor = 1000000ULL;
> + u64 scaled_npf, scaled_integer, scaled_fraction;
> + u32 frac_desired, int_desired;
> + u8 loband_bits, vcodiv_bits;
Do you really support frequencies above 4GHz ? If not most of the 64-bit
values could be stored in 32 bits.
> +
> + scaled_lo_freq = lo_freq;
> + /* Scale to larger number for precision */
> + scaled_lo_freq = scaled_lo_freq * scale_factor * 100;
> +
> + mxm_dbg(ctx, "scaled lo_freq %llu lo_freq %llu\n",
> + scaled_lo_freq, lo_freq);
> +
> + if (MAX2175_IS_BAND_AM(ctx)) {
> + if (max2175_get_bit(ctx, 5, 7) == 0)
> + loband_bits = 0;
> + vcodiv_bits = 0;
> + lo_mult = 16;
> + } else if (max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_FM) {
> + if (lo_freq <= 74700000) {
> + loband_bits = 0;
> + vcodiv_bits = 0;
> + lo_mult = 16;
> + } else if ((lo_freq > 74700000) && (lo_freq <= 110000000)) {
No need for the inner parentheses.
> + loband_bits = 1;
> + vcodiv_bits = 0;
> + } else {
> + loband_bits = 1;
> + vcodiv_bits = 3;
> + }
> + lo_mult = 8;
> + } else if (max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF) {
> + if (lo_freq <= 210000000) {
> + loband_bits = 2;
> + vcodiv_bits = 2;
> + } else {
> + loband_bits = 2;
> + vcodiv_bits = 1;
> + }
> + lo_mult = 4;
> + } else {
> + loband_bits = 3;
> + vcodiv_bits = 2;
> + lo_mult = 2;
> + }
> +
> + if (max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_L)
> + scaled_npf = (scaled_lo_freq / ctx->xtal_freq / lo_mult) /
100;
> + else
> + scaled_npf = (scaled_lo_freq / ctx->xtal_freq * lo_mult) /
100;
> +
> + scaled_integer = scaled_npf / scale_factor * scale_factor;
> + int_desired = (u32)(scaled_npf / scale_factor);
> + scaled_fraction = scaled_npf - scaled_integer;
> + frac_desired = (u32)(scaled_fraction * 1048576 / scale_factor);
> +
> + /* Check CSM is not busy */
> + ret = max2175_poll_csm_ready(ctx);
> + if (ret) {
> + v4l2_err(ctx->client, "lo_freq: csm busy. freq %llu\n",
> + lo_freq);
> + return ret;
> + }
> +
> + mxm_dbg(ctx, "loband %u vcodiv %u lo_mult %u scaled_npf %llu\n",
> + loband_bits, vcodiv_bits, lo_mult, scaled_npf);
> + mxm_dbg(ctx, "scaled int %llu frac %llu desired int %u frac %u\n",
> + scaled_integer, scaled_fraction, int_desired, frac_desired);
> +
> + /* Write the calculated values to the appropriate registers */
> + max2175_set_bits(ctx, 5, 3, 2, loband_bits);
> + max2175_set_bits(ctx, 6, 7, 6, vcodiv_bits);
> + max2175_set_bits(ctx, 1, 7, 0, (u8)(int_desired & 0xff));
> + max2175_set_bits(ctx, 2, 3, 0, (u8)((frac_desired >> 16) & 0x1f));
> + max2175_set_bits(ctx, 3, 7, 0, (u8)((frac_desired >> 8) & 0xff));
> + max2175_set_bits(ctx, 4, 7, 0, (u8)(frac_desired & 0xff));
> + /* Flush the above registers to device */
> + max2175_flush_regstore(ctx, 1, 6);
> + return ret;
> +}
[snip]
> +static int max2175_set_rf_freq_non_am_bands(struct max2175_ctx *ctx, u64
> freq,
> + u32 lo_pos)
> +{
> + int ret;
> + s64 adj_freq;
> + u64 low_if_freq;
> +
> + mxm_dbg(ctx, "rf_freq: non AM bands\n");
> +
> + if (MAX2175_IS_FM_MODE(ctx))
> + low_if_freq = 128000;
> + else if (MAX2175_IS_FMHD_MODE(ctx))
> + low_if_freq = 228000;
> + else
> + return max2175_set_lo_freq(ctx, freq);
> +
> + if (max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF) {
You perform this check in multiple places, you could create a helper function.
> + if (lo_pos == MAX2175_LO_ABOVE_DESIRED)
> + adj_freq = freq + low_if_freq;
> + else
> + adj_freq = freq - low_if_freq;
> + } else {
> + if (lo_pos == MAX2175_LO_ABOVE_DESIRED)
> + adj_freq = freq - low_if_freq;
> + else
> + adj_freq = freq + low_if_freq;
> + }
This could be written
if ((max2175_get_bits(ctx, 5, 1, 0) == MAX2175_BAND_VHF) ==
(lo_pos == MAX2175_LO_ABOVE_DESIRED))
adj_freq = freq + low_if_freq;
else
adj_freq = freq - low_if_freq;
Same for the other similar constructs in the driver. Up to you.
> +
> + ret = max2175_set_lo_freq(ctx, adj_freq);
> + if (ret)
> + return ret;
> +
> + return max2175_set_nco_freq(ctx, low_if_freq);
> +}
[snip]
> +#define max2175_ctx_from_sd(x) \
> + container_of(x, struct max2175_ctx, sd)
> +#define max2175_ctx_from_ctrl(x) \
> + container_of(x, struct max2175_ctx, ctrl_hdl)
I'd move it right after the structure definition, and turn them into static
inline functions.
> +static int max2175_s_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct max2175_ctx *ctx = max2175_ctx_from_ctrl(ctrl->handler);
> + int ret = 0;
> +
> + mxm_dbg(ctx, "s_ctrl: id 0x%x, val %u\n", ctrl->id, ctrl->val);
> + switch (ctrl->id) {
> + case V4L2_CID_MAX2175_I2S_EN:
> + max2175_i2s_enable(ctx, ctrl->val == 1);
> + break;
> + case V4L2_CID_MAX2175_I2S_MODE:
> + max2175_s_ctrl_i2s_mode(ctx, ctrl->val);
> + break;
> + case V4L2_CID_MAX2175_AM_HIZ:
> + v4l2_ctrl_activate(ctx->am_hiz, false);
> + break;
> + case V4L2_CID_MAX2175_HSLS:
> + v4l2_ctrl_activate(ctx->hsls, false);
> + break;
> + case V4L2_CID_MAX2175_RX_MODE:
> + mxm_dbg(ctx, "rx mode %u\n", ctrl->val);
> + max2175_s_ctrl_rx_mode(ctx, ctrl->val);
> + break;
> + default:
> + v4l2_err(ctx->client, "s:invalid ctrl id 0x%x\n", ctrl->id);
> + ret = -EINVAL;
This should never happen. The driver has too many error and debug messages
overall.
> + }
> +
> + return ret;
> +}
> +
> +static int max2175_get_lna_gain(struct max2175_ctx *ctx)
> +{
> + int gain = 0;
> + enum max2175_band band = max2175_get_bits(ctx, 5, 1, 0);
> +
> + switch (band) {
> + case MAX2175_BAND_AM:
> + gain = max2175_read_bits(ctx, 51, 3, 1);
> + break;
> + case MAX2175_BAND_FM:
> + gain = max2175_read_bits(ctx, 50, 3, 1);
> + break;
> + case MAX2175_BAND_VHF:
> + gain = max2175_read_bits(ctx, 52, 3, 0);
> + break;
> + default:
> + v4l2_err(ctx->client, "invalid band %d to get rf gain\n",
band);
Can this happen ?
> + break;
> + }
> + return gain;
> +}
> +
> +static int max2175_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
> +{
> + struct max2175_ctx *ctx = max2175_ctx_from_ctrl(ctrl->handler);
> +
> + /* Only the dynamically changing values need to be in g_volatile_ctrl
*/
> + mxm_dbg(ctx, "g_volatile_ctrl: id 0x%x\n", ctrl->id);
> + switch (ctrl->id) {
> + case V4L2_CID_RF_TUNER_LNA_GAIN:
> + ctrl->val = max2175_get_lna_gain(ctx);
> + break;
> + case V4L2_CID_RF_TUNER_IF_GAIN:
> + ctrl->val = max2175_read_bits(ctx, 49, 4, 0);
> + break;
> + case V4L2_CID_RF_TUNER_PLL_LOCK:
> + ctrl->val = (max2175_read_bits(ctx, 60, 7, 6) == 3);
> + break;
> + default:
> + v4l2_err(ctx->client, "g:invalid ctrl id 0x%x\n", ctrl->id);
This should never happen either.
> + return -EINVAL;
> + }
> + mxm_dbg(ctx, "g_volatile_ctrl: id 0x%x val %d\n", ctrl->id, ctrl-
>val);
> + return 0;
> +};
[snip]
> +static const struct v4l2_ctrl_config max2175_i2s_en = {
> + .ops = &max2175_ctrl_ops,
> + .id = V4L2_CID_MAX2175_I2S_EN,
V4L2_CID_MAX2175_I2S_ENABLE ?
> + .name = "I2S Enable",
> + .type = V4L2_CTRL_TYPE_BOOLEAN,
> + .min = 0,
> + .max = 1,
> + .step = 1,
> + .def = 1,
> +};
> +
> +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_INTEGER,
Should this be a menu control ?
> + .min = 0,
> + .max = 4,
> + .step = 1,
> + .def = 0,
> +};
> +
> +static const struct v4l2_ctrl_config max2175_am_hiz = {
> + .ops = &max2175_ctrl_ops,
> + .id = V4L2_CID_MAX2175_AM_HIZ,
> + .name = "AM High impedance input",
> + .type = V4L2_CTRL_TYPE_BOOLEAN,
> + .min = 0,
> + .max = 1,
> + .step = 1,
> + .def = 0,
> +};
> +
> +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,
> +};
> +
> +
> +/* NOTE: Any addition/deletion in the below list should be reflected in
> + * max2175_modetag enum
> + */
> +static const char * const max2175_ctrl_eu_rx_mode_strings[] = {
> + "DAB 1.2",
> + "NULL",
Do you really mean "NULL", not NULL ?
> +};
> +
> +static const char * const max2175_ctrl_na_rx_mode_strings[] = {
> + "NA FM 1.0",
> + "NULL",
> +};
> +
> +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_mode_strings) - 2,
If there's a single mode supported I'd skip adding those controls for now.
> + .def = 0,
> + .qmenu = max2175_ctrl_eu_rx_mode_strings,
> +};
> +
> +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_mode_strings) - 2,
> + .def = 0,
> + .qmenu = max2175_ctrl_na_rx_mode_strings,
> +};
> +
> +static u32 max2175_refout_load_to_bits(struct i2c_client *client, u32 load)
> +{
> + u32 bits = 0; /* REFOUT disabled */
> +
> + if (load >= 0 && load <= 40)
> + bits = load / 10;
> + else if (load >= 60 && load <= 70)
> + bits = load / 10 - 1;
> + else
> + dev_warn(&client->dev, "invalid refout_load %u\n", load);
Your DT bindings specify 0 as a valid value.
An invalid value specified in DT should be a fatal error.
> +
> + return bits;
> +}
> +
> +static int max2175_probe(struct i2c_client *client,
> + const struct i2c_device_id *id)
> +{
> + struct max2175_ctx *ctx;
> + struct device *dev = &client->dev;
> + struct v4l2_subdev *sd;
> + struct v4l2_ctrl_handler *hdl;
> + struct clk *clk;
> + bool master = true;
> + u32 refout_load, refout_bits = 0; /* REFOUT disabled */
> + int ret;
> +
> + /* Check if the adapter supports the needed features */
> + if (!i2c_check_functionality(client->adapter,
> + I2C_FUNC_SMBUS_BYTE_DATA)) {
> + dev_err(&client->dev, "i2c check failed\n");
> + return -EIO;
> + }
> +
> + if (of_find_property(client->dev.of_node, "maxim,slave", NULL))
> + master = false;
> +
> + if (!of_property_read_u32(client->dev.of_node, "maxim,refout-load",
> + &refout_load))
> + refout_bits = max2175_refout_load_to_bits(client,
refout_load);
> +
> + clk = devm_clk_get(&client->dev, "xtal");
> + if (IS_ERR(clk)) {
> + ret = PTR_ERR(clk);
> + dev_err(&client->dev, "cannot get xtal clock %d\n", ret);
> + return -ENODEV;
> + }
> +
> + ctx = kzalloc(sizeof(struct max2175_ctx),
sizeof(*ctx)
> + GFP_KERNEL);
This fits on one line.
> + if (ctx == NULL)
> + return -ENOMEM;
> +
> + sd = &ctx->sd;
> + ctx->master = master;
> + ctx->mode_resolved = false;
> +
> + /* Set the defaults */
> + ctx->freq = bands_rf.rangelow;
> +
> + ctx->xtal_freq = clk_get_rate(clk);
> + dev_info(&client->dev, "xtal freq %lluHz\n", ctx->xtal_freq);
> +
> + v4l2_i2c_subdev_init(sd, client, &max2175_ops);
> + ctx->client = client;
> +
> + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
> + ctx->dev = dev;
> +
> + /* Controls */
> + hdl = &ctx->ctrl_hdl;
> + ret = v4l2_ctrl_handler_init(hdl, 8);
> + if (ret) {
> + dev_err(&client->dev, "ctrl handler init failed\n");
> + goto err;
> + }
> +
> + ctx->lna_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> + V4L2_CID_RF_TUNER_LNA_GAIN,
> + 0, 15, 1, 2);
> + ctx->lna_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> + V4L2_CTRL_FLAG_READ_ONLY);
> + ctx->if_gain = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> + V4L2_CID_RF_TUNER_IF_GAIN,
> + 0, 31, 1, 0);
> + ctx->if_gain->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> + V4L2_CTRL_FLAG_READ_ONLY);
> + ctx->pll_lock = v4l2_ctrl_new_std(hdl, &max2175_ctrl_ops,
> + V4L2_CID_RF_TUNER_PLL_LOCK,
> + 0, 1, 1, 0);
> + ctx->pll_lock->flags |= (V4L2_CTRL_FLAG_VOLATILE |
> + V4L2_CTRL_FLAG_READ_ONLY);
> + ctx->i2s_en = v4l2_ctrl_new_custom(hdl, &max2175_i2s_en, NULL);
> + ctx->i2s_mode = v4l2_ctrl_new_custom(hdl, &max2175_i2s_mode, NULL);
> + ctx->am_hiz = v4l2_ctrl_new_custom(hdl, &max2175_am_hiz, NULL);
> + ctx->hsls = v4l2_ctrl_new_custom(hdl, &max2175_hsls, NULL);
> +
> + if (ctx->xtal_freq == MAX2175_EU_XTAL_FREQ) {
> + ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
> + &max2175_eu_rx_mode,
NULL);
> + ctx->rx_modes = (struct max2175_rxmode *)eu_rx_modes;
> + } else {
> + ctx->rx_mode = v4l2_ctrl_new_custom(hdl,
> + &max2175_na_rx_mode,
NULL);
> + ctx->rx_modes = (struct max2175_rxmode *)na_rx_modes;
> + }
> + ctx->sd.ctrl_handler = &ctx->ctrl_hdl;
> +
> + ret = v4l2_async_register_subdev(sd);
> + if (ret) {
> + dev_err(&client->dev, "register subdev failed\n");
> + goto err_reg;
> + }
> + dev_info(&client->dev, "subdev registered\n");
> +
> + /* Initialize device */
> + ret = max2175_core_init(ctx, refout_bits);
> + if (ret)
> + goto err_init;
> +
> + mxm_dbg(ctx, "probed\n");
> + return 0;
> +
> +err_init:
> + v4l2_async_unregister_subdev(sd);
> +err_reg:
> + v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> +err:
> + kfree(ctx);
> + return ret;
> +}
> +
> +static int max2175_remove(struct i2c_client *client)
> +{
> + struct v4l2_subdev *sd = i2c_get_clientdata(client);
> + struct max2175_ctx *ctx = max2175_ctx_from_sd(sd);
> +
> + v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
> + v4l2_async_unregister_subdev(sd);
> + mxm_dbg(ctx, "removed\n");
> + kfree(ctx);
> + return 0;
> +}
> +
> +static const struct i2c_device_id max2175_id[] = {
> + { DRIVER_NAME, 0},
> + {},
> +};
> +
No need for a blank line here.
> +MODULE_DEVICE_TABLE(i2c, max2175_id);
> +
> +static const struct of_device_id max2175_of_ids[] = {
> + { .compatible = "maxim, max2175", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, max2175_of_ids);
> +
> +static struct i2c_driver max2175_driver = {
> + .driver = {
> + .name = DRIVER_NAME,
> + .of_match_table = max2175_of_ids,
> + },
> + .probe = max2175_probe,
> + .remove = max2175_remove,
> + .id_table = max2175_id,
> +};
> +
> +module_i2c_driver(max2175_driver);
> +
> +MODULE_DESCRIPTION("Maxim MAX2175 RF to Bits tuner driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_AUTHOR("Ramesh Shanmugasundaram
> <ramesh.shanmugasundaram@bp.renesas.com>"); diff --git
> a/drivers/media/i2c/max2175/max2175.h b/drivers/media/i2c/max2175/max2175.h
> new file mode 100644
> index 0000000..61a508b
> --- /dev/null
> +++ b/drivers/media/i2c/max2175/max2175.h
> @@ -0,0 +1,124 @@
> +/*
> + * Maxim Integrated MAX2175 RF to Bits tuner driver
> + *
> + * This driver & most of the hard coded values are based on the reference
> + * application delivered by Maxim for this chip.
> + *
> + * Copyright (C) 2016 Maxim Integrated Products
> + * Copyright (C) 2016 Renesas Electronics Corporation
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2
> + * as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __MAX2175_H__
> +#define __MAX2175_H__
> +
> +#include <linux/types.h>
> +
> +enum max2175_region {
> + MAX2175_REGION_EU = 0, /* Europe */
> + MAX2175_REGION_NA, /* North America */
> +};
> +
> +#define MAX2175_EU_XTAL_FREQ (36864000) /* In Hz */
> +#define MAX2175_NA_XTAL_FREQ (40186125) /* In Hz */
> +
> +enum max2175_band {
> + MAX2175_BAND_AM = 0,
> + MAX2175_BAND_FM,
> + MAX2175_BAND_VHF,
> + MAX2175_BAND_L,
> +};
> +
> +/* NOTE: Any addition/deletion in the below enum should be reflected in
> + * V4L2_CID_MAX2175_RX_MODE ctrl strings
> + */
> +enum max2175_modetag {
> + /* EU modes */
> + MAX2175_DAB_1_2 = 0,
> +
> + /* Other possible modes to add in future
> + * MAX2175_DAB_1_0,
> + * MAX2175_DAB_1_3,
> + * MAX2175_EU_FM_2_2,
> + * MAX2175_EU_FM_1_0,
> + * MAX2175_EU_FMHD_4_0,
> + * MAX2175_EU_AM_1_0,
> + * MAX2175_EU_AM_2_2,
> + */
> +
> + /* NA modes */
> + MAX2175_NA_FM_1_0 = 0,
> +
> + /* Other possible modes to add in future
> + * MAX2175_NA_FM_1_2,
> + * MAX2175_NA_FMHD_1_0,
> + * MAX2175_NA_FMHD_1_2,
> + * MAX2175_NA_AM_1_0,
> + * MAX2175_NA_AM_1_2,
> + */
> +};
> +
> +/* Supported I2S modes */
> +enum {
> + MAX2175_I2S_MODE0 = 0,
> + MAX2175_I2S_MODE1,
> + MAX2175_I2S_MODE2,
> + MAX2175_I2S_MODE3,
> + MAX2175_I2S_MODE4,
> +};
> +
> +/* Coefficient table groups */
> +enum {
> + MAX2175_CH_MSEL = 0,
> + MAX2175_EQ_MSEL,
> + MAX2175_AA_MSEL,
> +};
> +
> +/* HSLS LO injection polarity */
> +enum {
> + MAX2175_LO_BELOW_DESIRED = 0,
> + MAX2175_LO_ABOVE_DESIRED,
> +};
> +
> +/* Channel FSM modes */
> +enum max2175_csm_mode {
> + MAX2175_CSM_MODE_LOAD_TO_BUFFER = 0,
> + MAX2175_CSM_MODE_PRESET_TUNE,
> + MAX2175_CSM_MODE_SEARCH,
> + MAX2175_CSM_MODE_AF_UPDATE,
> + MAX2175_CSM_MODE_JUMP_FAST_TUNE,
> + MAX2175_CSM_MODE_CHECK,
> + MAX2175_CSM_MODE_LOAD_AND_SWAP,
> + MAX2175_CSM_MODE_END,
> + MAX2175_CSM_MODE_BUFFER_PLUS_PRESET_TUNE,
> + MAX2175_CSM_MODE_BUFFER_PLUS_SEARCH,
> + MAX2175_CSM_MODE_BUFFER_PLUS_AF_UPDATE,
> + MAX2175_CSM_MODE_BUFFER_PLUS_JUMP_FAST_TUNE,
> + MAX2175_CSM_MODE_BUFFER_PLUS_CHECK,
> + MAX2175_CSM_MODE_BUFFER_PLUS_LOAD_AND_SWAP,
> + MAX2175_CSM_MODE_NO_ACTION
> +};
> +
> +/* Rx mode */
> +struct max2175_rxmode {
> + enum max2175_band band; /* Associated band */
> + u32 freq; /* Default freq in Hz */
> + u8 i2s_word_size; /* Bit value */
> + u8 i2s_modes[4]; /* Supported modes */
> +};
> +
> +/* Register map */
> +struct max2175_regmap {
> + u8 idx; /* Register index */
> + u8 val; /* Register value */
> +};
As no other file than max2175.c includes this, I would move at least the
structure definitions to the .c file.
> +#endif /* __MAX2175_H__ */
--
Regards,
Laurent Pinchart
next prev parent reply other threads:[~2016-10-18 19:25 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-10-12 14:10 [RFC 0/5] Add V4L2 SDR (DRIF & MAX2175) driver Ramesh Shanmugasundaram
2016-10-12 14:10 ` [RFC 1/5] media: i2c: max2175: Add MAX2175 support Ramesh Shanmugasundaram
[not found] ` <1476281429-27603-2-git-send-email-ramesh.shanmugasundaram-kTT6dE0pTRh9uiUsa/gSgQ@public.gmane.org>
2016-10-15 12:42 ` Geert Uytterhoeven
[not found] ` <CAMuHMdUYQoJL4h8prEpontF4YH8Ha+SWDdeZHYEV3_uMZ-SBXw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-10-18 15:04 ` Ramesh Shanmugasundaram
2016-10-18 19:25 ` Laurent Pinchart [this message]
2016-10-21 14:49 ` Ramesh Shanmugasundaram
2016-11-10 8:46 ` Laurent Pinchart
2016-10-12 14:10 ` [RFC 2/5] media: v4l2-ctrls: Reserve controls for MAX217X Ramesh Shanmugasundaram
2016-10-12 14:10 ` [RFC 3/5] media: platform: rcar_drif: Add DRIF support Ramesh Shanmugasundaram
2016-10-18 13:13 ` Rob Herring
2016-10-18 15:13 ` Ramesh Shanmugasundaram
2016-10-18 14:29 ` Geert Uytterhoeven
2016-10-18 18:26 ` Laurent Pinchart
2016-10-21 13:17 ` Ramesh Shanmugasundaram
[not found] ` <CAMuHMdXvGEm3bdNOsa6Q1FLB9yMSTAzO4nHcCb-pnYYwg6f6Cg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2016-10-21 13:15 ` Ramesh Shanmugasundaram
2016-10-12 14:10 ` [RFC 4/5] media: Add new SDR formats SC16, SC18 & SC20 Ramesh Shanmugasundaram
2016-10-12 14:10 ` [RFC 5/5] doc_rst: media: New " Ramesh Shanmugasundaram
[not found] ` <1476281429-27603-6-git-send-email-ramesh.shanmugasundaram-kTT6dE0pTRh9uiUsa/gSgQ@public.gmane.org>
2016-10-18 18:35 ` Laurent Pinchart
2016-10-24 10:19 ` Ramesh Shanmugasundaram
2016-11-02 9:00 ` Ramesh Shanmugasundaram
[not found] ` <SG2PR06MB10389152CEC59BB77A5DA7DDC3A00-ESzmfEwOt/zfc7TNChRnj20DtJ1/0DrXvxpqHgZTriW3zl9H0oFU5g@public.gmane.org>
2016-11-02 20:58 ` Laurent Pinchart
2016-11-03 20:36 ` Antti Palosaari
2016-11-04 9:23 ` Ramesh Shanmugasundaram
2016-11-10 8:08 ` Laurent Pinchart
2016-11-11 4:54 ` Antti Palosaari
2016-11-11 13:53 ` Hans Verkuil
[not found] ` <8438b944-216e-3237-c312-92a674fd4541-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2016-11-11 13:57 ` Laurent Pinchart
2016-11-11 14:00 ` Hans Verkuil
[not found] ` <fb15b6f3-6c5c-0922-8655-aabd4799d158-qWit8jRvyhVmR6Xm/wNWPw@public.gmane.org>
2016-11-14 15:53 ` Ramesh Shanmugasundaram
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=2034831.3otZHvJ6bZ@avalon \
--to=laurent.pinchart@ideasonboard.com \
--cc=chris.paterson2@renesas.com \
--cc=crope@iki.fi \
--cc=devicetree@vger.kernel.org \
--cc=geert@linux-m68k.org \
--cc=hverkuil@xs4all.nl \
--cc=linux-media@vger.kernel.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=mchehab@kernel.org \
--cc=ramesh.shanmugasundaram@bp.renesas.com \
--cc=robh+dt@kernel.org \
--cc=sakari.ailus@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).