From 9370bb92b2d16684ee45cf24e879c93c509162da Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Thu, 19 Dec 2024 01:47:39 +0000 Subject: [PATCH] add wifi6 8852be driver --- kernel/drivers/media/i2c/dw9763.c | 216 +++++++++++++++++++++++++++++++++++++++++------------ 1 files changed, 167 insertions(+), 49 deletions(-) diff --git a/kernel/drivers/media/i2c/dw9763.c b/kernel/drivers/media/i2c/dw9763.c index 907b543..337f97f 100644 --- a/kernel/drivers/media/i2c/dw9763.c +++ b/kernel/drivers/media/i2c/dw9763.c @@ -15,12 +15,14 @@ #include <media/v4l2-device.h> #include <linux/rk_vcm_head.h> #include <linux/compat.h> +#include <linux/regulator/consumer.h> -#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x0) +#define DRIVER_VERSION KERNEL_VERSION(0, 0x01, 0x1) #define DW9763_NAME "dw9763" #define DW9763_MAX_CURRENT 120U #define DW9763_MAX_REG 1023U +#define DW9763_GRADUAL_MOVELENS_STEPS 32 #define DW9763_DEFAULT_START_CURRENT 20 #define DW9763_DEFAULT_RATED_CURRENT 90 @@ -40,6 +42,10 @@ SAC4_MODE = 5, DIRECT_MODE, }; + +static int debug; +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "debug level (0-2)"); /* dw9763 device structure */ struct dw9763_device { @@ -69,6 +75,8 @@ struct rk_cam_vcm_cfg vcm_cfg; int max_ma; struct mutex lock; + struct regulator *supply; + bool power_on; }; static inline struct dw9763_device *to_dw9763_vcm(struct v4l2_ctrl *ctrl) @@ -88,6 +96,7 @@ u8 buf[5]; u8 *val_p; __be32 val_be; + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); if (len > 4) return -EINVAL; @@ -106,7 +115,7 @@ dev_err(&client->dev, "Failed to write 0x%04x,0x%x\n", reg, val); return -EIO; } - dev_dbg(&client->dev, "succeed to write 0x%04x,0x%x\n", reg, val); + v4l2_dbg(1, debug, &dev_vcm->sd, "succeed to write 0x%04x,0x%x\n", reg, val); return 0; } @@ -120,6 +129,7 @@ u8 *data_be_p; __be32 data_be = 0; int ret; + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); if (len > 4 || !len) return -EINVAL; @@ -142,6 +152,8 @@ return -EIO; *val = be32_to_cpu(data_be); + + v4l2_dbg(1, debug, &dev_vcm->sd, "succeed to read 0x%04x,0x%x\n", reg, *val); return 0; } @@ -204,11 +216,11 @@ break; } - dev_dbg(&client->dev, + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: vcm_movefull_t is: %d us\n", __func__, move_time_us); - return move_time_us; + return ((move_time_us + 500) / 1000); } static int dw9763_set_dac(struct dw9763_device *dev_vcm, @@ -228,7 +240,7 @@ ret = dw9763_write_reg(client, 0x03, 2, dest_dac); if (ret != 0) goto err; - dev_dbg(&client->dev, + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: set reg val %d\n", __func__, dest_dac); return ret; @@ -249,7 +261,7 @@ goto err; *cur_dac = abs_step; - dev_dbg(&client->dev, "%s: get dac %d\n", __func__, *cur_dac); + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: get dac %d\n", __func__, *cur_dac); return 0; @@ -279,7 +291,7 @@ abs_step = 0; *cur_pos = abs_step; - dev_dbg(&client->dev, "%s: get position %d\n", __func__, *cur_pos); + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: get position %d\n", __func__, *cur_pos); return 0; err: @@ -293,7 +305,6 @@ { int ret; unsigned int position = 0; - struct i2c_client *client = dev_vcm->client; if (dest_pos >= VCMDRV_MAX_LOG) position = dev_vcm->start_current; @@ -308,7 +319,8 @@ dev_vcm->current_related_pos = dest_pos; ret = dw9763_set_dac(dev_vcm, position); - dev_dbg(&client->dev, "%s: set position %d, dac %d\n", __func__, dest_pos, position); + v4l2_dbg(1, debug, &dev_vcm->sd, "%s: set position %d, dac %d\n", + __func__, dest_pos, position); return ret; } @@ -331,7 +343,7 @@ long mv_us; int ret = 0; - dev_dbg(&client->dev, "ctrl->id: 0x%x, ctrl->val: 0x%x\n", + v4l2_dbg(1, debug, &dev_vcm->sd, "ctrl->id: 0x%x, ctrl->val: 0x%x\n", ctrl->id, ctrl->val); if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) { @@ -345,9 +357,9 @@ ret = dw9763_set_pos(dev_vcm, dest_pos); - dev_vcm->move_us = dev_vcm->vcm_movefull_t; + dev_vcm->move_us = dev_vcm->vcm_movefull_t * 1000; - dev_dbg(&client->dev, + v4l2_dbg(1, debug, &dev_vcm->sd, "dest_pos %d, move_us %ld\n", dest_pos, dev_vcm->move_us); @@ -373,9 +385,19 @@ .s_ctrl = dw9763_set_ctrl, }; +static int dw9763_init(struct i2c_client *client); static int dw9763_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { int rval; + struct dw9763_device *dev_vcm = sd_to_dw9763_vcm(sd); + unsigned int move_time; + int dac = dev_vcm->start_current; + struct i2c_client *client = dev_vcm->client; + +#ifdef CONFIG_PM + v4l2_info(sd, "%s: enter, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif rval = pm_runtime_get_sync(sd->dev); if (rval < 0) { @@ -383,12 +405,72 @@ return rval; } + dw9763_init(client); + + v4l2_dbg(1, debug, sd, "%s: current_lens_pos %d, current_related_pos %d\n", + __func__, dev_vcm->current_lens_pos, dev_vcm->current_related_pos); + + move_time = 1000 * dw9763_move_time(dev_vcm, DW9763_GRADUAL_MOVELENS_STEPS); + while (dac <= dev_vcm->current_lens_pos) { + dw9763_set_dac(dev_vcm, dac); + usleep_range(move_time, move_time + 100); + dac += DW9763_GRADUAL_MOVELENS_STEPS; + if (dac > dev_vcm->current_lens_pos) + break; + } + + if (dac > dev_vcm->current_lens_pos) { + dac = dev_vcm->current_lens_pos; + dw9763_set_dac(dev_vcm, dac); + } + +#ifdef CONFIG_PM + v4l2_info(sd, "%s: exit, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif return 0; } static int dw9763_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) { + struct dw9763_device *dev_vcm = sd_to_dw9763_vcm(sd); + int dac = dev_vcm->current_lens_pos; + unsigned int move_time; + int ret; + struct i2c_client *client = dev_vcm->client; + +#ifdef CONFIG_PM + v4l2_info(sd, "%s: enter, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif + + v4l2_dbg(1, debug, sd, "%s: current_lens_pos %d, current_related_pos %d\n", + __func__, dev_vcm->current_lens_pos, dev_vcm->current_related_pos); + + dac -= DW9763_GRADUAL_MOVELENS_STEPS; + move_time = 1000 * dw9763_move_time(dev_vcm, DW9763_GRADUAL_MOVELENS_STEPS); + while (dac >= DW9763_GRADUAL_MOVELENS_STEPS) { + dw9763_set_dac(dev_vcm, dac); + usleep_range(move_time, move_time + 1000); + dac -= DW9763_GRADUAL_MOVELENS_STEPS; + if (dac <= 0) + break; + } + + if (dac < DW9763_GRADUAL_MOVELENS_STEPS) { + dac = DW9763_GRADUAL_MOVELENS_STEPS / 2; + dw9763_set_dac(dev_vcm, dac); + } + /* set to power down mode */ + ret = dw9763_write_reg(client, 0x02, 1, 0x01); + if (ret) + dev_err(&client->dev, "failed to set power down mode!\n"); + pm_runtime_put(sd->dev); +#ifdef CONFIG_PM + v4l2_info(sd, "%s: exit, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif return 0; } @@ -442,7 +524,7 @@ vcm_tim->vcm_end_t.tv_sec = dev_vcm->end_move_tv.tv_sec; vcm_tim->vcm_end_t.tv_usec = dev_vcm->end_move_tv.tv_usec; - dev_dbg(&client->dev, "dw9763_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", + v4l2_dbg(1, debug, &dev_vcm->sd, "dw9763_get_move_res 0x%lx, 0x%lx, 0x%lx, 0x%lx\n", vcm_tim->vcm_start_t.tv_sec, vcm_tim->vcm_start_t.tv_usec, vcm_tim->vcm_end_t.tv_sec, @@ -634,13 +716,50 @@ } #endif -static int __dw9763_set_power(struct dw9763_device *dw9763_dev, bool on) +static int __dw9763_set_power(struct dw9763_device *dw9763, bool on) { - if (dw9763_dev->power_gpio) - gpiod_direction_output(dw9763_dev->power_gpio, on); - usleep_range(10000, 11000); + struct i2c_client *client = dw9763->client; + int ret = 0; - return 0; + dev_info(&client->dev, "%s(%d) on(%d)\n", __func__, __LINE__, on); + + if (dw9763->power_on == !!on) + goto unlock_and_return; + + if (on) { + ret = regulator_enable(dw9763->supply); + if (ret < 0) { + dev_err(&client->dev, "Failed to enable regulator\n"); + goto unlock_and_return; + } + dw9763->power_on = true; + } else { + ret = regulator_disable(dw9763->supply); + if (ret < 0) { + dev_err(&client->dev, "Failed to disable regulator\n"); + goto unlock_and_return; + } + dw9763->power_on = false; + } + +unlock_and_return: + return ret; +} + +static int dw9763_configure_regulator(struct dw9763_device *dw9763) +{ + struct i2c_client *client = dw9763->client; + int ret = 0; + + dw9763->supply = devm_regulator_get(&client->dev, "avdd"); + if (IS_ERR(dw9763->supply)) { + ret = PTR_ERR(dw9763->supply); + if (ret != -EPROBE_DEFER) + dev_err(&client->dev, "could not get regulator avdd\n"); + return ret; + } + dw9763->power_on = false; + return ret; } static int __maybe_unused dw9763_check_id(struct dw9763_device *dw9763_dev) @@ -661,20 +780,6 @@ dev_info(&dw9763_dev->client->dev, "Detected dw9763 vcm id:0x%x\n", DW9763_CHIP_ID); return 0; -} -static int dw9763_probe_init(struct i2c_client *client) -{ - int ret = 0; - - /* Default goto power down mode when finished probe */ - ret = dw9763_write_reg(client, 0x02, 1, 0x01); - if (ret) - goto err; - - return 0; -err: - dev_err(&client->dev, "probe init failed with error %d\n", ret); - return -1; } static int dw9763_probe(struct i2c_client *client, @@ -765,9 +870,11 @@ dev_warn(&client->dev, "Failed to get power-gpios, maybe no use\n"); } - - /* enter power down mode */ - dw9763_probe_init(client); + ret = dw9763_configure_regulator(dw9763_dev); + if (ret) { + dev_err(&client->dev, "Failed to get power regulator!\n"); + return ret; + } v4l2_i2c_subdev_init(&dw9763_dev->sd, client, &dw9763_ops); dw9763_dev->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; @@ -780,6 +887,10 @@ ret = media_entity_pads_init(&dw9763_dev->sd.entity, 0, NULL); if (ret < 0) goto err_cleanup; + + ret = dw9763_check_id(dw9763_dev); + if (ret) + goto err_power_off; sd = &dw9763_dev->sd; sd->entity.function = MEDIA_ENT_F_LENS; @@ -823,6 +934,9 @@ dev_info(&client->dev, "probing successful\n"); return 0; +err_power_off: + __dw9763_set_power(dw9763_dev, false); + err_cleanup: dw9763_subdev_cleanup(dw9763_dev); @@ -847,21 +961,18 @@ { struct dw9763_device *dev_vcm = i2c_get_clientdata(client); int ret = 0; - u32 ring = 0; u32 mode_val = 0; u32 algo_time = 0; + if (dev_vcm->step_mode == DIRECT_MODE) + return 0; - /* Delay 200us~300us */ - usleep_range(200, 300); ret = dw9763_write_reg(client, 0x02, 1, 0x00); if (ret) goto err; - usleep_range(100, 200); - if (dev_vcm->step_mode != DIRECT_MODE) - ring = 0x02; - ret = dw9763_write_reg(client, 0x02, 1, ring); + usleep_range(200, 300); + ret = dw9763_write_reg(client, 0x02, 1, 0x02); if (ret) goto err; switch (dev_vcm->step_mode) { @@ -895,13 +1006,15 @@ static int __maybe_unused dw9763_vcm_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - int ret = 0; + struct dw9763_device *dev_vcm = i2c_get_clientdata(client); + struct v4l2_subdev *sd = &(dev_vcm->sd); - /* set to power down mode */ - ret = dw9763_write_reg(client, 0x02, 1, 0x01); - if (ret) - dev_err(&client->dev, "failed to set power down mode!\n"); +#ifdef CONFIG_PM + v4l2_dbg(1, debug, sd, "%s: enter, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif + __dw9763_set_power(dev_vcm, false); return 0; } @@ -909,9 +1022,14 @@ { struct i2c_client *client = to_i2c_client(dev); struct dw9763_device *dev_vcm = i2c_get_clientdata(client); + struct v4l2_subdev *sd = &(dev_vcm->sd); - dw9763_init(client); - dw9763_set_pos(dev_vcm, dev_vcm->current_related_pos); +#ifdef CONFIG_PM + v4l2_dbg(1, debug, sd, "%s: enter, power.usage_count(%d)!\n", __func__, + atomic_read(&sd->dev->power.usage_count)); +#endif + __dw9763_set_power(dev_vcm, true); + return 0; } -- Gitblit v1.6.2