diff options
Diffstat (limited to 'drivers/media/i2c')
-rw-r--r-- | drivers/media/i2c/Kconfig | 6 | ||||
-rw-r--r-- | drivers/media/i2c/ad5820.c | 5 | ||||
-rw-r--r-- | drivers/media/i2c/adv7604.c | 24 | ||||
-rw-r--r-- | drivers/media/i2c/cx25840/cx25840-core.c | 11 | ||||
-rw-r--r-- | drivers/media/i2c/cx25840/cx25840-ir.c | 7 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp-pll.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-core.c | 916 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-regs.c | 4 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp.h | 28 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/ov772x.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/ov9740.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/soc_camera/tw9910.c | 3 | ||||
-rw-r--r-- | drivers/media/i2c/tvaudio.c | 5 | ||||
-rw-r--r-- | drivers/media/i2c/tvp514x.c | 6 |
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) |