Lines Matching +full:fw +full:- +full:gpios
1 // SPDX-License-Identifier: GPL-2.0-or-later
25 #include <media/media-entity.h>
27 #include <media/v4l2-ctrls.h>
28 #include <media/v4l2-device.h>
29 #include <media/v4l2-mediabus.h>
30 #include <media/v4l2-subdev.h>
106 * H/W register Interface (0xd0000000 - 0xd0000fff)
156 /* By default value, output from sensor will be YUV422 0-255 */
208 msg[0].addr = client->addr; in s5k4ecgx_i2c_read()
213 msg[1].addr = client->addr; in s5k4ecgx_i2c_read()
218 ret = i2c_transfer(client->adapter, msg, 2); in s5k4ecgx_i2c_read()
274 v4l2_err(sd, "FW version check failed!\n"); in s5k4ecgx_read_fw_ver()
275 return -ENODEV; in s5k4ecgx_read_fw_ver()
282 v4l2_info(sd, "chip found FW ver: 0x%x, HW rev: 0x%x\n", in s5k4ecgx_read_fw_ver()
318 * < record 0 >, ..., < record N - 1 >, < CRC32-CCITT (4-bytes) >,
319 * where "record" is a 4-byte register address followed by 2-byte
322 * git://git.linaro.org/people/sangwook/fimc-v4l2-app.git
327 const struct firmware *fw; in s5k4ecgx_load_firmware() local
333 err = request_firmware(&fw, S5K4ECGX_FIRMWARE, sd->v4l2_dev->dev); in s5k4ecgx_load_firmware()
338 regs_num = get_unaligned_le32(fw->data); in s5k4ecgx_load_firmware()
340 v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n", in s5k4ecgx_load_firmware()
341 S5K4ECGX_FIRMWARE, fw->size, regs_num); in s5k4ecgx_load_firmware()
344 if (fw->size != regs_num * FW_RECORD_SIZE + FW_CRC_SIZE) { in s5k4ecgx_load_firmware()
345 err = -EINVAL; in s5k4ecgx_load_firmware()
348 crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE); in s5k4ecgx_load_firmware()
349 crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE); in s5k4ecgx_load_firmware()
351 v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file); in s5k4ecgx_load_firmware()
352 err = -EINVAL; in s5k4ecgx_load_firmware()
355 ptr = fw->data + FW_RECORD_SIZE; in s5k4ecgx_load_firmware()
361 if (addr - addr_inc != 2) in s5k4ecgx_load_firmware()
370 release_firmware(fw); in s5k4ecgx_load_firmware()
380 ret = s5k4ecgx_write(c, REG_G_PREV_IN_WIDTH, r->width); in s5k4ecgx_set_input_window()
382 ret = s5k4ecgx_write(c, REG_G_PREV_IN_HEIGHT, r->height); in s5k4ecgx_set_input_window()
384 ret = s5k4ecgx_write(c, REG_G_PREV_IN_XOFFS, r->left); in s5k4ecgx_set_input_window()
386 ret = s5k4ecgx_write(c, REG_G_PREV_IN_YOFFS, r->top); in s5k4ecgx_set_input_window()
388 ret = s5k4ecgx_write(c, REG_G_CAP_IN_WIDTH, r->width); in s5k4ecgx_set_input_window()
390 ret = s5k4ecgx_write(c, REG_G_CAP_IN_HEIGHT, r->height); in s5k4ecgx_set_input_window()
392 ret = s5k4ecgx_write(c, REG_G_CAP_IN_XOFFS, r->left); in s5k4ecgx_set_input_window()
394 ret = s5k4ecgx_write(c, REG_G_CAP_IN_YOFFS, r->top); in s5k4ecgx_set_input_window()
405 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_WIDTH, r->width); in s5k4ecgx_set_zoom_window()
407 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_HEIGHT, r->height); in s5k4ecgx_set_zoom_window()
409 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_XOFFS, r->left); in s5k4ecgx_set_zoom_window()
411 ret = s5k4ecgx_write(c, REG_G_PREVZOOM_IN_YOFFS, r->top); in s5k4ecgx_set_zoom_window()
413 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_WIDTH, r->width); in s5k4ecgx_set_zoom_window()
415 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_HEIGHT, r->height); in s5k4ecgx_set_zoom_window()
417 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_XOFFS, r->left); in s5k4ecgx_set_zoom_window()
419 ret = s5k4ecgx_write(c, REG_G_CAPZOOM_IN_YOFFS, r->top); in s5k4ecgx_set_zoom_window()
426 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); in s5k4ecgx_set_output_framefmt()
430 priv->curr_frmsize->size.width); in s5k4ecgx_set_output_framefmt()
433 priv->curr_frmsize->size.height); in s5k4ecgx_set_output_framefmt()
436 priv->curr_pixfmt->reg_p_format); in s5k4ecgx_set_output_framefmt()
459 if (!gpio_is_valid(priv->gpio[id].gpio)) in s5k4ecgx_gpio_set_value()
461 gpio_set_value(priv->gpio[id].gpio, val); in s5k4ecgx_gpio_set_value()
470 ret = regulator_bulk_enable(S5K4ECGX_NUM_SUPPLIES, priv->supplies); in __s5k4ecgx_power_on()
476 if (s5k4ecgx_gpio_set_value(priv, STBY, priv->gpio[STBY].level)) in __s5k4ecgx_power_on()
479 if (s5k4ecgx_gpio_set_value(priv, RSET, priv->gpio[RSET].level)) in __s5k4ecgx_power_on()
487 if (s5k4ecgx_gpio_set_value(priv, RSET, !priv->gpio[RSET].level)) in __s5k4ecgx_power_off()
490 if (s5k4ecgx_gpio_set_value(priv, STBY, !priv->gpio[STBY].level)) in __s5k4ecgx_power_off()
493 priv->streaming = 0; in __s5k4ecgx_power_off()
495 return regulator_bulk_disable(S5K4ECGX_NUM_SUPPLIES, priv->supplies); in __s5k4ecgx_power_off()
507 while (i--) { in s5k4ecgx_try_frame_size()
508 int err = abs(fsize->size.width - mf->width) in s5k4ecgx_try_frame_size()
509 + abs(fsize->size.height - mf->height); in s5k4ecgx_try_frame_size()
517 mf->width = match->size.width; in s5k4ecgx_try_frame_size()
518 mf->height = match->size.height; in s5k4ecgx_try_frame_size()
524 return -EINVAL; in s5k4ecgx_try_frame_size()
531 if (code->index >= ARRAY_SIZE(s5k4ecgx_formats)) in s5k4ecgx_enum_mbus_code()
532 return -EINVAL; in s5k4ecgx_enum_mbus_code()
533 code->code = s5k4ecgx_formats[code->index].code; in s5k4ecgx_enum_mbus_code()
544 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { in s5k4ecgx_get_fmt()
547 fmt->format = *mf; in s5k4ecgx_get_fmt()
552 mf = &fmt->format; in s5k4ecgx_get_fmt()
554 mutex_lock(&priv->lock); in s5k4ecgx_get_fmt()
555 mf->width = priv->curr_frmsize->size.width; in s5k4ecgx_get_fmt()
556 mf->height = priv->curr_frmsize->size.height; in s5k4ecgx_get_fmt()
557 mf->code = priv->curr_pixfmt->code; in s5k4ecgx_get_fmt()
558 mf->colorspace = priv->curr_pixfmt->colorspace; in s5k4ecgx_get_fmt()
559 mf->field = V4L2_FIELD_NONE; in s5k4ecgx_get_fmt()
560 mutex_unlock(&priv->lock); in s5k4ecgx_get_fmt()
570 while (--i) in s5k4ecgx_try_fmt()
571 if (mf->code == s5k4ecgx_formats[i].code) in s5k4ecgx_try_fmt()
573 mf->code = s5k4ecgx_formats[i].code; in s5k4ecgx_try_fmt()
587 pf = s5k4ecgx_try_fmt(sd, &fmt->format); in s5k4ecgx_set_fmt()
588 s5k4ecgx_try_frame_size(&fmt->format, &fsize); in s5k4ecgx_set_fmt()
589 fmt->format.colorspace = V4L2_COLORSPACE_JPEG; in s5k4ecgx_set_fmt()
590 fmt->format.field = V4L2_FIELD_NONE; in s5k4ecgx_set_fmt()
592 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { in s5k4ecgx_set_fmt()
595 *mf = fmt->format; in s5k4ecgx_set_fmt()
600 mutex_lock(&priv->lock); in s5k4ecgx_set_fmt()
601 if (!priv->streaming) { in s5k4ecgx_set_fmt()
602 priv->curr_frmsize = fsize; in s5k4ecgx_set_fmt()
603 priv->curr_pixfmt = pf; in s5k4ecgx_set_fmt()
604 priv->set_params = 1; in s5k4ecgx_set_fmt()
606 ret = -EBUSY; in s5k4ecgx_set_fmt()
608 mutex_unlock(&priv->lock); in s5k4ecgx_set_fmt()
624 struct v4l2_subdev *sd = &container_of(ctrl->handler, struct s5k4ecgx, in s5k4ecgx_s_ctrl()
625 handler)->sd; in s5k4ecgx_s_ctrl()
631 v4l2_dbg(1, debug, sd, "ctrl: 0x%x, value: %d\n", ctrl->id, ctrl->val); in s5k4ecgx_s_ctrl()
633 mutex_lock(&priv->lock); in s5k4ecgx_s_ctrl()
634 switch (ctrl->id) { in s5k4ecgx_s_ctrl()
636 err = s5k4ecgx_write(client, REG_USER_CONTRAST, ctrl->val); in s5k4ecgx_s_ctrl()
640 err = s5k4ecgx_write(client, REG_USER_SATURATION, ctrl->val); in s5k4ecgx_s_ctrl()
647 ctrl->val * SHARPNESS_DIV); in s5k4ecgx_s_ctrl()
651 err = s5k4ecgx_write(client, REG_USER_BRIGHTNESS, ctrl->val); in s5k4ecgx_s_ctrl()
654 mutex_unlock(&priv->lock); in s5k4ecgx_s_ctrl()
673 mutex_lock(&priv->lock); in s5k4ecgx_registered()
679 mutex_unlock(&priv->lock); in s5k4ecgx_registered()
689 struct v4l2_mbus_framefmt *mf = v4l2_subdev_get_try_format(sd, fh->pad, 0); in s5k4ecgx_open()
691 mf->width = s5k4ecgx_prev_sizes[0].size.width; in s5k4ecgx_open()
692 mf->height = s5k4ecgx_prev_sizes[0].size.height; in s5k4ecgx_open()
693 mf->code = s5k4ecgx_formats[0].code; in s5k4ecgx_open()
694 mf->colorspace = V4L2_COLORSPACE_JPEG; in s5k4ecgx_open()
695 mf->field = V4L2_FIELD_NONE; in s5k4ecgx_open()
722 priv->set_params = 1; in s5k4ecgx_s_power()
732 v4l2_ctrl_handler_log_status(sd->ctrl_handler, sd->name); in s5k4ecgx_log_status()
744 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); in __s5k4ecgx_s_params()
745 const struct v4l2_rect *crop_rect = &priv->curr_frmsize->input_window; in __s5k4ecgx_s_params()
791 struct i2c_client *client = v4l2_get_subdevdata(&priv->sd); in __s5k4ecgx_s_stream()
794 if (on && priv->set_params) { in __s5k4ecgx_s_stream()
798 priv->set_params = 0; in __s5k4ecgx_s_stream()
817 mutex_lock(&priv->lock); in s5k4ecgx_s_stream()
819 if (priv->streaming == !on) { in s5k4ecgx_s_stream()
822 priv->streaming = on & 1; in s5k4ecgx_s_stream()
825 mutex_unlock(&priv->lock); in s5k4ecgx_s_stream()
860 for (i = 0; i < ARRAY_SIZE(priv->gpio); i++) { in s5k4ecgx_free_gpios()
861 if (!gpio_is_valid(priv->gpio[i].gpio)) in s5k4ecgx_free_gpios()
863 gpio_free(priv->gpio[i].gpio); in s5k4ecgx_free_gpios()
864 priv->gpio[i].gpio = -EINVAL; in s5k4ecgx_free_gpios()
871 const struct s5k4ecgx_gpio *gpio = &pdata->gpio_stby; in s5k4ecgx_config_gpios()
874 priv->gpio[STBY].gpio = -EINVAL; in s5k4ecgx_config_gpios()
875 priv->gpio[RSET].gpio = -EINVAL; in s5k4ecgx_config_gpios()
877 ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_STBY"); in s5k4ecgx_config_gpios()
883 priv->gpio[STBY] = *gpio; in s5k4ecgx_config_gpios()
884 if (gpio_is_valid(gpio->gpio)) in s5k4ecgx_config_gpios()
885 gpio_set_value(gpio->gpio, 0); in s5k4ecgx_config_gpios()
887 gpio = &pdata->gpio_reset; in s5k4ecgx_config_gpios()
889 ret = s5k4ecgx_config_gpio(gpio->gpio, gpio->level, "S5K4ECGX_RST"); in s5k4ecgx_config_gpios()
894 priv->gpio[RSET] = *gpio; in s5k4ecgx_config_gpios()
895 if (gpio_is_valid(gpio->gpio)) in s5k4ecgx_config_gpios()
896 gpio_set_value(gpio->gpio, 0); in s5k4ecgx_config_gpios()
904 struct v4l2_ctrl_handler *hdl = &priv->handler; in s5k4ecgx_init_v4l2_ctrls()
911 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -208, 127, 1, 0); in s5k4ecgx_init_v4l2_ctrls()
912 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0); in s5k4ecgx_init_v4l2_ctrls()
913 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0); in s5k4ecgx_init_v4l2_ctrls()
916 v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -32704/SHARPNESS_DIV, in s5k4ecgx_init_v4l2_ctrls()
918 if (hdl->error) { in s5k4ecgx_init_v4l2_ctrls()
919 ret = hdl->error; in s5k4ecgx_init_v4l2_ctrls()
923 priv->sd.ctrl_handler = hdl; in s5k4ecgx_init_v4l2_ctrls()
931 struct s5k4ecgx_platform_data *pdata = client->dev.platform_data; in s5k4ecgx_probe()
937 dev_err(&client->dev, "platform data is missing!\n"); in s5k4ecgx_probe()
938 return -EINVAL; in s5k4ecgx_probe()
941 priv = devm_kzalloc(&client->dev, sizeof(struct s5k4ecgx), GFP_KERNEL); in s5k4ecgx_probe()
943 return -ENOMEM; in s5k4ecgx_probe()
945 mutex_init(&priv->lock); in s5k4ecgx_probe()
946 priv->streaming = 0; in s5k4ecgx_probe()
948 sd = &priv->sd; in s5k4ecgx_probe()
952 strscpy(sd->name, S5K4ECGX_DRIVER_NAME, sizeof(sd->name)); in s5k4ecgx_probe()
954 sd->internal_ops = &s5k4ecgx_subdev_internal_ops; in s5k4ecgx_probe()
955 /* Support v4l2 sub-device user space API */ in s5k4ecgx_probe()
956 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in s5k4ecgx_probe()
958 priv->pad.flags = MEDIA_PAD_FL_SOURCE; in s5k4ecgx_probe()
959 sd->entity.function = MEDIA_ENT_F_CAM_SENSOR; in s5k4ecgx_probe()
960 ret = media_entity_pads_init(&sd->entity, 1, &priv->pad); in s5k4ecgx_probe()
966 dev_err(&client->dev, "Failed to set gpios\n"); in s5k4ecgx_probe()
970 priv->supplies[i].supply = s5k4ecgx_supply_names[i]; in s5k4ecgx_probe()
972 ret = devm_regulator_bulk_get(&client->dev, S5K4ECGX_NUM_SUPPLIES, in s5k4ecgx_probe()
973 priv->supplies); in s5k4ecgx_probe()
975 dev_err(&client->dev, "Failed to get regulators\n"); in s5k4ecgx_probe()
982 priv->curr_pixfmt = &s5k4ecgx_formats[0]; in s5k4ecgx_probe()
983 priv->curr_frmsize = &s5k4ecgx_prev_sizes[0]; in s5k4ecgx_probe()
990 media_entity_cleanup(&priv->sd.entity); in s5k4ecgx_probe()
1000 mutex_destroy(&priv->lock); in s5k4ecgx_remove()
1003 v4l2_ctrl_handler_free(&priv->handler); in s5k4ecgx_remove()
1004 media_entity_cleanup(&sd->entity); in s5k4ecgx_remove()
1028 MODULE_AUTHOR("Seok-Young Jang <quartz.jang@samsung.com>");