--- zzzz-none-000/linux-3.10.107/drivers/media/i2c/s5c73m3/s5c73m3-core.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/media/i2c/s5c73m3/s5c73m3-core.c 2021-02-04 17:41:59.000000000 +0000 @@ -15,7 +15,7 @@ * GNU General Public License for more details. */ -#include +#include #include #include #include @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include "s5c73m3.h" @@ -46,6 +49,8 @@ module_param(update_fw, int, 0644); #define S5C73M3_EMBEDDED_DATA_MAXLEN SZ_4K +#define S5C73M3_MIPI_DATA_LANES 4 +#define S5C73M3_CLK_NAME "cis_extclk" static const char * const s5c73m3_supply_names[S5C73M3_MAX_SUPPLIES] = { "vdd-int", /* Digital Core supply (1.2V), CAM_ISP_CORE_1.2V */ @@ -162,7 +167,7 @@ */ ret = i2c_transfer(client->adapter, msg, 2); if (ret == 2) { - *data = be16_to_cpup((u16 *)rbuf); + *data = be16_to_cpup((__be16 *)rbuf); v4l2_dbg(4, s5c73m3_dbg, client, "%s: addr: 0x%04x, data: 0x%04x\n", __func__, addr, *data); @@ -819,10 +824,11 @@ } static void s5c73m3_oif_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { + struct v4l2_subdev *sd = &state->sensor_sd; u32 code; switch (fmt->pad) { @@ -845,7 +851,7 @@ *fs = state->oif_pix_size[RES_ISP]; else *fs = s5c73m3_find_frame_size( - v4l2_subdev_get_try_format(fh, + v4l2_subdev_get_try_format(sd, cfg, OIF_ISP_PAD), RES_ISP); break; @@ -855,7 +861,7 @@ } static void s5c73m3_try_format(struct s5c73m3 *state, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt, const struct s5c73m3_frame_size **fs) { @@ -947,7 +953,7 @@ } static int s5c73m3_oif_enum_frame_interval(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_interval_enum *fie) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -985,7 +991,7 @@ } static int s5c73m3_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = sensor_sd_to_s5c73m3(sd); @@ -993,7 +999,7 @@ u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1019,7 +1025,7 @@ } static int s5c73m3_oif_get_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); @@ -1027,7 +1033,7 @@ u32 code; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); + fmt->format = *v4l2_subdev_get_try_format(sd, cfg, fmt->pad); return 0; } @@ -1057,7 +1063,7 @@ } static int s5c73m3_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1067,10 +1073,10 @@ mutex_lock(&state->lock); - s5c73m3_try_format(state, fh, fmt, &frame_size); + s5c73m3_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; } else { switch (fmt->pad) { @@ -1096,7 +1102,7 @@ } static int s5c73m3_oif_set_fmt(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_format *fmt) { const struct s5c73m3_frame_size *frame_size = NULL; @@ -1106,11 +1112,16 @@ mutex_lock(&state->lock); - s5c73m3_oif_try_format(state, fh, fmt, &frame_size); + s5c73m3_oif_try_format(state, cfg, fmt, &frame_size); if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { - mf = v4l2_subdev_get_try_format(fh, fmt->pad); + mf = v4l2_subdev_get_try_format(sd, cfg, fmt->pad); *mf = fmt->format; + if (fmt->pad == OIF_ISP_PAD) { + mf = v4l2_subdev_get_try_format(sd, cfg, OIF_SOURCE_PAD); + mf->width = fmt->format.width; + mf->height = fmt->format.height; + } } else { switch (fmt->pad) { case OIF_ISP_PAD: @@ -1179,7 +1190,7 @@ } static int s5c73m3_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { static const int codes[] = { @@ -1195,7 +1206,7 @@ } static int s5c73m3_oif_enum_mbus_code(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_mbus_code_enum *code) { int ret; @@ -1210,7 +1221,7 @@ } static int s5c73m3_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { int idx; @@ -1237,9 +1248,10 @@ } static int s5c73m3_oif_enum_frame_size(struct v4l2_subdev *sd, - struct v4l2_subdev_fh *fh, + struct v4l2_subdev_pad_config *cfg, struct v4l2_subdev_frame_size_enum *fse) { + struct s5c73m3 *state = oif_sd_to_s5c73m3(sd); int idx; if (fse->pad == OIF_SOURCE_PAD) { @@ -1249,11 +1261,25 @@ switch (fse->code) { case S5C73M3_JPEG_FMT: case S5C73M3_ISP_FMT: { - struct v4l2_mbus_framefmt *mf = - v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + unsigned w, h; + + if (fse->which == V4L2_SUBDEV_FORMAT_TRY) { + struct v4l2_mbus_framefmt *mf; - fse->max_width = fse->min_width = mf->width; - fse->max_height = fse->min_height = mf->height; + mf = v4l2_subdev_get_try_format(sd, cfg, + OIF_ISP_PAD); + + w = mf->width; + h = mf->height; + } else { + const struct s5c73m3_frame_size *fs; + + fs = state->oif_pix_size[RES_ISP]; + w = fs->width; + h = fs->height; + } + fse->max_width = fse->min_width = w; + fse->max_height = fse->min_height = h; return 0; } default: @@ -1296,11 +1322,11 @@ { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, S5C73M3_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, S5C73M3_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, S5C73M3_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); @@ -1311,15 +1337,15 @@ { struct v4l2_mbus_framefmt *mf; - mf = v4l2_subdev_get_try_format(fh, OIF_ISP_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_ISP_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_JPEG_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_JPEG_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_jpeg_resolutions[1], S5C73M3_JPEG_FMT); - mf = v4l2_subdev_get_try_format(fh, OIF_SOURCE_PAD); + mf = v4l2_subdev_get_try_format(sd, fh->pad, OIF_SOURCE_PAD); s5c73m3_fill_mbus_fmt(mf, &s5c73m3_isp_resolutions[1], S5C73M3_ISP_FMT); return 0; @@ -1350,9 +1376,20 @@ for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) { ret = regulator_enable(state->supplies[i].consumer); if (ret) - goto err; + goto err_reg_dis; } + ret = clk_set_rate(state->clock, state->mclk_frequency); + if (ret < 0) + goto err_reg_dis; + + ret = clk_prepare_enable(state->clock); + if (ret < 0) + goto err_reg_dis; + + v4l2_dbg(1, s5c73m3_dbg, &state->oif_sd, "clock frequency: %ld\n", + clk_get_rate(state->clock)); + s5c73m3_gpio_deassert(state, STBY); usleep_range(100, 200); @@ -1360,7 +1397,8 @@ usleep_range(50, 100); return 0; -err: + +err_reg_dis: for (--i; i >= 0; i--) regulator_disable(state->supplies[i].consumer); return ret; @@ -1375,6 +1413,9 @@ if (s5c73m3_gpio_assert(state, STBY)) usleep_range(100, 200); + + clk_disable_unprepare(state->clock); + state->streaming = 0; state->isp_ready = 0; @@ -1383,11 +1424,17 @@ if (ret) goto err; } + return 0; err: - for (++i; i < S5C73M3_MAX_SUPPLIES; i++) - regulator_enable(state->supplies[i].consumer); + for (++i; i < S5C73M3_MAX_SUPPLIES; i++) { + int r = regulator_enable(state->supplies[i].consumer); + if (r < 0) + v4l2_err(&state->oif_sd, "Failed to reenable %s: %d\n", + state->supplies[i].supply, r); + } + clk_prepare_enable(state->clock); return ret; } @@ -1406,7 +1453,7 @@ state->apply_fiv = 1; state->apply_fmt = 1; } - } else if (!on == state->power) { + } else if (state->power == !on) { ret = s5c73m3_set_af_softlanding(state); if (!ret) ret = __s5c73m3_power_off(state); @@ -1443,17 +1490,6 @@ S5C73M3_JPEG_PAD, &state->oif_sd.entity, OIF_JPEG_PAD, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); - mutex_lock(&state->lock); - ret = __s5c73m3_power_on(state); - if (ret == 0) - s5c73m3_get_fw_version(state); - - __s5c73m3_power_off(state); - mutex_unlock(&state->lock); - - v4l2_dbg(1, s5c73m3_dbg, sd, "%s: Booting %s (%d)\n", - __func__, ret ? "failed" : "succeded", ret); - return ret; } @@ -1511,59 +1547,111 @@ .video = &s5c73m3_oif_video_ops, }; -static int s5c73m3_configure_gpio(int nr, int val, const char *name) +static int s5c73m3_configure_gpios(struct s5c73m3 *state) { - unsigned long flags = val ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW; - int ret; + static const char * const gpio_names[] = { + "S5C73M3_STBY", "S5C73M3_RST" + }; + struct i2c_client *c = state->i2c_client; + struct s5c73m3_gpio *g = state->gpio; + int ret, i; - if (!gpio_is_valid(nr)) - return 0; - ret = gpio_request_one(nr, flags, name); - if (!ret) - gpio_export(nr, 0); - return ret; + for (i = 0; i < GPIO_NUM; ++i) { + unsigned int flags = GPIOF_DIR_OUT; + if (g[i].level) + flags |= GPIOF_INIT_HIGH; + ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags, + gpio_names[i]); + if (ret) { + v4l2_err(c, "failed to request gpio %s\n", + gpio_names[i]); + return ret; + } + } + return 0; } -static int s5c73m3_free_gpios(struct s5c73m3 *state) +static int s5c73m3_parse_gpios(struct s5c73m3 *state) { - int i; + static const char * const prop_names[] = { + "standby-gpios", "xshutdown-gpios", + }; + struct device *dev = &state->i2c_client->dev; + struct device_node *node = dev->of_node; + int ret, i; - for (i = 0; i < ARRAY_SIZE(state->gpio); i++) { - if (!gpio_is_valid(state->gpio[i].gpio)) - continue; - gpio_free(state->gpio[i].gpio); - state->gpio[i].gpio = -EINVAL; + for (i = 0; i < GPIO_NUM; ++i) { + enum of_gpio_flags of_flags; + + ret = of_get_named_gpio_flags(node, prop_names[i], + 0, &of_flags); + if (ret < 0) { + dev_err(dev, "failed to parse %s DT property\n", + prop_names[i]); + return -EINVAL; + } + state->gpio[i].gpio = ret; + state->gpio[i].level = !(of_flags & OF_GPIO_ACTIVE_LOW); } return 0; } -static int s5c73m3_configure_gpios(struct s5c73m3 *state, - const struct s5c73m3_platform_data *pdata) +static int s5c73m3_get_platform_data(struct s5c73m3 *state) { - const struct s5c73m3_gpio *gpio = &pdata->gpio_stby; + struct device *dev = &state->i2c_client->dev; + const struct s5c73m3_platform_data *pdata = dev->platform_data; + struct device_node *node = dev->of_node; + struct device_node *node_ep; + struct v4l2_of_endpoint ep; int ret; - state->gpio[STBY].gpio = -EINVAL; - state->gpio[RST].gpio = -EINVAL; + if (!node) { + if (!pdata) { + dev_err(dev, "Platform data not specified\n"); + return -EINVAL; + } + + state->mclk_frequency = pdata->mclk_frequency; + state->gpio[STBY] = pdata->gpio_stby; + state->gpio[RST] = pdata->gpio_reset; + return 0; + } - ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_STBY"); - if (ret) { - s5c73m3_free_gpios(state); - return ret; + state->clock = devm_clk_get(dev, S5C73M3_CLK_NAME); + if (IS_ERR(state->clock)) + return PTR_ERR(state->clock); + + if (of_property_read_u32(node, "clock-frequency", + &state->mclk_frequency)) { + state->mclk_frequency = S5C73M3_DEFAULT_MCLK_FREQ; + dev_info(dev, "using default %u Hz clock frequency\n", + state->mclk_frequency); } - state->gpio[STBY] = *gpio; - if (gpio_is_valid(gpio->gpio)) - gpio_set_value(gpio->gpio, 0); - gpio = &pdata->gpio_reset; - ret = s5c73m3_configure_gpio(gpio->gpio, gpio->level, "S5C73M3_RST"); - if (ret) { - s5c73m3_free_gpios(state); - return ret; + ret = s5c73m3_parse_gpios(state); + if (ret < 0) + return -EINVAL; + + node_ep = of_graph_get_next_endpoint(node, NULL); + if (!node_ep) { + dev_warn(dev, "no endpoint defined for node: %s\n", + node->full_name); + return 0; } - state->gpio[RST] = *gpio; - if (gpio_is_valid(gpio->gpio)) - gpio_set_value(gpio->gpio, 0); + + v4l2_of_parse_endpoint(node_ep, &ep); + of_node_put(node_ep); + + if (ep.bus_type != V4L2_MBUS_CSI2) { + dev_err(dev, "unsupported bus type\n"); + return -EINVAL; + } + /* + * Number of MIPI CSI-2 data lanes is currently not configurable, + * always a default value of 4 lanes is used. + */ + if (ep.bus.mipi_csi2.num_data_lanes != S5C73M3_MIPI_DATA_LANES) + dev_info(dev, "falling back to 4 MIPI CSI-2 data lanes\n"); return 0; } @@ -1572,27 +1660,26 @@ const struct i2c_device_id *id) { struct device *dev = &client->dev; - const struct s5c73m3_platform_data *pdata = client->dev.platform_data; struct v4l2_subdev *sd; struct v4l2_subdev *oif_sd; struct s5c73m3 *state; int ret, i; - if (pdata == NULL) { - dev_err(&client->dev, "Platform data not specified\n"); - return -EINVAL; - } - state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL); if (!state) return -ENOMEM; + state->i2c_client = client; + ret = s5c73m3_get_platform_data(state); + if (ret < 0) + return ret; + mutex_init(&state->lock); sd = &state->sensor_sd; oif_sd = &state->oif_sd; v4l2_subdev_init(sd, &s5c73m3_subdev_ops); - sd->owner = client->driver->driver.owner; + sd->owner = client->dev.driver->owner; v4l2_set_subdevdata(sd, state); strlcpy(sd->name, "S5C73M3", sizeof(sd->name)); @@ -1624,12 +1711,9 @@ if (ret < 0) return ret; - state->mclk_frequency = pdata->mclk_frequency; - state->bus_type = pdata->bus_type; - - ret = s5c73m3_configure_gpios(state, pdata); + ret = s5c73m3_configure_gpios(state); if (ret) - goto out_err1; + goto out_err; for (i = 0; i < S5C73M3_MAX_SUPPLIES; i++) state->supplies[i].supply = s5c73m3_supply_names[i]; @@ -1638,12 +1722,12 @@ state->supplies); if (ret) { dev_err(dev, "failed to get regulators\n"); - goto out_err2; + goto out_err; } ret = s5c73m3_init_controls(state); if (ret) - goto out_err2; + goto out_err; state->sensor_pix_size[RES_ISP] = &s5c73m3_isp_resolutions[1]; state->sensor_pix_size[RES_JPEG] = &s5c73m3_jpeg_resolutions[1]; @@ -1659,16 +1743,32 @@ ret = s5c73m3_register_spi_driver(state); if (ret < 0) - goto out_err2; + goto out_err; - state->i2c_client = client; + oif_sd->dev = dev; + + ret = __s5c73m3_power_on(state); + if (ret < 0) + goto out_err1; + + ret = s5c73m3_get_fw_version(state); + __s5c73m3_power_off(state); - v4l2_info(sd, "%s: completed succesfully\n", __func__); + if (ret < 0) { + dev_err(dev, "Device detection failed: %d\n", ret); + goto out_err1; + } + + ret = v4l2_async_register_subdev(oif_sd); + if (ret < 0) + goto out_err1; + + v4l2_info(sd, "%s: completed successfully\n", __func__); return 0; -out_err2: - s5c73m3_free_gpios(state); out_err1: + s5c73m3_unregister_spi_driver(state); +out_err: media_entity_cleanup(&sd->entity); return ret; } @@ -1679,7 +1779,7 @@ struct s5c73m3 *state = oif_sd_to_s5c73m3(oif_sd); struct v4l2_subdev *sensor_sd = &state->sensor_sd; - v4l2_device_unregister_subdev(oif_sd); + v4l2_async_unregister_subdev(oif_sd); v4l2_ctrl_handler_free(oif_sd->ctrl_handler); media_entity_cleanup(&oif_sd->entity); @@ -1688,7 +1788,6 @@ media_entity_cleanup(&sensor_sd->entity); s5c73m3_unregister_spi_driver(state); - s5c73m3_free_gpios(state); return 0; } @@ -1699,8 +1798,17 @@ }; MODULE_DEVICE_TABLE(i2c, s5c73m3_id); +#ifdef CONFIG_OF +static const struct of_device_id s5c73m3_of_match[] = { + { .compatible = "samsung,s5c73m3" }, + { } +}; +MODULE_DEVICE_TABLE(of, s5c73m3_of_match); +#endif + static struct i2c_driver s5c73m3_i2c_driver = { .driver = { + .of_match_table = of_match_ptr(s5c73m3_of_match), .name = DRIVER_NAME, }, .probe = s5c73m3_probe,