13d0407baSopenharmony_ci// SPDX-License-Identifier: GPL-2.0 23d0407baSopenharmony_ci/* 33d0407baSopenharmony_ci * dw9763 vcm driver 43d0407baSopenharmony_ci * 53d0407baSopenharmony_ci * Copyright (C) 2019 Fuzhou Rockchip Electronics Co., Ltd. 63d0407baSopenharmony_ci */ 73d0407baSopenharmony_ci 83d0407baSopenharmony_ci#include <linux/delay.h> 93d0407baSopenharmony_ci#include <linux/i2c.h> 103d0407baSopenharmony_ci#include <linux/module.h> 113d0407baSopenharmony_ci#include <linux/pm_runtime.h> 123d0407baSopenharmony_ci#include <linux/rk-camera-module.h> 133d0407baSopenharmony_ci#include <linux/version.h> 143d0407baSopenharmony_ci#include <media/v4l2-ctrls.h> 153d0407baSopenharmony_ci#include <media/v4l2-device.h> 163d0407baSopenharmony_ci#include <linux/rk_vcm_head.h> 173d0407baSopenharmony_ci#include <linux/compat.h> 183d0407baSopenharmony_ci 193d0407baSopenharmony_ci#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) 203d0407baSopenharmony_ci#define DW9763_NAME "dw9763" 213d0407baSopenharmony_ci 223d0407baSopenharmony_ci#define DW9763_RING_PD_CONTROL_REG 0x02 233d0407baSopenharmony_ci#define DW9763_DATAM_REG 0X03 243d0407baSopenharmony_ci#define DW9763_DATAL_REG 0X04 253d0407baSopenharmony_ci 263d0407baSopenharmony_ci#define DW9763_STATUS_ADDR 0x05 273d0407baSopenharmony_ci#define DW9763_SAC_PRESC_REG 0x06 283d0407baSopenharmony_ci#define DW9763_SAC_TIME_REG 0x07 293d0407baSopenharmony_ci#define DW9763_FLAG_REG 0X10 303d0407baSopenharmony_ci 313d0407baSopenharmony_ci#define DW9763_MAX_CURRENT 100U 323d0407baSopenharmony_ci#define DW9763_MAX_REG 1023U 333d0407baSopenharmony_ci 343d0407baSopenharmony_ci#define DW9763_DEFAULT_START_CURRENT 0 353d0407baSopenharmony_ci#define DW9763_DEFAULT_RATED_CURRENT 100 363d0407baSopenharmony_ci#define DW9763_DEFAULT_STEP_MODE 0xd 373d0407baSopenharmony_ci#define REG_NULL 0xFF 383d0407baSopenharmony_ci 393d0407baSopenharmony_ci#define OF_CAMERA_VCMDRV_CONTROL_MODE "rockchip,vcm-control-mode" 403d0407baSopenharmony_ci#define OF_CAMERA_VCMDRV_SACDIV_MODE "rockchip,vcm-sacdiv-mode" 413d0407baSopenharmony_ci#define VCMDRV_DEFAULT_CONTROL_MODE 4 423d0407baSopenharmony_ci#define VCMDRV_DEFAULT_SACDIV_MODE 1 433d0407baSopenharmony_ci 443d0407baSopenharmony_ci/* dw9763 device structure */ 453d0407baSopenharmony_cistruct dw9763_device { 463d0407baSopenharmony_ci struct v4l2_ctrl_handler ctrls_vcm; 473d0407baSopenharmony_ci struct v4l2_subdev sd; 483d0407baSopenharmony_ci struct v4l2_device vdev; 493d0407baSopenharmony_ci u16 current_val; 503d0407baSopenharmony_ci 513d0407baSopenharmony_ci unsigned short current_related_pos; 523d0407baSopenharmony_ci unsigned short current_lens_pos; 533d0407baSopenharmony_ci unsigned int start_current; 543d0407baSopenharmony_ci unsigned int rated_current; 553d0407baSopenharmony_ci unsigned int step; 563d0407baSopenharmony_ci unsigned int step_mode; 573d0407baSopenharmony_ci unsigned int control_mode; 583d0407baSopenharmony_ci unsigned int sacdiv_mode; 593d0407baSopenharmony_ci unsigned long mv_time_per_pos; 603d0407baSopenharmony_ci 613d0407baSopenharmony_ci struct __kernel_old_timeval start_move_tv; 623d0407baSopenharmony_ci struct __kernel_old_timeval end_move_tv; 633d0407baSopenharmony_ci unsigned long move_us; 643d0407baSopenharmony_ci 653d0407baSopenharmony_ci u32 module_index; 663d0407baSopenharmony_ci const char *module_facing; 673d0407baSopenharmony_ci}; 683d0407baSopenharmony_ci 693d0407baSopenharmony_cistatic inline struct dw9763_device *to_dw9763_vcm(struct v4l2_ctrl *ctrl) 703d0407baSopenharmony_ci{ 713d0407baSopenharmony_ci return container_of(ctrl->handler, struct dw9763_device, ctrls_vcm); 723d0407baSopenharmony_ci} 733d0407baSopenharmony_ci 743d0407baSopenharmony_cistatic inline struct dw9763_device *sd_to_dw9763_vcm(struct v4l2_subdev *subdev) 753d0407baSopenharmony_ci{ 763d0407baSopenharmony_ci return container_of(subdev, struct dw9763_device, sd); 773d0407baSopenharmony_ci} 783d0407baSopenharmony_ci 793d0407baSopenharmony_cistatic int dw9763_read_reg(struct i2c_client *client, 803d0407baSopenharmony_ci u8 addr, u32 *val, u8 len) 813d0407baSopenharmony_ci{ 823d0407baSopenharmony_ci struct i2c_msg msgs[2]; 833d0407baSopenharmony_ci u8 *data_be_p; 843d0407baSopenharmony_ci __be32 data_be = 0; 853d0407baSopenharmony_ci int ret; 863d0407baSopenharmony_ci 873d0407baSopenharmony_ci if (len > 4 || !len) 883d0407baSopenharmony_ci return -EINVAL; 893d0407baSopenharmony_ci 903d0407baSopenharmony_ci data_be_p = (u8 *)&data_be; 913d0407baSopenharmony_ci /* Write register address */ 923d0407baSopenharmony_ci msgs[0].addr = client->addr; 933d0407baSopenharmony_ci msgs[0].flags = 0; 943d0407baSopenharmony_ci msgs[0].len = 1; 953d0407baSopenharmony_ci msgs[0].buf = (u8 *)&addr; 963d0407baSopenharmony_ci 973d0407baSopenharmony_ci /* Read data from register */ 983d0407baSopenharmony_ci msgs[1].addr = client->addr; 993d0407baSopenharmony_ci msgs[1].flags = I2C_M_RD; 1003d0407baSopenharmony_ci msgs[1].len = len; 1013d0407baSopenharmony_ci msgs[1].buf = &data_be_p[4 - len]; 1023d0407baSopenharmony_ci 1033d0407baSopenharmony_ci ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 1043d0407baSopenharmony_ci if (ret != ARRAY_SIZE(msgs)) 1053d0407baSopenharmony_ci return -EIO; 1063d0407baSopenharmony_ci 1073d0407baSopenharmony_ci *val = be32_to_cpu(data_be); 1083d0407baSopenharmony_ci 1093d0407baSopenharmony_ci return 0; 1103d0407baSopenharmony_ci} 1113d0407baSopenharmony_ci 1123d0407baSopenharmony_cistatic int dw9763_write_reg(struct i2c_client *client, 1133d0407baSopenharmony_ci u8 addr, u32 val, u8 len) 1143d0407baSopenharmony_ci{ 1153d0407baSopenharmony_ci u32 buf_i, val_i; 1163d0407baSopenharmony_ci u8 buf[5]; 1173d0407baSopenharmony_ci u8 *val_p; 1183d0407baSopenharmony_ci __be32 val_be; 1193d0407baSopenharmony_ci 1203d0407baSopenharmony_ci if (len > 4) 1213d0407baSopenharmony_ci return -EINVAL; 1223d0407baSopenharmony_ci 1233d0407baSopenharmony_ci buf[0] = addr & 0xff; 1243d0407baSopenharmony_ci 1253d0407baSopenharmony_ci val_be = cpu_to_be32(val); 1263d0407baSopenharmony_ci val_p = (u8 *)&val_be; 1273d0407baSopenharmony_ci buf_i = 1; 1283d0407baSopenharmony_ci val_i = 4 - len; 1293d0407baSopenharmony_ci 1303d0407baSopenharmony_ci while (val_i < 4) 1313d0407baSopenharmony_ci buf[buf_i++] = val_p[val_i++]; 1323d0407baSopenharmony_ci 1333d0407baSopenharmony_ci if (i2c_master_send(client, buf, len + 1) != len + 1) 1343d0407baSopenharmony_ci return -EIO; 1353d0407baSopenharmony_ci 1363d0407baSopenharmony_ci return 0; 1373d0407baSopenharmony_ci} 1383d0407baSopenharmony_ci 1393d0407baSopenharmony_cistatic int dw9763_get_pos(struct dw9763_device *dev_vcm, 1403d0407baSopenharmony_ci unsigned int *cur_pos) 1413d0407baSopenharmony_ci{ 1423d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); 1433d0407baSopenharmony_ci int ret; 1443d0407baSopenharmony_ci u32 val; 1453d0407baSopenharmony_ci unsigned int abs_step; 1463d0407baSopenharmony_ci 1473d0407baSopenharmony_ci ret = dw9763_read_reg(client, DW9763_DATAM_REG, &val, 2); 1483d0407baSopenharmony_ci if (ret != 0) 1493d0407baSopenharmony_ci goto err; 1503d0407baSopenharmony_ci 1513d0407baSopenharmony_ci abs_step = val & 0x3ff; 1523d0407baSopenharmony_ci if (abs_step <= dev_vcm->start_current) 1533d0407baSopenharmony_ci abs_step = VCMDRV_MAX_LOG; 1543d0407baSopenharmony_ci else if ((abs_step > dev_vcm->start_current) && 1553d0407baSopenharmony_ci (abs_step <= dev_vcm->rated_current)) 1563d0407baSopenharmony_ci abs_step = (dev_vcm->rated_current - abs_step) / dev_vcm->step; 1573d0407baSopenharmony_ci else 1583d0407baSopenharmony_ci abs_step = 0; 1593d0407baSopenharmony_ci 1603d0407baSopenharmony_ci *cur_pos = abs_step; 1613d0407baSopenharmony_ci dev_dbg(&client->dev, "%s: get position %d\n", __func__, *cur_pos); 1623d0407baSopenharmony_ci return 0; 1633d0407baSopenharmony_ci 1643d0407baSopenharmony_cierr: 1653d0407baSopenharmony_ci dev_err(&client->dev, 1663d0407baSopenharmony_ci "%s: failed with error %d\n", __func__, ret); 1673d0407baSopenharmony_ci return ret; 1683d0407baSopenharmony_ci} 1693d0407baSopenharmony_ci 1703d0407baSopenharmony_cistatic int dw9763_set_pos(struct dw9763_device *dev_vcm, 1713d0407baSopenharmony_ci unsigned int dest_pos) 1723d0407baSopenharmony_ci{ 1733d0407baSopenharmony_ci int ret; 1743d0407baSopenharmony_ci unsigned int position = 0; 1753d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); 1763d0407baSopenharmony_ci 1773d0407baSopenharmony_ci if (dest_pos >= VCMDRV_MAX_LOG) 1783d0407baSopenharmony_ci position = dev_vcm->start_current; 1793d0407baSopenharmony_ci else 1803d0407baSopenharmony_ci position = dev_vcm->start_current + 1813d0407baSopenharmony_ci (dev_vcm->step * (VCMDRV_MAX_LOG - dest_pos)); 1823d0407baSopenharmony_ci 1833d0407baSopenharmony_ci if (position > DW9763_MAX_REG) 1843d0407baSopenharmony_ci position = DW9763_MAX_REG; 1853d0407baSopenharmony_ci 1863d0407baSopenharmony_ci dev_vcm->current_lens_pos = position; 1873d0407baSopenharmony_ci dev_vcm->current_related_pos = dest_pos; 1883d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_DATAM_REG, position & 0x3ff, 2); 1893d0407baSopenharmony_ci if (ret != 0) 1903d0407baSopenharmony_ci goto err; 1913d0407baSopenharmony_ci 1923d0407baSopenharmony_ci dev_dbg(&client->dev, "@@@@@@@@ %s: get position %d\n", __func__, position); 1933d0407baSopenharmony_ci return ret; 1943d0407baSopenharmony_cierr: 1953d0407baSopenharmony_ci dev_err(&client->dev, 1963d0407baSopenharmony_ci "%s: failed with error %d\n", __func__, ret); 1973d0407baSopenharmony_ci return ret; 1983d0407baSopenharmony_ci} 1993d0407baSopenharmony_ci 2003d0407baSopenharmony_cistatic int dw9763_get_ctrl(struct v4l2_ctrl *ctrl) 2013d0407baSopenharmony_ci{ 2023d0407baSopenharmony_ci struct dw9763_device *dev_vcm = to_dw9763_vcm(ctrl); 2033d0407baSopenharmony_ci 2043d0407baSopenharmony_ci if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) 2053d0407baSopenharmony_ci return dw9763_get_pos(dev_vcm, &ctrl->val); 2063d0407baSopenharmony_ci 2073d0407baSopenharmony_ci return -EINVAL; 2083d0407baSopenharmony_ci} 2093d0407baSopenharmony_ci 2103d0407baSopenharmony_cistatic int dw9763_set_ctrl(struct v4l2_ctrl *ctrl) 2113d0407baSopenharmony_ci{ 2123d0407baSopenharmony_ci struct dw9763_device *dev_vcm = to_dw9763_vcm(ctrl); 2133d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd); 2143d0407baSopenharmony_ci unsigned int dest_pos = ctrl->val; 2153d0407baSopenharmony_ci int move_pos; 2163d0407baSopenharmony_ci long mv_us; 2173d0407baSopenharmony_ci int ret = 0; 2183d0407baSopenharmony_ci 2193d0407baSopenharmony_ci if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { 2203d0407baSopenharmony_ci if (dest_pos > VCMDRV_MAX_LOG) { 2213d0407baSopenharmony_ci dev_info(&client->dev, 2223d0407baSopenharmony_ci "%s dest_pos is error. %d > %d\n", 2233d0407baSopenharmony_ci __func__, dest_pos, VCMDRV_MAX_LOG); 2243d0407baSopenharmony_ci return -EINVAL; 2253d0407baSopenharmony_ci } 2263d0407baSopenharmony_ci /* calculate move time */ 2273d0407baSopenharmony_ci move_pos = dev_vcm->current_related_pos - dest_pos; 2283d0407baSopenharmony_ci if (move_pos < 0) 2293d0407baSopenharmony_ci move_pos = -move_pos; 2303d0407baSopenharmony_ci 2313d0407baSopenharmony_ci ret = dw9763_set_pos(dev_vcm, dest_pos); 2323d0407baSopenharmony_ci 2333d0407baSopenharmony_ci if (dev_vcm->control_mode == 1) 2343d0407baSopenharmony_ci dev_vcm->move_us = dev_vcm->mv_time_per_pos * move_pos; 2353d0407baSopenharmony_ci else 2363d0407baSopenharmony_ci dev_vcm->move_us = dev_vcm->mv_time_per_pos; 2373d0407baSopenharmony_ci dev_dbg(&client->dev, 2383d0407baSopenharmony_ci "dest_pos %d, move_us %ld\n", 2393d0407baSopenharmony_ci dest_pos, dev_vcm->move_us); 2403d0407baSopenharmony_ci 2413d0407baSopenharmony_ci dev_vcm->start_move_tv = ns_to_kernel_old_timeval(ktime_get_ns()); 2423d0407baSopenharmony_ci mv_us = dev_vcm->start_move_tv.tv_usec + dev_vcm->move_us; 2433d0407baSopenharmony_ci if (mv_us >= 1000000) { 2443d0407baSopenharmony_ci dev_vcm->end_move_tv.tv_sec = 2453d0407baSopenharmony_ci dev_vcm->start_move_tv.tv_sec + 1; 2463d0407baSopenharmony_ci dev_vcm->end_move_tv.tv_usec = mv_us - 1000000; 2473d0407baSopenharmony_ci } else { 2483d0407baSopenharmony_ci dev_vcm->end_move_tv.tv_sec = 2493d0407baSopenharmony_ci dev_vcm->start_move_tv.tv_sec; 2503d0407baSopenharmony_ci dev_vcm->end_move_tv.tv_usec = mv_us; 2513d0407baSopenharmony_ci } 2523d0407baSopenharmony_ci } 2533d0407baSopenharmony_ci 2543d0407baSopenharmony_ci return ret; 2553d0407baSopenharmony_ci} 2563d0407baSopenharmony_ci 2573d0407baSopenharmony_cistatic const struct v4l2_ctrl_ops dw9763_vcm_ctrl_ops = { 2583d0407baSopenharmony_ci .g_volatile_ctrl = dw9763_get_ctrl, 2593d0407baSopenharmony_ci .s_ctrl = dw9763_set_ctrl, 2603d0407baSopenharmony_ci}; 2613d0407baSopenharmony_ci 2623d0407baSopenharmony_cistatic int dw9763t_init(struct dw9763_device *dev) 2633d0407baSopenharmony_ci{ 2643d0407baSopenharmony_ci int ret = 0; 2653d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dev->sd); 2663d0407baSopenharmony_ci u32 control_mode = 0; 2673d0407baSopenharmony_ci u32 step_mode = 0; 2683d0407baSopenharmony_ci 2693d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_RING_PD_CONTROL_REG, 0x01, 1); 2703d0407baSopenharmony_ci if (ret < 0) 2713d0407baSopenharmony_ci goto err; 2723d0407baSopenharmony_ci 2733d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_RING_PD_CONTROL_REG, 0x00, 1); 2743d0407baSopenharmony_ci if (ret < 0) 2753d0407baSopenharmony_ci goto err; 2763d0407baSopenharmony_ci 2773d0407baSopenharmony_ci /*There is need a sleep after power on for write i2c*/ 2783d0407baSopenharmony_ci usleep_range(10000, 11000); 2793d0407baSopenharmony_ci 2803d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_RING_PD_CONTROL_REG, 0x02, 1); 2813d0407baSopenharmony_ci if (ret < 0) 2823d0407baSopenharmony_ci goto err; 2833d0407baSopenharmony_ci 2843d0407baSopenharmony_ci 2853d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_SAC_PRESC_REG, 0x61, 2); 2863d0407baSopenharmony_ci if (ret < 0) 2873d0407baSopenharmony_ci goto err; 2883d0407baSopenharmony_ci 2893d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_SAC_TIME_REG, 0x39, 2); 2903d0407baSopenharmony_ci if (ret < 0) 2913d0407baSopenharmony_ci goto err; 2923d0407baSopenharmony_ci 2933d0407baSopenharmony_ci dev_info(&client->dev, "enter vcm driver init\n"); 2943d0407baSopenharmony_ci /*There is need a sleep after out of standby status*/ 2953d0407baSopenharmony_ci msleep(100); 2963d0407baSopenharmony_ci 2973d0407baSopenharmony_ci /*step_mode = (dev->sacdiv_mode << 6) | (dev->step_mode & 0x3f); 2983d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_SACT_REG, step_mode, 1); 2993d0407baSopenharmony_ci if (ret < 0) 3003d0407baSopenharmony_ci goto err; 3013d0407baSopenharmony_ci control_mode = 0x31; 3023d0407baSopenharmony_ci control_mode |= (dev->control_mode & 0x07) << 1; 3033d0407baSopenharmony_ci ret = dw9763_write_reg(client, DW9763_CONTROL, control_mode, 1); 3043d0407baSopenharmony_ci if (ret < 0) 3053d0407baSopenharmony_ci goto err; 3063d0407baSopenharmony_ci*/ 3073d0407baSopenharmony_ci dev_info(&client->dev, "dw9763t_init OK!!!\n"); 3083d0407baSopenharmony_ci return 0; 3093d0407baSopenharmony_cierr: 3103d0407baSopenharmony_ci dev_err(&client->dev, "failed with error %d\n", ret); 3113d0407baSopenharmony_ci return ret; 3123d0407baSopenharmony_ci} 3133d0407baSopenharmony_ci 3143d0407baSopenharmony_cistatic int dw9763_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 3153d0407baSopenharmony_ci{ 3163d0407baSopenharmony_ci int rval; 3173d0407baSopenharmony_ci struct dw9763_device *dev_vcm = sd_to_dw9763_vcm(sd); 3183d0407baSopenharmony_ci 3193d0407baSopenharmony_ci rval = pm_runtime_get_sync(sd->dev); 3203d0407baSopenharmony_ci if (rval < 0) { 3213d0407baSopenharmony_ci pm_runtime_put_noidle(sd->dev); 3223d0407baSopenharmony_ci return rval; 3233d0407baSopenharmony_ci } 3243d0407baSopenharmony_ci 3253d0407baSopenharmony_ci rval = dw9763t_init(dev_vcm); 3263d0407baSopenharmony_ci if (rval < 0) { 3273d0407baSopenharmony_ci pm_runtime_put_noidle(sd->dev); 3283d0407baSopenharmony_ci return rval; 3293d0407baSopenharmony_ci } 3303d0407baSopenharmony_ci return 0; 3313d0407baSopenharmony_ci} 3323d0407baSopenharmony_ci 3333d0407baSopenharmony_cistatic int dw9763_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 3343d0407baSopenharmony_ci{ 3353d0407baSopenharmony_ci pm_runtime_put(sd->dev); 3363d0407baSopenharmony_ci 3373d0407baSopenharmony_ci return 0; 3383d0407baSopenharmony_ci} 3393d0407baSopenharmony_ci 3403d0407baSopenharmony_cistatic const struct v4l2_subdev_internal_ops dw9763_int_ops = { 3413d0407baSopenharmony_ci .open = dw9763_open, 3423d0407baSopenharmony_ci .close = dw9763_close, 3433d0407baSopenharmony_ci}; 3443d0407baSopenharmony_ci 3453d0407baSopenharmony_cistatic long dw9763_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) 3463d0407baSopenharmony_ci{ 3473d0407baSopenharmony_ci int ret = 0; 3483d0407baSopenharmony_ci struct rk_cam_vcm_tim *vcm_tim; 3493d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 3503d0407baSopenharmony_ci struct dw9763_device *dw9763_dev = sd_to_dw9763_vcm(sd); 3513d0407baSopenharmony_ci 3523d0407baSopenharmony_ci// if (cmd == RK_VIDIOC_VCM_TIMEINFO) { 3533d0407baSopenharmony_ci vcm_tim = (struct rk_cam_vcm_tim *)arg; 3543d0407baSopenharmony_ci 3553d0407baSopenharmony_ci vcm_tim->vcm_start_t.tv_sec = dw9763_dev->start_move_tv.tv_sec; 3563d0407baSopenharmony_ci vcm_tim->vcm_start_t.tv_usec = 3573d0407baSopenharmony_ci dw9763_dev->start_move_tv.tv_usec; 3583d0407baSopenharmony_ci vcm_tim->vcm_end_t.tv_sec = dw9763_dev->end_move_tv.tv_sec; 3593d0407baSopenharmony_ci vcm_tim->vcm_end_t.tv_usec = dw9763_dev->end_move_tv.tv_usec; 3603d0407baSopenharmony_ci 3613d0407baSopenharmony_ci dev_dbg(&client->dev, "dw9763_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", 3623d0407baSopenharmony_ci vcm_tim->vcm_start_t.tv_sec, 3633d0407baSopenharmony_ci vcm_tim->vcm_start_t.tv_usec, 3643d0407baSopenharmony_ci vcm_tim->vcm_end_t.tv_sec, 3653d0407baSopenharmony_ci vcm_tim->vcm_end_t.tv_usec); 3663d0407baSopenharmony_ci //} else { 3673d0407baSopenharmony_ci // dev_err(&client->dev, 3683d0407baSopenharmony_ci // "cmd 0x%x not supported\n", cmd); 3693d0407baSopenharmony_ci // return -EINVAL; 3703d0407baSopenharmony_ci //} 3713d0407baSopenharmony_ci 3723d0407baSopenharmony_ci return ret; 3733d0407baSopenharmony_ci} 3743d0407baSopenharmony_ci 3753d0407baSopenharmony_ci#ifdef CONFIG_COMPAT 3763d0407baSopenharmony_cistatic long dw9763_compat_ioctl32(struct v4l2_subdev *sd, 3773d0407baSopenharmony_ci unsigned int cmd, unsigned long arg) 3783d0407baSopenharmony_ci{ 3793d0407baSopenharmony_ci struct rk_cam_vcm_tim vcm_tim; 3803d0407baSopenharmony_ci struct rk_cam_compat_vcm_tim compat_vcm_tim; 3813d0407baSopenharmony_ci void __user *up = compat_ptr(arg); 3823d0407baSopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(sd); 3833d0407baSopenharmony_ci long ret; 3843d0407baSopenharmony_ci 3853d0407baSopenharmony_ci if (cmd == RK_VIDIOC_COMPAT_VCM_TIMEINFO) { 3863d0407baSopenharmony_ci struct rk_cam_compat_vcm_tim __user *p32 = up; 3873d0407baSopenharmony_ci 3883d0407baSopenharmony_ci ret = dw9763_ioctl(sd, RK_VIDIOC_VCM_TIMEINFO, &vcm_tim); 3893d0407baSopenharmony_ci compat_vcm_tim.vcm_start_t.tv_sec = vcm_tim.vcm_start_t.tv_sec; 3903d0407baSopenharmony_ci compat_vcm_tim.vcm_start_t.tv_usec = 3913d0407baSopenharmony_ci vcm_tim.vcm_start_t.tv_usec; 3923d0407baSopenharmony_ci compat_vcm_tim.vcm_end_t.tv_sec = vcm_tim.vcm_end_t.tv_sec; 3933d0407baSopenharmony_ci compat_vcm_tim.vcm_end_t.tv_usec = vcm_tim.vcm_end_t.tv_usec; 3943d0407baSopenharmony_ci 3953d0407baSopenharmony_ci put_user(compat_vcm_tim.vcm_start_t.tv_sec, 3963d0407baSopenharmony_ci &p32->vcm_start_t.tv_sec); 3973d0407baSopenharmony_ci put_user(compat_vcm_tim.vcm_start_t.tv_usec, 3983d0407baSopenharmony_ci &p32->vcm_start_t.tv_usec); 3993d0407baSopenharmony_ci put_user(compat_vcm_tim.vcm_end_t.tv_sec, 4003d0407baSopenharmony_ci &p32->vcm_end_t.tv_sec); 4013d0407baSopenharmony_ci put_user(compat_vcm_tim.vcm_end_t.tv_usec, 4023d0407baSopenharmony_ci &p32->vcm_end_t.tv_usec); 4033d0407baSopenharmony_ci } else { 4043d0407baSopenharmony_ci dev_err(&client->dev, 4053d0407baSopenharmony_ci "cmd 0x%x not supported\n", cmd); 4063d0407baSopenharmony_ci return -EINVAL; 4073d0407baSopenharmony_ci } 4083d0407baSopenharmony_ci 4093d0407baSopenharmony_ci return ret; 4103d0407baSopenharmony_ci} 4113d0407baSopenharmony_ci#endif 4123d0407baSopenharmony_ci 4133d0407baSopenharmony_cistatic const struct v4l2_subdev_core_ops dw9763_core_ops = { 4143d0407baSopenharmony_ci .ioctl = dw9763_ioctl, 4153d0407baSopenharmony_ci#ifdef CONFIG_COMPAT 4163d0407baSopenharmony_ci .compat_ioctl32 = dw9763_compat_ioctl32 4173d0407baSopenharmony_ci#endif 4183d0407baSopenharmony_ci}; 4193d0407baSopenharmony_ci 4203d0407baSopenharmony_cistatic const struct v4l2_subdev_ops dw9763_ops = { 4213d0407baSopenharmony_ci .core = &dw9763_core_ops, 4223d0407baSopenharmony_ci}; 4233d0407baSopenharmony_ci 4243d0407baSopenharmony_cistatic void dw9763_subdev_cleanup(struct dw9763_device *dw9763_dev) 4253d0407baSopenharmony_ci{ 4263d0407baSopenharmony_ci v4l2_device_unregister_subdev(&dw9763_dev->sd); 4273d0407baSopenharmony_ci v4l2_device_unregister(&dw9763_dev->vdev); 4283d0407baSopenharmony_ci v4l2_ctrl_handler_free(&dw9763_dev->ctrls_vcm); 4293d0407baSopenharmony_ci media_entity_cleanup(&dw9763_dev->sd.entity); 4303d0407baSopenharmony_ci} 4313d0407baSopenharmony_ci 4323d0407baSopenharmony_cistatic int dw9763_init_controls(struct dw9763_device *dev_vcm) 4333d0407baSopenharmony_ci{ 4343d0407baSopenharmony_ci struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm; 4353d0407baSopenharmony_ci const struct v4l2_ctrl_ops *ops = &dw9763_vcm_ctrl_ops; 4363d0407baSopenharmony_ci 4373d0407baSopenharmony_ci v4l2_ctrl_handler_init(hdl, 1); 4383d0407baSopenharmony_ci 4393d0407baSopenharmony_ci v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, 4403d0407baSopenharmony_ci 0, VCMDRV_MAX_LOG, 1, VCMDRV_MAX_LOG); 4413d0407baSopenharmony_ci 4423d0407baSopenharmony_ci if (hdl->error) 4433d0407baSopenharmony_ci dev_err(dev_vcm->sd.dev, "%s fail error: 0x%x\n", 4443d0407baSopenharmony_ci __func__, hdl->error); 4453d0407baSopenharmony_ci dev_vcm->sd.ctrl_handler = hdl; 4463d0407baSopenharmony_ci return hdl->error; 4473d0407baSopenharmony_ci} 4483d0407baSopenharmony_ci 4493d0407baSopenharmony_cistatic int dw9763_probe(struct i2c_client *client, 4503d0407baSopenharmony_ci const struct i2c_device_id *id) 4513d0407baSopenharmony_ci{ 4523d0407baSopenharmony_ci struct device_node *np = of_node_get(client->dev.of_node); 4533d0407baSopenharmony_ci struct dw9763_device *dw9763_dev; 4543d0407baSopenharmony_ci int ret; 4553d0407baSopenharmony_ci int current_distance; 4563d0407baSopenharmony_ci unsigned int start_current; 4573d0407baSopenharmony_ci unsigned int rated_current; 4583d0407baSopenharmony_ci unsigned int step_mode; 4593d0407baSopenharmony_ci unsigned int control_mode; 4603d0407baSopenharmony_ci unsigned int sacdiv_mode; 4613d0407baSopenharmony_ci struct v4l2_subdev *sd; 4623d0407baSopenharmony_ci char facing[2]; 4633d0407baSopenharmony_ci 4643d0407baSopenharmony_ci printk("XXXXXXXXXXXXXXX dw9763_probe\n"); 4653d0407baSopenharmony_ci 4663d0407baSopenharmony_ci dev_info(&client->dev, "probing...\n"); 4673d0407baSopenharmony_ci if (of_property_read_u32(np, 4683d0407baSopenharmony_ci OF_CAMERA_VCMDRV_START_CURRENT, 4693d0407baSopenharmony_ci (unsigned int *)&start_current)) { 4703d0407baSopenharmony_ci start_current = DW9763_DEFAULT_START_CURRENT; 4713d0407baSopenharmony_ci dev_info(&client->dev, 4723d0407baSopenharmony_ci "could not get module %s from dts!\n", 4733d0407baSopenharmony_ci OF_CAMERA_VCMDRV_START_CURRENT); 4743d0407baSopenharmony_ci } 4753d0407baSopenharmony_ci if (of_property_read_u32(np, 4763d0407baSopenharmony_ci OF_CAMERA_VCMDRV_RATED_CURRENT, 4773d0407baSopenharmony_ci (unsigned int *)&rated_current)) { 4783d0407baSopenharmony_ci rated_current = DW9763_DEFAULT_RATED_CURRENT; 4793d0407baSopenharmony_ci dev_info(&client->dev, 4803d0407baSopenharmony_ci "could not get module %s from dts!\n", 4813d0407baSopenharmony_ci OF_CAMERA_VCMDRV_RATED_CURRENT); 4823d0407baSopenharmony_ci } 4833d0407baSopenharmony_ci if (of_property_read_u32(np, 4843d0407baSopenharmony_ci OF_CAMERA_VCMDRV_STEP_MODE, 4853d0407baSopenharmony_ci (unsigned int *)&step_mode)) { 4863d0407baSopenharmony_ci step_mode = DW9763_DEFAULT_STEP_MODE; 4873d0407baSopenharmony_ci dev_info(&client->dev, 4883d0407baSopenharmony_ci "could not get module %s from dts!\n", 4893d0407baSopenharmony_ci OF_CAMERA_VCMDRV_STEP_MODE); 4903d0407baSopenharmony_ci } 4913d0407baSopenharmony_ci if (of_property_read_u32(np, 4923d0407baSopenharmony_ci OF_CAMERA_VCMDRV_CONTROL_MODE, 4933d0407baSopenharmony_ci (unsigned int *)&control_mode)) { 4943d0407baSopenharmony_ci control_mode = VCMDRV_DEFAULT_CONTROL_MODE; 4953d0407baSopenharmony_ci dev_info(&client->dev, 4963d0407baSopenharmony_ci "could not get module %s from dts!\n", 4973d0407baSopenharmony_ci OF_CAMERA_VCMDRV_CONTROL_MODE); 4983d0407baSopenharmony_ci } 4993d0407baSopenharmony_ci if (of_property_read_u32(np, 5003d0407baSopenharmony_ci OF_CAMERA_VCMDRV_SACDIV_MODE, 5013d0407baSopenharmony_ci (unsigned int *)&sacdiv_mode)) { 5023d0407baSopenharmony_ci sacdiv_mode = VCMDRV_DEFAULT_SACDIV_MODE; 5033d0407baSopenharmony_ci dev_info(&client->dev, 5043d0407baSopenharmony_ci "could not get module %s from dts!\n", 5053d0407baSopenharmony_ci OF_CAMERA_VCMDRV_SACDIV_MODE); 5063d0407baSopenharmony_ci } 5073d0407baSopenharmony_ci 5083d0407baSopenharmony_ci dw9763_dev = devm_kzalloc(&client->dev, sizeof(*dw9763_dev), 5093d0407baSopenharmony_ci GFP_KERNEL); 5103d0407baSopenharmony_ci if (dw9763_dev == NULL) 5113d0407baSopenharmony_ci return -ENOMEM; 5123d0407baSopenharmony_ci 5133d0407baSopenharmony_ci ret = of_property_read_u32(np, RKMODULE_CAMERA_MODULE_INDEX, 5143d0407baSopenharmony_ci &dw9763_dev->module_index); 5153d0407baSopenharmony_ci ret |= of_property_read_string(np, RKMODULE_CAMERA_MODULE_FACING, 5163d0407baSopenharmony_ci &dw9763_dev->module_facing); 5173d0407baSopenharmony_ci if (ret) { 5183d0407baSopenharmony_ci dev_err(&client->dev, 5193d0407baSopenharmony_ci "could not get module information!\n"); 5203d0407baSopenharmony_ci return -EINVAL; 5213d0407baSopenharmony_ci } 5223d0407baSopenharmony_ci 5233d0407baSopenharmony_ci v4l2_i2c_subdev_init(&dw9763_dev->sd, client, &dw9763_ops); 5243d0407baSopenharmony_ci dw9763_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 5253d0407baSopenharmony_ci dw9763_dev->sd.internal_ops = &dw9763_int_ops; 5263d0407baSopenharmony_ci 5273d0407baSopenharmony_ci ret = dw9763_init_controls(dw9763_dev); 5283d0407baSopenharmony_ci if (ret) 5293d0407baSopenharmony_ci goto err_cleanup; 5303d0407baSopenharmony_ci 5313d0407baSopenharmony_ci ret = media_entity_pads_init(&dw9763_dev->sd.entity, 0, NULL); 5323d0407baSopenharmony_ci if (ret < 0) 5333d0407baSopenharmony_ci goto err_cleanup; 5343d0407baSopenharmony_ci 5353d0407baSopenharmony_ci sd = &dw9763_dev->sd; 5363d0407baSopenharmony_ci sd->entity.function = MEDIA_ENT_F_LENS; 5373d0407baSopenharmony_ci 5383d0407baSopenharmony_ci memset(facing, 0, sizeof(facing)); 5393d0407baSopenharmony_ci if (strcmp(dw9763_dev->module_facing, "back") == 0) 5403d0407baSopenharmony_ci facing[0] = 'b'; 5413d0407baSopenharmony_ci else 5423d0407baSopenharmony_ci facing[0] = 'f'; 5433d0407baSopenharmony_ci 5443d0407baSopenharmony_ci snprintf(sd->name, sizeof(sd->name), "m%02d_%s_%s %s", 5453d0407baSopenharmony_ci dw9763_dev->module_index, facing, 5463d0407baSopenharmony_ci DW9763_NAME, dev_name(sd->dev)); 5473d0407baSopenharmony_ci ret = v4l2_async_register_subdev(sd); 5483d0407baSopenharmony_ci if (ret) 5493d0407baSopenharmony_ci dev_err(&client->dev, "v4l2 async register subdev failed\n"); 5503d0407baSopenharmony_ci 5513d0407baSopenharmony_ci current_distance = rated_current - start_current; 5523d0407baSopenharmony_ci current_distance = current_distance * DW9763_MAX_REG / 5533d0407baSopenharmony_ci DW9763_MAX_CURRENT; 5543d0407baSopenharmony_ci dw9763_dev->step = (current_distance + (VCMDRV_MAX_LOG - 1)) / 5553d0407baSopenharmony_ci VCMDRV_MAX_LOG; 5563d0407baSopenharmony_ci dw9763_dev->start_current = start_current * DW9763_MAX_REG / 5573d0407baSopenharmony_ci DW9763_MAX_CURRENT; 5583d0407baSopenharmony_ci dw9763_dev->rated_current = dw9763_dev->start_current + 5593d0407baSopenharmony_ci VCMDRV_MAX_LOG * 5603d0407baSopenharmony_ci dw9763_dev->step; 5613d0407baSopenharmony_ci dw9763_dev->step_mode = step_mode; 5623d0407baSopenharmony_ci dw9763_dev->move_us = 0; 5633d0407baSopenharmony_ci dw9763_dev->current_related_pos = VCMDRV_MAX_LOG; 5643d0407baSopenharmony_ci dw9763_dev->start_move_tv = ns_to_kernel_old_timeval(ktime_get_ns()); 5653d0407baSopenharmony_ci dw9763_dev->end_move_tv = ns_to_kernel_old_timeval(ktime_get_ns()); 5663d0407baSopenharmony_ci 5673d0407baSopenharmony_ci switch (control_mode) { 5683d0407baSopenharmony_ci case 0: 5693d0407baSopenharmony_ci dev_err(&client->dev, "control_mode is derect mode, not support\n"); 5703d0407baSopenharmony_ci return -EINVAL; 5713d0407baSopenharmony_ci case 1: 5723d0407baSopenharmony_ci dw9763_dev->mv_time_per_pos = (126 + step_mode * 2) * dw9763_dev->step; 5733d0407baSopenharmony_ci dev_dbg(&client->dev, "control_mode is LSC mode\n"); 5743d0407baSopenharmony_ci break; 5753d0407baSopenharmony_ci case 2: 5763d0407baSopenharmony_ci case 3: 5773d0407baSopenharmony_ci case 4: 5783d0407baSopenharmony_ci case 5: 5793d0407baSopenharmony_ci case 6: 5803d0407baSopenharmony_ci case 7: 5813d0407baSopenharmony_ci dw9763_dev->mv_time_per_pos = (6300 + step_mode * 100); 5823d0407baSopenharmony_ci dev_dbg(&client->dev, "control_mode is LSC mode\n"); 5833d0407baSopenharmony_ci break; 5843d0407baSopenharmony_ci default: 5853d0407baSopenharmony_ci dev_err(&client->dev, "set unknown control_mode\n"); 5863d0407baSopenharmony_ci return -EINVAL; 5873d0407baSopenharmony_ci } 5883d0407baSopenharmony_ci 5893d0407baSopenharmony_ci switch (sacdiv_mode) { 5903d0407baSopenharmony_ci case 0: 5913d0407baSopenharmony_ci dw9763_dev->mv_time_per_pos *= 2; 5923d0407baSopenharmony_ci dev_dbg(&client->dev, "sacdiv_mode is %d\n", sacdiv_mode); 5933d0407baSopenharmony_ci break; 5943d0407baSopenharmony_ci case 1: 5953d0407baSopenharmony_ci dev_dbg(&client->dev, "sacdiv_mode is %d\n", sacdiv_mode); 5963d0407baSopenharmony_ci break; 5973d0407baSopenharmony_ci case 2: 5983d0407baSopenharmony_ci dw9763_dev->mv_time_per_pos /= 2; 5993d0407baSopenharmony_ci dev_dbg(&client->dev, "sacdiv_mode is %d\n", sacdiv_mode); 6003d0407baSopenharmony_ci break; 6013d0407baSopenharmony_ci case 3: 6023d0407baSopenharmony_ci dw9763_dev->mv_time_per_pos /= 4; 6033d0407baSopenharmony_ci dev_dbg(&client->dev, "sacdiv_mode is %d\n", sacdiv_mode); 6043d0407baSopenharmony_ci break; 6053d0407baSopenharmony_ci default: 6063d0407baSopenharmony_ci dev_err(&client->dev, "set unknown control_mode\n"); 6073d0407baSopenharmony_ci return -EINVAL; 6083d0407baSopenharmony_ci } 6093d0407baSopenharmony_ci 6103d0407baSopenharmony_ci pm_runtime_set_active(&client->dev); 6113d0407baSopenharmony_ci pm_runtime_enable(&client->dev); 6123d0407baSopenharmony_ci pm_runtime_idle(&client->dev); 6133d0407baSopenharmony_ci 6143d0407baSopenharmony_ci dev_info(&client->dev, "probing successful\n"); 6153d0407baSopenharmony_ci 6163d0407baSopenharmony_ci printk("XXXXXXXXXXXXXXX dw9763_probe OK\n"); 6173d0407baSopenharmony_ci 6183d0407baSopenharmony_ci return 0; 6193d0407baSopenharmony_ci 6203d0407baSopenharmony_cierr_cleanup: 6213d0407baSopenharmony_ci dw9763_subdev_cleanup(dw9763_dev); 6223d0407baSopenharmony_ci dev_err(&client->dev, "Probe failed: %d\n", ret); 6233d0407baSopenharmony_ci return ret; 6243d0407baSopenharmony_ci} 6253d0407baSopenharmony_ci 6263d0407baSopenharmony_cistatic int dw9763_remove(struct i2c_client *client) 6273d0407baSopenharmony_ci{ 6283d0407baSopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 6293d0407baSopenharmony_ci struct dw9763_device *dw9763_dev = sd_to_dw9763_vcm(sd); 6303d0407baSopenharmony_ci 6313d0407baSopenharmony_ci pm_runtime_disable(&client->dev); 6323d0407baSopenharmony_ci dw9763_subdev_cleanup(dw9763_dev); 6333d0407baSopenharmony_ci 6343d0407baSopenharmony_ci return 0; 6353d0407baSopenharmony_ci} 6363d0407baSopenharmony_ci 6373d0407baSopenharmony_cistatic int __maybe_unused dw9763_vcm_suspend(struct device *dev) 6383d0407baSopenharmony_ci{ 6393d0407baSopenharmony_ci return 0; 6403d0407baSopenharmony_ci} 6413d0407baSopenharmony_ci 6423d0407baSopenharmony_cistatic int __maybe_unused dw9763_vcm_resume(struct device *dev) 6433d0407baSopenharmony_ci{ 6443d0407baSopenharmony_ci return 0; 6453d0407baSopenharmony_ci} 6463d0407baSopenharmony_ci 6473d0407baSopenharmony_cistatic const struct i2c_device_id dw9763_id_table[] = { 6483d0407baSopenharmony_ci { DW9763_NAME, 0 }, 6493d0407baSopenharmony_ci { { 0 } } 6503d0407baSopenharmony_ci}; 6513d0407baSopenharmony_ciMODULE_DEVICE_TABLE(i2c, dw9763_id_table); 6523d0407baSopenharmony_ci 6533d0407baSopenharmony_cistatic const struct of_device_id dw9763_of_table[] = { 6543d0407baSopenharmony_ci { .compatible = "dongwoon,dw9763" }, 6553d0407baSopenharmony_ci { { 0 } } 6563d0407baSopenharmony_ci}; 6573d0407baSopenharmony_ciMODULE_DEVICE_TABLE(of, dw9763_of_table); 6583d0407baSopenharmony_ci 6593d0407baSopenharmony_cistatic const struct dev_pm_ops dw9763_pm_ops = { 6603d0407baSopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(dw9763_vcm_suspend, dw9763_vcm_resume) 6613d0407baSopenharmony_ci SET_RUNTIME_PM_OPS(dw9763_vcm_suspend, dw9763_vcm_resume, NULL) 6623d0407baSopenharmony_ci}; 6633d0407baSopenharmony_ci 6643d0407baSopenharmony_cistatic struct i2c_driver dw9763_i2c_driver = { 6653d0407baSopenharmony_ci .driver = { 6663d0407baSopenharmony_ci .name = DW9763_NAME, 6673d0407baSopenharmony_ci .pm = &dw9763_pm_ops, 6683d0407baSopenharmony_ci .of_match_table = dw9763_of_table, 6693d0407baSopenharmony_ci }, 6703d0407baSopenharmony_ci .probe = &dw9763_probe, 6713d0407baSopenharmony_ci .remove = &dw9763_remove, 6723d0407baSopenharmony_ci .id_table = dw9763_id_table, 6733d0407baSopenharmony_ci}; 6743d0407baSopenharmony_ci 6753d0407baSopenharmony_cimodule_i2c_driver(dw9763_i2c_driver); 6763d0407baSopenharmony_ci 6773d0407baSopenharmony_ciMODULE_DESCRIPTION("DW9763 VCM driver"); 6783d0407baSopenharmony_ciMODULE_LICENSE("GPL v2"); 679