Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (C) 2018 Intel Corporation
0003 
0004 #include <linux/acpi.h>
0005 #include <linux/delay.h>
0006 #include <linux/i2c.h>
0007 #include <linux/iopoll.h>
0008 #include <linux/module.h>
0009 #include <linux/pm_runtime.h>
0010 #include <media/v4l2-ctrls.h>
0011 #include <media/v4l2-device.h>
0012 
0013 #define DW9807_MAX_FOCUS_POS    1023
0014 /*
0015  * This sets the minimum granularity for the focus positions.
0016  * A value of 1 gives maximum accuracy for a desired focus position.
0017  */
0018 #define DW9807_FOCUS_STEPS  1
0019 /*
0020  * This acts as the minimum granularity of lens movement.
0021  * Keep this value power of 2, so the control steps can be
0022  * uniformly adjusted for gradual lens movement, with desired
0023  * number of control steps.
0024  */
0025 #define DW9807_CTRL_STEPS   16
0026 #define DW9807_CTRL_DELAY_US    1000
0027 
0028 #define DW9807_CTL_ADDR     0x02
0029 /*
0030  * DW9807 separates two registers to control the VCM position.
0031  * One for MSB value, another is LSB value.
0032  */
0033 #define DW9807_MSB_ADDR     0x03
0034 #define DW9807_LSB_ADDR     0x04
0035 #define DW9807_STATUS_ADDR  0x05
0036 #define DW9807_MODE_ADDR    0x06
0037 #define DW9807_RESONANCE_ADDR   0x07
0038 
0039 #define MAX_RETRY       10
0040 
0041 struct dw9807_device {
0042     struct v4l2_ctrl_handler ctrls_vcm;
0043     struct v4l2_subdev sd;
0044     u16 current_val;
0045 };
0046 
0047 static inline struct dw9807_device *sd_to_dw9807_vcm(
0048                     struct v4l2_subdev *subdev)
0049 {
0050     return container_of(subdev, struct dw9807_device, sd);
0051 }
0052 
0053 static int dw9807_i2c_check(struct i2c_client *client)
0054 {
0055     const char status_addr = DW9807_STATUS_ADDR;
0056     char status_result;
0057     int ret;
0058 
0059     ret = i2c_master_send(client, &status_addr, sizeof(status_addr));
0060     if (ret < 0) {
0061         dev_err(&client->dev, "I2C write STATUS address fail ret = %d\n",
0062             ret);
0063         return ret;
0064     }
0065 
0066     ret = i2c_master_recv(client, &status_result, sizeof(status_result));
0067     if (ret < 0) {
0068         dev_err(&client->dev, "I2C read STATUS value fail ret = %d\n",
0069             ret);
0070         return ret;
0071     }
0072 
0073     return status_result;
0074 }
0075 
0076 static int dw9807_set_dac(struct i2c_client *client, u16 data)
0077 {
0078     const char tx_data[3] = {
0079         DW9807_MSB_ADDR, ((data >> 8) & 0x03), (data & 0xff)
0080     };
0081     int val, ret;
0082 
0083     /*
0084      * According to the datasheet, need to check the bus status before we
0085      * write VCM position. This ensure that we really write the value
0086      * into the register
0087      */
0088     ret = readx_poll_timeout(dw9807_i2c_check, client, val, val <= 0,
0089             DW9807_CTRL_DELAY_US, MAX_RETRY * DW9807_CTRL_DELAY_US);
0090 
0091     if (ret || val < 0) {
0092         if (ret) {
0093             dev_warn(&client->dev,
0094                 "Cannot do the write operation because VCM is busy\n");
0095         }
0096 
0097         return ret ? -EBUSY : val;
0098     }
0099 
0100     /* Write VCM position to registers */
0101     ret = i2c_master_send(client, tx_data, sizeof(tx_data));
0102     if (ret < 0) {
0103         dev_err(&client->dev,
0104             "I2C write MSB fail ret=%d\n", ret);
0105 
0106         return ret;
0107     }
0108 
0109     return 0;
0110 }
0111 
0112 static int dw9807_set_ctrl(struct v4l2_ctrl *ctrl)
0113 {
0114     struct dw9807_device *dev_vcm = container_of(ctrl->handler,
0115         struct dw9807_device, ctrls_vcm);
0116 
0117     if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) {
0118         struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd);
0119 
0120         dev_vcm->current_val = ctrl->val;
0121         return dw9807_set_dac(client, ctrl->val);
0122     }
0123 
0124     return -EINVAL;
0125 }
0126 
0127 static const struct v4l2_ctrl_ops dw9807_vcm_ctrl_ops = {
0128     .s_ctrl = dw9807_set_ctrl,
0129 };
0130 
0131 static int dw9807_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
0132 {
0133     return pm_runtime_resume_and_get(sd->dev);
0134 }
0135 
0136 static int dw9807_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
0137 {
0138     pm_runtime_put(sd->dev);
0139 
0140     return 0;
0141 }
0142 
0143 static const struct v4l2_subdev_internal_ops dw9807_int_ops = {
0144     .open = dw9807_open,
0145     .close = dw9807_close,
0146 };
0147 
0148 static const struct v4l2_subdev_ops dw9807_ops = { };
0149 
0150 static void dw9807_subdev_cleanup(struct dw9807_device *dw9807_dev)
0151 {
0152     v4l2_async_unregister_subdev(&dw9807_dev->sd);
0153     v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm);
0154     media_entity_cleanup(&dw9807_dev->sd.entity);
0155 }
0156 
0157 static int dw9807_init_controls(struct dw9807_device *dev_vcm)
0158 {
0159     struct v4l2_ctrl_handler *hdl = &dev_vcm->ctrls_vcm;
0160     const struct v4l2_ctrl_ops *ops = &dw9807_vcm_ctrl_ops;
0161     struct i2c_client *client = v4l2_get_subdevdata(&dev_vcm->sd);
0162 
0163     v4l2_ctrl_handler_init(hdl, 1);
0164 
0165     v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE,
0166               0, DW9807_MAX_FOCUS_POS, DW9807_FOCUS_STEPS, 0);
0167 
0168     dev_vcm->sd.ctrl_handler = hdl;
0169     if (hdl->error) {
0170         dev_err(&client->dev, "%s fail error: 0x%x\n",
0171             __func__, hdl->error);
0172         return hdl->error;
0173     }
0174 
0175     return 0;
0176 }
0177 
0178 static int dw9807_probe(struct i2c_client *client)
0179 {
0180     struct dw9807_device *dw9807_dev;
0181     int rval;
0182 
0183     dw9807_dev = devm_kzalloc(&client->dev, sizeof(*dw9807_dev),
0184                   GFP_KERNEL);
0185     if (dw9807_dev == NULL)
0186         return -ENOMEM;
0187 
0188     v4l2_i2c_subdev_init(&dw9807_dev->sd, client, &dw9807_ops);
0189     dw9807_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
0190     dw9807_dev->sd.internal_ops = &dw9807_int_ops;
0191 
0192     rval = dw9807_init_controls(dw9807_dev);
0193     if (rval)
0194         goto err_cleanup;
0195 
0196     rval = media_entity_pads_init(&dw9807_dev->sd.entity, 0, NULL);
0197     if (rval < 0)
0198         goto err_cleanup;
0199 
0200     dw9807_dev->sd.entity.function = MEDIA_ENT_F_LENS;
0201 
0202     rval = v4l2_async_register_subdev(&dw9807_dev->sd);
0203     if (rval < 0)
0204         goto err_cleanup;
0205 
0206     pm_runtime_set_active(&client->dev);
0207     pm_runtime_enable(&client->dev);
0208     pm_runtime_idle(&client->dev);
0209 
0210     return 0;
0211 
0212 err_cleanup:
0213     v4l2_ctrl_handler_free(&dw9807_dev->ctrls_vcm);
0214     media_entity_cleanup(&dw9807_dev->sd.entity);
0215 
0216     return rval;
0217 }
0218 
0219 static int dw9807_remove(struct i2c_client *client)
0220 {
0221     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0222     struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
0223 
0224     pm_runtime_disable(&client->dev);
0225 
0226     dw9807_subdev_cleanup(dw9807_dev);
0227 
0228     return 0;
0229 }
0230 
0231 /*
0232  * This function sets the vcm position, so it consumes least current
0233  * The lens position is gradually moved in units of DW9807_CTRL_STEPS,
0234  * to make the movements smoothly.
0235  */
0236 static int __maybe_unused dw9807_vcm_suspend(struct device *dev)
0237 {
0238     struct i2c_client *client = to_i2c_client(dev);
0239     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0240     struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
0241     const char tx_data[2] = { DW9807_CTL_ADDR, 0x01 };
0242     int ret, val;
0243 
0244     for (val = dw9807_dev->current_val & ~(DW9807_CTRL_STEPS - 1);
0245          val >= 0; val -= DW9807_CTRL_STEPS) {
0246         ret = dw9807_set_dac(client, val);
0247         if (ret)
0248             dev_err_once(dev, "%s I2C failure: %d", __func__, ret);
0249         usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10);
0250     }
0251 
0252     /* Power down */
0253     ret = i2c_master_send(client, tx_data, sizeof(tx_data));
0254     if (ret < 0) {
0255         dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret);
0256         return ret;
0257     }
0258 
0259     return 0;
0260 }
0261 
0262 /*
0263  * This function sets the vcm position to the value set by the user
0264  * through v4l2_ctrl_ops s_ctrl handler
0265  * The lens position is gradually moved in units of DW9807_CTRL_STEPS,
0266  * to make the movements smoothly.
0267  */
0268 static int  __maybe_unused dw9807_vcm_resume(struct device *dev)
0269 {
0270     struct i2c_client *client = to_i2c_client(dev);
0271     struct v4l2_subdev *sd = i2c_get_clientdata(client);
0272     struct dw9807_device *dw9807_dev = sd_to_dw9807_vcm(sd);
0273     const char tx_data[2] = { DW9807_CTL_ADDR, 0x00 };
0274     int ret, val;
0275 
0276     /* Power on */
0277     ret = i2c_master_send(client, tx_data, sizeof(tx_data));
0278     if (ret < 0) {
0279         dev_err(&client->dev, "I2C write CTL fail ret = %d\n", ret);
0280         return ret;
0281     }
0282 
0283     for (val = dw9807_dev->current_val % DW9807_CTRL_STEPS;
0284          val < dw9807_dev->current_val + DW9807_CTRL_STEPS - 1;
0285          val += DW9807_CTRL_STEPS) {
0286         ret = dw9807_set_dac(client, val);
0287         if (ret)
0288             dev_err_ratelimited(dev, "%s I2C failure: %d",
0289                         __func__, ret);
0290         usleep_range(DW9807_CTRL_DELAY_US, DW9807_CTRL_DELAY_US + 10);
0291     }
0292 
0293     return 0;
0294 }
0295 
0296 static const struct of_device_id dw9807_of_table[] = {
0297     { .compatible = "dongwoon,dw9807-vcm" },
0298     /* Compatibility for older firmware, NEVER USE THIS IN FIRMWARE! */
0299     { .compatible = "dongwoon,dw9807" },
0300     { /* sentinel */ }
0301 };
0302 MODULE_DEVICE_TABLE(of, dw9807_of_table);
0303 
0304 static const struct dev_pm_ops dw9807_pm_ops = {
0305     SET_SYSTEM_SLEEP_PM_OPS(dw9807_vcm_suspend, dw9807_vcm_resume)
0306     SET_RUNTIME_PM_OPS(dw9807_vcm_suspend, dw9807_vcm_resume, NULL)
0307 };
0308 
0309 static struct i2c_driver dw9807_i2c_driver = {
0310     .driver = {
0311         .name = "dw9807",
0312         .pm = &dw9807_pm_ops,
0313         .of_match_table = dw9807_of_table,
0314     },
0315     .probe_new = dw9807_probe,
0316     .remove = dw9807_remove,
0317 };
0318 
0319 module_i2c_driver(dw9807_i2c_driver);
0320 
0321 MODULE_AUTHOR("Chiang, Alan");
0322 MODULE_DESCRIPTION("DW9807 VCM driver");
0323 MODULE_LICENSE("GPL v2");