summaryrefslogtreecommitdiffstats
path: root/drivers/media/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r--drivers/media/i2c/Kconfig6
-rw-r--r--drivers/media/i2c/ad5820.c5
-rw-r--r--drivers/media/i2c/adv7604.c24
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c11
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c7
-rw-r--r--drivers/media/i2c/smiapp-pll.c3
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c916
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.c4
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h28
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c3
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c3
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c3
-rw-r--r--drivers/media/i2c/tvaudio.c5
-rw-r--r--drivers/media/i2c/tvp514x.c6
14 files changed, 522 insertions, 502 deletions
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 2669b4bad910..b31fa6fae009 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -221,7 +221,7 @@ config VIDEO_ADV7604
config VIDEO_ADV7604_CEC
bool "Enable Analog Devices ADV7604 CEC support"
- depends on VIDEO_ADV7604 && MEDIA_CEC
+ depends on VIDEO_ADV7604 && MEDIA_CEC_SUPPORT
---help---
When selected the adv7604 will support the optional
HDMI CEC feature.
@@ -242,7 +242,7 @@ config VIDEO_ADV7842
config VIDEO_ADV7842_CEC
bool "Enable Analog Devices ADV7842 CEC support"
- depends on VIDEO_ADV7842 && MEDIA_CEC
+ depends on VIDEO_ADV7842 && MEDIA_CEC_SUPPORT
---help---
When selected the adv7842 will support the optional
HDMI CEC feature.
@@ -481,7 +481,7 @@ config VIDEO_ADV7511
config VIDEO_ADV7511_CEC
bool "Enable Analog Devices ADV7511 CEC support"
- depends on VIDEO_ADV7511 && MEDIA_CEC
+ depends on VIDEO_ADV7511 && MEDIA_CEC_SUPPORT
---help---
When selected the adv7511 will support the optional
HDMI CEC feature.
diff --git a/drivers/media/i2c/ad5820.c b/drivers/media/i2c/ad5820.c
index beab2f381b81..a9026a91855e 100644
--- a/drivers/media/i2c/ad5820.c
+++ b/drivers/media/i2c/ad5820.c
@@ -65,16 +65,17 @@ static int ad5820_write(struct ad5820_device *coil, u16 data)
{
struct i2c_client *client = v4l2_get_subdevdata(&coil->subdev);
struct i2c_msg msg;
+ __be16 be_data;
int r;
if (!client->adapter)
return -ENODEV;
- data = cpu_to_be16(data);
+ be_data = cpu_to_be16(data);
msg.addr = client->addr;
msg.flags = 0;
msg.len = 2;
- msg.buf = (u8 *)&data;
+ msg.buf = (u8 *)&be_data;
r = i2c_transfer(client->adapter, &msg, 1);
if (r < 0) {
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 4003831de712..5630eb22daaa 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -1566,10 +1566,24 @@ static int adv76xx_query_dv_timings(struct v4l2_subdev *sd,
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
if (is_digital_input(sd)) {
+ bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
+ u8 vic = 0;
+ u32 w, h;
+
+ w = hdmi_read16(sd, 0x07, info->linewidth_mask);
+ h = hdmi_read16(sd, 0x09, info->field0_height_mask);
+
+ if (hdmi_signal && (io_read(sd, 0x60) & 1))
+ vic = infoframe_read(sd, 0x04);
+
+ if (vic && v4l2_find_dv_timings_cea861_vic(timings, vic) &&
+ bt->width == w && bt->height == h)
+ goto found;
+
timings->type = V4L2_DV_BT_656_1120;
- bt->width = hdmi_read16(sd, 0x07, info->linewidth_mask);
- bt->height = hdmi_read16(sd, 0x09, info->field0_height_mask);
+ bt->width = w;
+ bt->height = h;
bt->pixelclock = info->read_hdmi_pixelclock(sd);
bt->hfrontporch = hdmi_read16(sd, 0x20, info->hfrontporch_mask);
bt->hsync = hdmi_read16(sd, 0x22, info->hsync_mask);
@@ -3074,13 +3088,13 @@ static int adv76xx_parse_dt(struct adv76xx_state *state)
return ret;
}
- if (!of_property_read_u32(endpoint, "default-input", &v))
+ of_node_put(endpoint);
+
+ if (!of_property_read_u32(np, "default-input", &v))
state->pdata.default_input = v;
else
state->pdata.default_input = -1;
- of_node_put(endpoint);
-
flags = bus_cfg.bus.parallel.flags;
if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index 142ae28803bb..0dcf450052ac 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -873,10 +873,7 @@ void cx25840_std_setup(struct i2c_client *client)
"Chroma sub-carrier freq = %d.%06d MHz\n",
fsc / 1000000, fsc % 1000000);
- v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, "
- "vblank %i, vactive %i, vblank656 %i, src_dec %i, "
- "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, "
- "sc 0x%06x\n",
+ v4l_dbg(1, cx25840_debug, client, "hblank %i, hactive %i, vblank %i, vactive %i, vblank656 %i, src_dec %i, burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x, sc 0x%06x\n",
hblank, hactive, vblank, vactive, vblank656,
src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
}
@@ -5169,11 +5166,9 @@ static int cx25840_probe(struct i2c_client *client,
id = CX2310X_AV;
} else if ((device_id & 0xff) == (device_id >> 8)) {
v4l_err(client,
- "likely a confused/unresponsive cx2388[578] A/V decoder"
- " found @ 0x%x (%s)\n",
+ "likely a confused/unresponsive cx2388[578] A/V decoder found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- v4l_err(client, "A method to reset it from the cx25840 driver"
- " software is not known at this time\n");
+ v4l_err(client, "A method to reset it from the cx25840 driver software is not known at this time\n");
return -ENODEV;
} else {
v4l_dbg(1, cx25840_debug, client, "cx25840 not found\n");
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 4b782012cadc..15fbd9607cee 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -1113,8 +1113,8 @@ int cx25840_ir_log_status(struct v4l2_subdev *sd)
j = 0;
break;
}
- v4l2_info(sd, "\tNext carrier edge window: 16 clocks "
- "-%1d/+%1d, %u to %u Hz\n", i, j,
+ v4l2_info(sd, "\tNext carrier edge window: 16 clocks -%1d/+%1d, %u to %u Hz\n",
+ i, j,
clock_divider_to_freq(rxclk, 16 + j),
clock_divider_to_freq(rxclk, 16 - i));
}
@@ -1124,8 +1124,7 @@ int cx25840_ir_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "\tLow pass filter: %s\n",
filtr ? "enabled" : "disabled");
if (filtr)
- v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, "
- "%u ns\n",
+ v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, %u ns\n",
lpf_count_to_us(filtr),
lpf_count_to_ns(filtr));
v4l2_info(sd, "\tPulse width timer timed-out: %s\n",
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
index e3348db56c46..771db56332b2 100644
--- a/drivers/media/i2c/smiapp-pll.c
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -479,7 +479,8 @@ int smiapp_pll_calculate(struct device *dev,
return 0;
}
- dev_info(dev, "unable to compute pre_pll divisor\n");
+ dev_dbg(dev, "unable to compute pre_pll divisor\n");
+
return rval;
}
EXPORT_SYMBOL_GPL(smiapp_pll_calculate);
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 44f8c7e10a35..59872b31f832 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -26,6 +26,7 @@
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/smiapp.h>
@@ -68,10 +69,9 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc;
unsigned int i;
- int rval;
+ int pixel_count = 0;
int line_count = 0;
- int embedded_start = -1, embedded_end = -1;
- int image_start = 0;
+ int rval;
rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
&fmt_model_type);
@@ -101,12 +101,11 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
u32 pixels;
char *which;
char *what;
+ u32 reg;
if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i),
- &desc);
+ reg = SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i);
+ rval = smiapp_read(sensor, reg, &desc);
if (rval)
return rval;
@@ -117,10 +116,8 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK;
} else if (fmt_model_type
== SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) {
- rval = smiapp_read(
- sensor,
- SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i),
- &desc);
+ reg = SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i);
+ rval = smiapp_read(sensor, reg, &desc);
if (rval)
return rval;
@@ -159,40 +156,47 @@ static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
break;
default:
what = "invalid";
- dev_dbg(&client->dev, "pixelcode %d\n", pixelcode);
break;
}
- dev_dbg(&client->dev, "%s pixels: %d %s\n",
- what, pixels, which);
-
- if (i < ncol_desc)
+ dev_dbg(&client->dev,
+ "0x%8.8x %s pixels: %d %s (pixelcode %u)\n", reg,
+ what, pixels, which, pixelcode);
+
+ if (i < ncol_desc) {
+ if (pixelcode ==
+ SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE)
+ sensor->visible_pixel_start = pixel_count;
+ pixel_count += pixels;
continue;
+ }
/* Handle row descriptors */
- if (pixelcode
- == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) {
- embedded_start = line_count;
- } else {
- if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE
- || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2)
- image_start = line_count;
- if (embedded_start != -1 && embedded_end == -1)
- embedded_end = line_count;
+ switch (pixelcode) {
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED:
+ if (sensor->embedded_end)
+ break;
+ sensor->embedded_start = line_count;
+ sensor->embedded_end = line_count + pixels;
+ break;
+ case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE:
+ sensor->image_start = line_count;
+ break;
}
line_count += pixels;
}
- if (embedded_start == -1 || embedded_end == -1) {
- embedded_start = 0;
- embedded_end = 0;
+ if (sensor->embedded_end > sensor->image_start) {
+ dev_dbg(&client->dev,
+ "adjusting image start line to %u (was %u)\n",
+ sensor->embedded_end, sensor->image_start);
+ sensor->image_start = sensor->embedded_end;
}
- sensor->image_start = image_start;
-
dev_dbg(&client->dev, "embedded data from lines %d to %d\n",
- embedded_start, embedded_end);
- dev_dbg(&client->dev, "image data starts at line %d\n", image_start);
+ sensor->embedded_start, sensor->embedded_end);
+ dev_dbg(&client->dev, "image data starts at line %d\n",
+ sensor->image_start);
return 0;
}
@@ -443,8 +447,7 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
orient ^= sensor->hvflip_inv_mask;
- rval = smiapp_write(sensor,
- SMIAPP_REG_U8_IMAGE_ORIENTATION,
+ rval = smiapp_write(sensor, SMIAPP_REG_U8_IMAGE_ORIENTATION,
orient);
if (rval < 0)
return rval;
@@ -459,10 +462,8 @@ static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
__smiapp_update_exposure_limits(sensor);
if (exposure > sensor->exposure->maximum) {
- sensor->exposure->val =
- sensor->exposure->maximum;
- rval = smiapp_set_ctrl(
- sensor->exposure);
+ sensor->exposure->val = sensor->exposure->maximum;
+ rval = smiapp_set_ctrl(sensor->exposure);
if (rval < 0)
return rval;
}
@@ -621,7 +622,7 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
static int smiapp_init_late_controls(struct smiapp_sensor *sensor)
{
unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
- sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE];
+ sensor->csi_format->compressed - sensor->compressed_min_bpp];
unsigned int max, i;
for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
@@ -754,6 +755,7 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct smiapp_pll *pll = &sensor->pll;
+ u8 compressed_max_bpp = 0;
unsigned int type, n;
unsigned int i, pixel_order;
int rval;
@@ -826,16 +828,27 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
pll->scale_m = sensor->scale_m;
for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ sensor->compressed_min_bpp =
+ min(smiapp_csi_data_formats[i].compressed,
+ sensor->compressed_min_bpp);
+ compressed_max_bpp =
+ max(smiapp_csi_data_formats[i].compressed,
+ compressed_max_bpp);
+ }
+
+ sensor->valid_link_freqs = devm_kcalloc(
+ &client->dev,
+ compressed_max_bpp - sensor->compressed_min_bpp + 1,
+ sizeof(*sensor->valid_link_freqs), GFP_KERNEL);
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
const struct smiapp_csi_data_format *f =
&smiapp_csi_data_formats[i];
unsigned long *valid_link_freqs =
&sensor->valid_link_freqs[
- f->compressed - SMIAPP_COMPRESSED_BASE];
+ f->compressed - sensor->compressed_min_bpp];
unsigned int j;
- BUG_ON(f->compressed < SMIAPP_COMPRESSED_BASE);
- BUG_ON(f->compressed > SMIAPP_COMPRESSED_MAX);
-
if (!(sensor->default_mbus_frame_fmts & 1 << i))
continue;
@@ -914,12 +927,6 @@ static int smiapp_update_mode(struct smiapp_sensor *sensor)
unsigned int binning_mode;
int rval;
- dev_dbg(&client->dev, "frame size: %dx%d\n",
- sensor->src->crop[SMIAPP_PAD_SRC].width,
- sensor->src->crop[SMIAPP_PAD_SRC].height);
- dev_dbg(&client->dev, "csi format width: %d\n",
- sensor->csi_format->width);
-
/* Binning has to be set up here; it affects limits */
if (sensor->binning_horizontal == 1 &&
sensor->binning_vertical == 1) {
@@ -1196,9 +1203,17 @@ out:
* Power management
*/
-static int smiapp_power_on(struct smiapp_sensor *sensor)
+static int smiapp_power_on(struct device *dev)
{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ /*
+ * The sub-device related to the I2C device is always the
+ * source one, i.e. ssds[0].
+ */
+ struct smiapp_sensor *sensor =
+ container_of(ssd, struct smiapp_sensor, ssds[0]);
unsigned int sleep;
int rval;
@@ -1307,8 +1322,7 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
if (!sensor->pixel_array)
return 0;
- rval = v4l2_ctrl_handler_setup(
- &sensor->pixel_array->ctrl_handler);
+ rval = v4l2_ctrl_handler_setup(&sensor->pixel_array->ctrl_handler);
if (rval)
goto out_cci_addr_fail;
@@ -1325,16 +1339,24 @@ static int smiapp_power_on(struct smiapp_sensor *sensor)
return 0;
out_cci_addr_fail:
+
gpiod_set_value(sensor->xshutdown, 0);
clk_disable_unprepare(sensor->ext_clk);
out_xclk_fail:
regulator_disable(sensor->vana);
+
return rval;
}
-static void smiapp_power_off(struct smiapp_sensor *sensor)
+static int smiapp_power_off(struct device *dev)
{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *subdev = i2c_get_clientdata(client);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct smiapp_sensor *sensor =
+ container_of(ssd, struct smiapp_sensor, ssds[0]);
+
/*
* Currently power/clock to lens are enable/disabled separately
* but they are essentially the same signals. So if the sensor is
@@ -1352,31 +1374,31 @@ static void smiapp_power_off(struct smiapp_sensor *sensor)
usleep_range(5000, 5000);
regulator_disable(sensor->vana);
sensor->streaming = false;
+
+ return 0;
}
static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int ret = 0;
+ int rval;
- mutex_lock(&sensor->power_mutex);
+ if (!on) {
+ pm_runtime_mark_last_busy(subdev->dev);
+ pm_runtime_put_autosuspend(subdev->dev);
- if (on && !sensor->power_count) {
- /* Power on and perform initialisation. */
- ret = smiapp_power_on(sensor);
- if (ret < 0)
- goto out;
- } else if (!on && sensor->power_count == 1) {
- smiapp_power_off(sensor);
+ return 0;
}
- /* Update the power count. */
- sensor->power_count += on ? 1 : -1;
- WARN_ON(sensor->power_count < 0);
+ rval = pm_runtime_get_sync(subdev->dev);
+ if (rval >= 0)
+ return 0;
-out:
- mutex_unlock(&sensor->power_mutex);
- return ret;
+ if (rval != -EBUSY && rval != -EAGAIN)
+ pm_runtime_set_active(subdev->dev);
+
+ pm_runtime_put(subdev->dev);
+
+ return rval;
}
/* -----------------------------------------------------------------------------
@@ -1614,7 +1636,8 @@ static int __smiapp_get_format(struct v4l2_subdev *subdev,
struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
- fmt->format = *v4l2_subdev_get_try_format(subdev, cfg, fmt->pad);
+ fmt->format = *v4l2_subdev_get_try_format(subdev, cfg,
+ fmt->pad);
} else {
struct v4l2_rect *r;
@@ -1714,7 +1737,6 @@ static void smiapp_propagate(struct v4l2_subdev *subdev,
static const struct smiapp_csi_data_format
*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
{
- const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
unsigned int i;
for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
@@ -1723,7 +1745,7 @@ static const struct smiapp_csi_data_format
return &smiapp_csi_data_formats[i];
}
- return csi_format;
+ return sensor->csi_format;
}
static int smiapp_set_format_source(struct v4l2_subdev *subdev,
@@ -1769,7 +1791,7 @@ static int smiapp_set_format_source(struct v4l2_subdev *subdev,
valid_link_freqs =
&sensor->valid_link_freqs[sensor->csi_format->compressed
- - SMIAPP_COMPRESSED_BASE];
+ - sensor->compressed_min_bpp];
__v4l2_ctrl_modify_range(
sensor->link_freq, 0,
@@ -2057,8 +2079,7 @@ static int smiapp_set_compose(struct v4l2_subdev *subdev,
smiapp_set_compose_scaler(subdev, cfg, sel, crops, comp);
*comp = sel->r;
- smiapp_propagate(subdev, cfg, sel->which,
- V4L2_SEL_TGT_COMPOSE);
+ smiapp_propagate(subdev, cfg, sel->which, V4L2_SEL_TGT_COMPOSE);
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
return smiapp_update_mode(sensor);
@@ -2135,9 +2156,8 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
->height;
src_size = &_r;
} else {
- src_size =
- v4l2_subdev_get_try_compose(
- subdev, cfg, ssd->sink_pad);
+ src_size = v4l2_subdev_get_try_compose(
+ subdev, cfg, ssd->sink_pad);
}
}
@@ -2161,6 +2181,15 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
return 0;
}
+static void smiapp_get_native_size(struct smiapp_subdev *ssd,
+ struct v4l2_rect *r)
+{
+ r->top = 0;
+ r->left = 0;
+ r->width = ssd->sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
+ r->height = ssd->sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
+}
+
static int __smiapp_get_selection(struct v4l2_subdev *subdev,
struct v4l2_subdev_pad_config *cfg,
struct v4l2_subdev_selection *sel)
@@ -2192,17 +2221,12 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_NATIVE_SIZE:
- if (ssd == sensor->pixel_array) {
- sel->r.left = sel->r.top = 0;
- sel->r.width =
- sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- sel->r.height =
- sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- } else if (sel->pad == ssd->sink_pad) {
+ if (ssd == sensor->pixel_array)
+ smiapp_get_native_size(ssd, &sel->r);
+ else if (sel->pad == ssd->sink_pad)
sel->r = sink_fmt;
- } else {
+ else
sel->r = *comp;
- }
break;
case V4L2_SEL_TGT_CROP:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
@@ -2303,15 +2327,26 @@ smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
return -EBUSY;
if (!sensor->nvm_size) {
+ int rval;
+
/* NVM not read yet - read it now */
sensor->nvm_size = sensor->hwcfg->nvm_size;
- if (smiapp_set_power(subdev, 1) < 0)
+
+ rval = pm_runtime_get_sync(&client->dev);
+ if (rval < 0) {
+ if (rval != -EBUSY && rval != -EAGAIN)
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_put(&client->dev);
return -ENODEV;
+ }
+
if (smiapp_read_nvm(sensor, sensor->nvm)) {
dev_err(&client->dev, "nvm read failed\n");
return -ENODEV;
}
- smiapp_set_power(subdev, 0);
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
}
/*
* NVM is still way below a PAGE_SIZE, so we can safely
@@ -2475,383 +2510,160 @@ static const struct v4l2_subdev_ops smiapp_ops;
static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
static const struct media_entity_operations smiapp_entity_ops;
-static int smiapp_register_subdevs(struct smiapp_sensor *sensor)
+static int smiapp_register_subdev(struct smiapp_sensor *sensor,
+ struct smiapp_subdev *ssd,
+ struct smiapp_subdev *sink_ssd,
+ u16 source_pad, u16 sink_pad, u32 link_flags)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct smiapp_subdev *ssds[] = {
- sensor->scaler,
- sensor->binner,
- sensor->pixel_array,
- };
- unsigned int i;
int rval;
- for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) {
- struct smiapp_subdev *this = ssds[i + 1];
- struct smiapp_subdev *last = ssds[i];
-
- if (!last)
- continue;
+ if (!sink_ssd)
+ return 0;
- rval = media_entity_pads_init(&this->sd.entity,
- this->npads, this->pads);
- if (rval) {
- dev_err(&client->dev,
- "media_entity_pads_init failed\n");
- return rval;
- }
+ rval = media_entity_pads_init(&ssd->sd.entity,
+ ssd->npads, ssd->pads);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_pads_init failed\n");
+ return rval;
+ }
- rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
- &this->sd);
- if (rval) {
- dev_err(&client->dev,
- "v4l2_device_register_subdev failed\n");
- return rval;
- }
+ rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+ &ssd->sd);
+ if (rval) {
+ dev_err(&client->dev,
+ "v4l2_device_register_subdev failed\n");
+ return rval;
+ }
- rval = media_create_pad_link(&this->sd.entity,
- this->source_pad,
- &last->sd.entity,
- last->sink_pad,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (rval) {
- dev_err(&client->dev,
- "media_create_pad_link failed\n");
- return rval;
- }
+ rval = media_create_pad_link(&ssd->sd.entity, source_pad,
+ &sink_ssd->sd.entity, sink_pad,
+ link_flags);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_create_pad_link failed\n");
+ v4l2_device_unregister_subdev(&ssd->sd);
+ return rval;
}
return 0;
}
-static void smiapp_cleanup(struct smiapp_sensor *sensor)
+static void smiapp_unregistered(struct v4l2_subdev *subdev)
{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
-
- device_remove_file(&client->dev, &dev_attr_nvm);
- device_remove_file(&client->dev, &dev_attr_ident);
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ unsigned int i;
- smiapp_free_controls(sensor);
+ for (i = 1; i < sensor->ssds_used; i++)
+ v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
}
-static int smiapp_init(struct smiapp_sensor *sensor)
+static int smiapp_registered(struct v4l2_subdev *subdev)
{
- struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- struct smiapp_pll *pll = &sensor->pll;
- struct smiapp_subdev *last = NULL;
- unsigned int i;
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
int rval;
- sensor->vana = devm_regulator_get(&client->dev, "vana");
- if (IS_ERR(sensor->vana)) {
- dev_err(&client->dev, "could not get regulator for vana\n");
- return PTR_ERR(sensor->vana);
- }
-
- sensor->ext_clk = devm_clk_get(&client->dev, NULL);
- if (IS_ERR(sensor->ext_clk)) {
- dev_err(&client->dev, "could not get clock (%ld)\n",
- PTR_ERR(sensor->ext_clk));
- return -EPROBE_DEFER;
- }
-
- rval = clk_set_rate(sensor->ext_clk,
- sensor->hwcfg->ext_clk);
- if (rval < 0) {
- dev_err(&client->dev,
- "unable to set clock freq to %u\n",
- sensor->hwcfg->ext_clk);
- return rval;
+ if (sensor->scaler) {
+ rval = smiapp_register_subdev(
+ sensor, sensor->binner, sensor->scaler,
+ SMIAPP_PAD_SRC, SMIAPP_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (rval < 0)
+ return rval;
}
- sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
- GPIOD_OUT_LOW);
- if (IS_ERR(sensor->xshutdown))
- return PTR_ERR(sensor->xshutdown);
-
- rval = smiapp_power_on(sensor);
+ rval = smiapp_register_subdev(
+ sensor, sensor->pixel_array, sensor->binner,
+ SMIAPP_PA_PAD_SRC, SMIAPP_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
if (rval)
- return -ENODEV;
-
- rval = smiapp_identify_module(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
- rval = smiapp_get_all_limits(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
- /*
- * Handle Sensor Module orientation on the board.
- *
- * The application of H-FLIP and V-FLIP on the sensor is modified by
- * the sensor orientation on the board.
- *
- * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
- * both H-FLIP and V-FLIP for normal operation which also implies
- * that a set/unset operation for user space HFLIP and VFLIP v4l2
- * controls will need to be internally inverted.
- *
- * Rotation also changes the bayer pattern.
- */
- if (sensor->hwcfg->module_board_orient ==
- SMIAPP_MODULE_BOARD_ORIENT_180)
- sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
- SMIAPP_IMAGE_ORIENTATION_VFLIP;
-
- rval = smiapp_call_quirk(sensor, limits);
- if (rval) {
- dev_err(&client->dev, "limits quirks failed\n");
- goto out_power_off;
- }
-
- if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
- u32 val;
-
- rval = smiapp_read(sensor,
- SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
- if (rval < 0) {
- rval = -ENODEV;
- goto out_power_off;
- }
- sensor->nbinning_subtypes = min_t(u8, val,
- SMIAPP_BINNING_SUBTYPES);
-
- for (i = 0; i < sensor->nbinning_subtypes; i++) {
- rval = smiapp_read(
- sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
- if (rval < 0) {
- rval = -ENODEV;
- goto out_power_off;
- }
- sensor->binning_subtypes[i] =
- *(struct smiapp_binning_subtype *)&val;
+ goto out_err;
- dev_dbg(&client->dev, "binning %xx%x\n",
- sensor->binning_subtypes[i].horizontal,
- sensor->binning_subtypes[i].vertical);
- }
- }
- sensor->binning_horizontal = 1;
- sensor->binning_vertical = 1;
+ return 0;
- if (device_create_file(&client->dev, &dev_attr_ident) != 0) {
- dev_err(&client->dev, "sysfs ident entry creation failed\n");
- rval = -ENOENT;
- goto out_power_off;
- }
- /* SMIA++ NVM initialization - it will be read from the sensor
- * when it is first requested by userspace.
- */
- if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) {
- sensor->nvm = devm_kzalloc(&client->dev,
- sensor->hwcfg->nvm_size, GFP_KERNEL);
- if (sensor->nvm == NULL) {
- dev_err(&client->dev, "nvm buf allocation failed\n");
- rval = -ENOMEM;
- goto out_cleanup;
- }
+out_err:
+ smiapp_unregistered(subdev);
- if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
- dev_err(&client->dev, "sysfs nvm entry failed\n");
- rval = -EBUSY;
- goto out_cleanup;
- }
- }
+ return rval;
+}
- /* We consider this as profile 0 sensor if any of these are zero. */
- if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
- !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
- } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- != SMIAPP_SCALING_CAPABILITY_NONE) {
- if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
- == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
- else
- sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
- sensor->scaler = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
- == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
- sensor->scaler = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- }
- sensor->binner = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
- sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
- sensor->ssds_used++;
+static void smiapp_cleanup(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ device_remove_file(&client->dev, &dev_attr_nvm);
+ device_remove_file(&client->dev, &dev_attr_ident);
- /* prepare PLL configuration input values */
- pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
- pll->csi2.lanes = sensor->hwcfg->lanes;
- pll->ext_clk_freq_hz = sensor->hwcfg->ext_clk;
- pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
- /* Profile 0 sensors have no separate OP clock branch. */
- if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
- pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
-
- for (i = 0; i < SMIAPP_SUBDEVS; i++) {
- struct {
- struct smiapp_subdev *ssd;
- char *name;
- } const __this[] = {
- { sensor->scaler, "scaler", },
- { sensor->binner, "binner", },
- { sensor->pixel_array, "pixel array", },
- }, *_this = &__this[i];
- struct smiapp_subdev *this = _this->ssd;
-
- if (!this)
- continue;
+ smiapp_free_controls(sensor);
+}
- if (this != sensor->src)
- v4l2_subdev_init(&this->sd, &smiapp_ops);
+static void smiapp_create_subdev(struct smiapp_sensor *sensor,
+ struct smiapp_subdev *ssd, const char *name,
+ unsigned short num_pads)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
- this->sensor = sensor;
+ if (!ssd)
+ return;
- if (this == sensor->pixel_array) {
- this->npads = 1;
- } else {
- this->npads = 2;
- this->source_pad = 1;
- }
+ if (ssd != sensor->src)
+ v4l2_subdev_init(&ssd->sd, &smiapp_ops);
- snprintf(this->sd.name,
- sizeof(this->sd.name), "%s %s %d-%4.4x",
- sensor->minfo.name, _this->name,
- i2c_adapter_id(client->adapter), client->addr);
-
- this->sink_fmt.width =
- sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- this->sink_fmt.height =
- sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- this->compose.width = this->sink_fmt.width;
- this->compose.height = this->sink_fmt.height;
- this->crop[this->source_pad] = this->compose;
- this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
- if (this != sensor->pixel_array) {
- this->crop[this->sink_pad] = this->compose;
- this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
- }
+ ssd->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+ ssd->sensor = sensor;
- this->sd.entity.ops = &smiapp_entity_ops;
+ ssd->npads = num_pads;
+ ssd->source_pad = num_pads - 1;
- if (last == NULL) {
- last = this;
- continue;
- }
+ snprintf(ssd->sd.name,
+ sizeof(ssd->sd.name), "%s %s %d-%4.4x", sensor->minfo.name,
+ name, i2c_adapter_id(client->adapter), client->addr);
- this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- this->sd.internal_ops = &smiapp_internal_ops;
- this->sd.owner = THIS_MODULE;
- v4l2_set_subdevdata(&this->sd, client);
+ smiapp_get_native_size(ssd, &ssd->sink_fmt);
- last = this;
+ ssd->compose.width = ssd->sink_fmt.width;
+ ssd->compose.height = ssd->sink_fmt.height;
+ ssd->crop[ssd->source_pad] = ssd->compose;
+ ssd->pads[ssd->source_pad].flags = MEDIA_PAD_FL_SOURCE;
+ if (ssd != sensor->pixel_array) {
+ ssd->crop[ssd->sink_pad] = ssd->compose;
+ ssd->pads[ssd->sink_pad].flags = MEDIA_PAD_FL_SINK;
}
- dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+ ssd->sd.entity.ops = &smiapp_entity_ops;
- sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
-
- /* final steps */
- smiapp_read_frame_fmt(sensor);
- rval = smiapp_init_controls(sensor);
- if (rval < 0)
- goto out_cleanup;
-
- rval = smiapp_call_quirk(sensor, init);
- if (rval)
- goto out_cleanup;
+ if (ssd == sensor->src)
+ return;
- rval = smiapp_get_mbus_formats(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_cleanup;
- }
-
- rval = smiapp_init_late_controls(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_cleanup;
- }
-
- mutex_lock(&sensor->mutex);
- rval = smiapp_update_mode(sensor);
- mutex_unlock(&sensor->mutex);
- if (rval) {
- dev_err(&client->dev, "update mode failed\n");
- goto out_cleanup;
- }
-
- sensor->streaming = false;
- sensor->dev_init_done = true;
-
- smiapp_power_off(sensor);
-
- return 0;
-
-out_cleanup:
- smiapp_cleanup(sensor);
-
-out_power_off:
- smiapp_power_off(sensor);
- return rval;
-}
-
-static int smiapp_registered(struct v4l2_subdev *subdev)
-{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
- int rval;
-
- if (!client->dev.of_node) {
- rval = smiapp_init(sensor);
- if (rval)
- return rval;
- }
-
- rval = smiapp_register_subdevs(sensor);
- if (rval)
- smiapp_cleanup(sensor);
-
- return rval;
+ ssd->sd.internal_ops = &smiapp_internal_ops;
+ ssd->sd.owner = THIS_MODULE;
+ ssd->sd.dev = &client->dev;
+ v4l2_set_subdevdata(&ssd->sd, client);
}
static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
struct smiapp_sensor *sensor = ssd->sensor;
- u32 mbus_code =
- smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
unsigned int i;
+ int rval;
mutex_lock(&sensor->mutex);
for (i = 0; i < ssd->npads; i++) {
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_get_try_format(sd, fh->pad, i);
- struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(sd, fh->pad, i);
+ struct v4l2_rect *try_crop =
+ v4l2_subdev_get_try_crop(sd, fh->pad, i);
struct v4l2_rect *try_comp;
- try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
- try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
- try_fmt->code = mbus_code;
- try_fmt->field = V4L2_FIELD_NONE;
+ smiapp_get_native_size(ssd, try_crop);
- try_crop->top = 0;
- try_crop->left = 0;
- try_crop->width = try_fmt->width;
- try_crop->height = try_fmt->height;
+ try_fmt->width = try_crop->width;
+ try_fmt->height = try_crop->height;
+ try_fmt->code = sensor->internal_csi_format->code;
+ try_fmt->field = V4L2_FIELD_NONE;
if (ssd != sensor->pixel_array)
continue;
@@ -2862,12 +2674,23 @@ static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
mutex_unlock(&sensor->mutex);
- return smiapp_set_power(sd, 1);
+ rval = pm_runtime_get_sync(sd->dev);
+ if (rval >= 0)
+ return 0;
+
+ if (rval != -EBUSY && rval != -EAGAIN)
+ pm_runtime_set_active(sd->dev);
+ pm_runtime_put(sd->dev);
+
+ return rval;
}
static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- return smiapp_set_power(sd, 0);
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_autosuspend(sd->dev);
+
+ return 0;
}
static const struct v4l2_subdev_video_ops smiapp_video_ops = {
@@ -2904,6 +2727,7 @@ static const struct media_entity_operations smiapp_entity_ops = {
static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
.registered = smiapp_registered,
+ .unregistered = smiapp_unregistered,
.open = smiapp_open,
.close = smiapp_close,
};
@@ -2924,20 +2748,20 @@ static int smiapp_suspend(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- bool streaming;
-
- BUG_ON(mutex_is_locked(&sensor->mutex));
+ bool streaming = sensor->streaming;
+ int rval;
- if (sensor->power_count == 0)
- return 0;
+ rval = pm_runtime_get_sync(dev);
+ if (rval < 0) {
+ if (rval != -EBUSY && rval != -EAGAIN)
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_put(dev);
+ return -EAGAIN;
+ }
if (sensor->streaming)
smiapp_stop_streaming(sensor);
- streaming = sensor->streaming;
-
- smiapp_power_off(sensor);
-
/* save state for resume */
sensor->streaming = streaming;
@@ -2949,14 +2773,9 @@ static int smiapp_resume(struct device *dev)
struct i2c_client *client = to_i2c_client(dev);
struct v4l2_subdev *subdev = i2c_get_clientdata(client);
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- int rval;
-
- if (sensor->power_count == 0)
- return 0;
+ int rval = 0;
- rval = smiapp_power_on(sensor);
- if (rval)
- return rval;
+ pm_runtime_put(dev);
if (sensor->streaming)
rval = smiapp_start_streaming(sensor);
@@ -3051,6 +2870,7 @@ static int smiapp_probe(struct i2c_client *client,
{
struct smiapp_sensor *sensor;
struct smiapp_hwconfig *hwcfg = smiapp_get_hwconfig(&client->dev);
+ unsigned int i;
int rval;
if (hwcfg == NULL)
@@ -3062,35 +2882,240 @@ static int smiapp_probe(struct i2c_client *client,
sensor->hwcfg = hwcfg;
mutex_init(&sensor->mutex);
- mutex_init(&sensor->power_mutex);
sensor->src = &sensor->ssds[sensor->ssds_used];
v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
- sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- sensor->src->sensor = sensor;
- sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
- rval = media_entity_pads_init(&sensor->src->sd.entity, 2,
- sensor->src->pads);
- if (rval < 0)
+ sensor->vana = devm_regulator_get(&client->dev, "vana");
+ if (IS_ERR(sensor->vana)) {
+ dev_err(&client->dev, "could not get regulator for vana\n");
+ return PTR_ERR(sensor->vana);
+ }
+
+ sensor->ext_clk = devm_clk_get(&client->dev, NULL);
+ if (IS_ERR(sensor->ext_clk)) {
+ dev_err(&client->dev, "could not get clock (%ld)\n",
+ PTR_ERR(sensor->ext_clk));
+ return -EPROBE_DEFER;
+ }
+
+ rval = clk_set_rate(sensor->ext_clk, sensor->hwcfg->ext_clk);
+ if (rval < 0) {
+ dev_err(&client->dev,
+ "unable to set clock freq to %u\n",
+ sensor->hwcfg->ext_clk);
return rval;
+ }
- if (client->dev.of_node) {
- rval = smiapp_init(sensor);
- if (rval)
- goto out_media_entity_cleanup;
+ sensor->xshutdown = devm_gpiod_get_optional(&client->dev, "xshutdown",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(sensor->xshutdown))
+ return PTR_ERR(sensor->xshutdown);
+
+ pm_runtime_enable(&client->dev);
+
+ rval = pm_runtime_get_sync(&client->dev);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ rval = smiapp_identify_module(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ rval = smiapp_get_all_limits(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
}
+ rval = smiapp_read_frame_fmt(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+
+ /*
+ * Handle Sensor Module orientation on the board.
+ *
+ * The application of H-FLIP and V-FLIP on the sensor is modified by
+ * the sensor orientation on the board.
+ *
+ * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
+ * both H-FLIP and V-FLIP for normal operation which also implies
+ * that a set/unset operation for user space HFLIP and VFLIP v4l2
+ * controls will need to be internally inverted.
+ *
+ * Rotation also changes the bayer pattern.
+ */
+ if (sensor->hwcfg->module_board_orient ==
+ SMIAPP_MODULE_BOARD_ORIENT_180)
+ sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
+ SMIAPP_IMAGE_ORIENTATION_VFLIP;
+
+ rval = smiapp_call_quirk(sensor, limits);
+ if (rval) {
+ dev_err(&client->dev, "limits quirks failed\n");
+ goto out_power_off;
+ }
+
+ if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
+ u32 val;
+
+ rval = smiapp_read(sensor,
+ SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->nbinning_subtypes = min_t(u8, val,
+ SMIAPP_BINNING_SUBTYPES);
+
+ for (i = 0; i < sensor->nbinning_subtypes; i++) {
+ rval = smiapp_read(
+ sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
+ if (rval < 0) {
+ rval = -ENODEV;
+ goto out_power_off;
+ }
+ sensor->binning_subtypes[i] =
+ *(struct smiapp_binning_subtype *)&val;
+
+ dev_dbg(&client->dev, "binning %xx%x\n",
+ sensor->binning_subtypes[i].horizontal,
+ sensor->binning_subtypes[i].vertical);
+ }
+ }
+ sensor->binning_horizontal = 1;
+ sensor->binning_vertical = 1;
+
+ if (device_create_file(&client->dev, &dev_attr_ident) != 0) {
+ dev_err(&client->dev, "sysfs ident entry creation failed\n");
+ rval = -ENOENT;
+ goto out_power_off;
+ }
+ /* SMIA++ NVM initialization - it will be read from the sensor
+ * when it is first requested by userspace.
+ */
+ if (sensor->minfo.smiapp_version && sensor->hwcfg->nvm_size) {
+ sensor->nvm = devm_kzalloc(&client->dev,
+ sensor->hwcfg->nvm_size, GFP_KERNEL);
+ if (sensor->nvm == NULL) {
+ rval = -ENOMEM;
+ goto out_cleanup;
+ }
+
+ if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
+ dev_err(&client->dev, "sysfs nvm entry failed\n");
+ rval = -EBUSY;
+ goto out_cleanup;
+ }
+ }
+
+ /* We consider this as profile 0 sensor if any of these are zero. */
+ if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
+ !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
+ } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ != SMIAPP_SCALING_CAPABILITY_NONE) {
+ if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
+ == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
+ else
+ sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
+ == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
+ sensor->scaler = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ }
+ sensor->binner = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+ sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
+ sensor->ssds_used++;
+
+ sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+
+ /* prepare PLL configuration input values */
+ sensor->pll.bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
+ sensor->pll.csi2.lanes = sensor->hwcfg->lanes;
+ sensor->pll.ext_clk_freq_hz = sensor->hwcfg->ext_clk;
+ sensor->pll.scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ /* Profile 0 sensors have no separate OP clock branch. */
+ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+ sensor->pll.flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+
+ smiapp_create_subdev(sensor, sensor->scaler, "scaler", 2);
+ smiapp_create_subdev(sensor, sensor->binner, "binner", 2);
+ smiapp_create_subdev(sensor, sensor->pixel_array, "pixel_array", 1);
+
+ dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
+
+ sensor->pixel_array->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ rval = smiapp_init_controls(sensor);
+ if (rval < 0)
+ goto out_cleanup;
+
+ rval = smiapp_call_quirk(sensor, init);
+ if (rval)
+ goto out_cleanup;
+
+ rval = smiapp_get_mbus_formats(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_cleanup;
+ }
+
+ rval = smiapp_init_late_controls(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_cleanup;
+ }
+
+ mutex_lock(&sensor->mutex);
+ rval = smiapp_update_mode(sensor);
+ mutex_unlock(&sensor->mutex);
+ if (rval) {
+ dev_err(&client->dev, "update mode failed\n");
+ goto out_cleanup;
+ }
+
+ sensor->streaming = false;
+ sensor->dev_init_done = true;
+
+ rval = media_entity_pads_init(&sensor->src->sd.entity, 2,
+ sensor->src->pads);
+ if (rval < 0)
+ goto out_media_entity_cleanup;
+
rval = v4l2_async_register_subdev(&sensor->src->sd);
if (rval < 0)
goto out_media_entity_cleanup;
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
return 0;
out_media_entity_cleanup:
media_entity_cleanup(&sensor->src->sd.entity);
+out_cleanup:
+ smiapp_cleanup(sensor);
+
+out_power_off:
+ pm_runtime_put(&client->dev);
+ pm_runtime_disable(&client->dev);
+
return rval;
}
@@ -3102,11 +3127,8 @@ static int smiapp_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(subdev);
- if (sensor->power_count) {
- gpiod_set_value(sensor->xshutdown, 0);
- clk_disable_unprepare(sensor->ext_clk);
- sensor->power_count = 0;
- }
+ pm_runtime_suspend(&client->dev);
+ pm_runtime_disable(&client->dev);
for (i = 0; i < sensor->ssds_used; i++) {
v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
@@ -3130,8 +3152,8 @@ static const struct i2c_device_id smiapp_id_table[] = {
MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
static const struct dev_pm_ops smiapp_pm_ops = {
- .suspend = smiapp_suspend,
- .resume = smiapp_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(smiapp_suspend, smiapp_resume)
+ SET_RUNTIME_PM_OPS(smiapp_power_off, smiapp_power_on, NULL)
};
static struct i2c_driver smiapp_i2c_driver = {
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c
index 1e501c06d18c..d6779e35d36f 100644
--- a/drivers/media/i2c/smiapp/smiapp-regs.c
+++ b/drivers/media/i2c/smiapp/smiapp-regs.c
@@ -268,8 +268,8 @@ int smiapp_write_no_quirk(struct smiapp_sensor *sensor, u32 reg, u32 val)
if (r == 1) {
if (retries)
dev_err(&client->dev,
- "sensor i2c stall encountered. "
- "retries: %d\n", retries);
+ "sensor i2c stall encountered. retries: %d\n",
+ retries);
return 0;
}
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index aae72bc87bf7..f74d695018b9 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -150,11 +150,6 @@ struct smiapp_csi_data_format {
#define SMIAPP_PAD_SRC 1
#define SMIAPP_PADS 2
-#define SMIAPP_COMPRESSED_BASE 8
-#define SMIAPP_COMPRESSED_MAX 16
-#define SMIAPP_NR_OF_COMPRESSED (SMIAPP_COMPRESSED_MAX - \
- SMIAPP_COMPRESSED_BASE + 1)
-
struct smiapp_binning_subtype {
u8 horizontal:4;
u8 vertical:4;
@@ -162,9 +157,9 @@ struct smiapp_binning_subtype {
struct smiapp_subdev {
struct v4l2_subdev sd;
- struct media_pad pads[2];
+ struct media_pad pads[SMIAPP_PADS];
struct v4l2_rect sink_fmt;
- struct v4l2_rect crop[2];
+ struct v4l2_rect crop[SMIAPP_PADS];
struct v4l2_rect compose; /* compose on sink */
unsigned short sink_pad;
unsigned short source_pad;
@@ -181,16 +176,9 @@ struct smiapp_sensor {
* "mutex" is used to serialise access to all fields here
* except v4l2_ctrls at the end of the struct. "mutex" is also
* used to serialise access to file handle specific
- * information. The exception to this rule is the power_mutex
- * below.
+ * information.
*/
struct mutex mutex;
- /*
- * power_mutex is used to serialise power management related
- * activities. Acquiring "mutex" at that time isn't necessary
- * since there are no other users anyway.
- */
- struct mutex power_mutex;
struct smiapp_subdev ssds[SMIAPP_SUBDEVS];
u32 ssds_used;
struct smiapp_subdev *src;
@@ -218,12 +206,14 @@ struct smiapp_sensor {
u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
u8 frame_skip;
- u16 image_start; /* Offset to first line after metadata lines */
-
- int power_count;
+ u16 embedded_start; /* embedded data start line */
+ u16 embedded_end;
+ u16 image_start; /* image data start line */
+ u16 visible_pixel_start; /* start pixel of the visible image */
bool streaming;
bool dev_init_done;
+ u8 compressed_min_bpp;
u8 *nvm; /* nvm memory buffer */
unsigned int nvm_size; /* bytes */
@@ -233,7 +223,7 @@ struct smiapp_sensor {
struct smiapp_pll pll;
/* Is a default format supported for a given BPP? */
- unsigned long valid_link_freqs[SMIAPP_NR_OF_COMPRESSED];
+ unsigned long *valid_link_freqs;
/* Pixel array controls */
struct v4l2_ctrl *analog_gain;
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index 7e68762b3a4b..985a3672b243 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -1064,8 +1064,7 @@ static int ov772x_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&adapter->dev,
- "I2C-Adapter doesn't support "
- "I2C_FUNC_SMBUS_BYTE_DATA\n");
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n");
return -EIO;
}
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index 0da632d7d33a..f11f76cdacad 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -881,8 +881,7 @@ static int ov9740_video_probe(struct i2c_client *client)
goto done;
}
- dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, "
- "Manufacturer 0x%02x, SMIA Version 0x%02x\n",
+ dev_info(&client->dev, "ov9740 Model ID 0x%04x, Revision 0x%02x, Manufacturer 0x%02x, SMIA Version 0x%02x\n",
priv->model, priv->revision, priv->manid, priv->smiaver);
ret = v4l2_ctrl_handler_setup(&priv->hdl);
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index 4002c07f3857..c9c49ed707b8 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -947,8 +947,7 @@ static int tw9910_probe(struct i2c_client *client,
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
dev_err(&client->dev,
- "I2C-Adapter doesn't support "
- "I2C_FUNC_SMBUS_BYTE_DATA\n");
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE_DATA\n");
return -EIO;
}
diff --git a/drivers/media/i2c/tvaudio.c b/drivers/media/i2c/tvaudio.c
index 42d1e26e581c..ce86534450ac 100644
--- a/drivers/media/i2c/tvaudio.c
+++ b/drivers/media/i2c/tvaudio.c
@@ -1894,8 +1894,9 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
printk(KERN_INFO "tvaudio: TV audio decoder + audio/video mux driver\n");
printk(KERN_INFO "tvaudio: known chips: ");
for (desc = chiplist; desc->name != NULL; desc++)
- printk("%s%s", (desc == chiplist) ? "" : ", ", desc->name);
- printk("\n");
+ printk(KERN_CONT "%s%s",
+ (desc == chiplist) ? "" : ", ", desc->name);
+ printk(KERN_CONT "\n");
}
chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index d5c9347f4c6d..0c62899c3667 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -894,7 +894,7 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
if (index != 0)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_YUYV8_2X8;
+ code->code = MEDIA_BUS_FMT_UYVY8_2X8;
return 0;
}
@@ -922,7 +922,7 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
return 0;
}
- format->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
+ format->format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format->format.width = tvp514x_std_list[decoder->current_std].width;
format->format.height = tvp514x_std_list[decoder->current_std].height;
format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
@@ -946,7 +946,7 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
struct tvp514x_decoder *decoder = to_decoder(sd);
if (fmt->format.field != V4L2_FIELD_INTERLACED ||
- fmt->format.code != MEDIA_BUS_FMT_YUYV8_2X8 ||
+ fmt->format.code != MEDIA_BUS_FMT_UYVY8_2X8 ||
fmt->format.colorspace != V4L2_COLORSPACE_SMPTE170M ||
fmt->format.width != tvp514x_std_list[decoder->current_std].width ||
fmt->format.height != tvp514x_std_list[decoder->current_std].height)
OpenPOWER on IntegriCloud