Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add some upstream commits #391

Merged
merged 15 commits into from
Feb 15, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions drivers/media/i2c/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ config VIDEO_IMX214
tristate "Sony IMX214 sensor support"
depends on GPIOLIB
select REGMAP_I2C
select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the Sony
IMX214 camera.
Expand Down
113 changes: 71 additions & 42 deletions drivers/media/i2c/dw9719.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Copyright (c) 2012 Intel Corporation

/*
* Based on linux/modules/camera/drivers/media/i2c/imx/dw9719.c in this repo:
* https://github.com/ZenfoneArea/android_kernel_asus_zenfone5
* Based on linux/modules/camera/drivers/media/i2c/imx/dw9719.c from:
* https://github.com/ZenfoneArea/android_kernel_asus_zenfone5 and
* latte-l-oss/drivers/external_drivers/camera/drivers/media/i2c/micam/dw9761.c
* from: https://github.com/MiCode/Xiaomi_Kernel_OpenSource/
*/

#include <linux/delay.h>
Expand All @@ -23,26 +25,45 @@

#define DW9719_INFO CCI_REG8(0)
#define DW9719_ID 0xF1
#define DW9761_ID 0xF4

#define DW9719_CONTROL CCI_REG8(2)
#define DW9719_STANDBY 0x00
#define DW9719_SHUTDOWN 0x01
#define DW9719_ENABLE_RINGING 0x02

#define DW9719_VCM_CURRENT CCI_REG16(3)

#define DW9719_STATUS CCI_REG16(5)
#define DW9719_STATUS_BUSY BIT(0)

#define DW9719_MODE CCI_REG8(6)
#define DW9719_MODE_SAC_SHIFT 4
#define DW9719_MODE_SAC3 4
#define DW9719_DEFAULT_SAC 4
#define DW9761_DEFAULT_SAC 6

#define DW9719_VCM_FREQ CCI_REG8(7)
#define DW9719_DEFAULT_VCM_FREQ 0x60
#define DW9761_DEFAULT_VCM_FREQ 0x3E

#define DW9761_VCM_PRELOAD CCI_REG8(8)
#define DW9761_DEFAULT_VCM_PRELOAD 0x73


#define to_dw9719_device(x) container_of(x, struct dw9719_device, sd)

enum dw9719_model {
DW9719,
DW9761,
};

struct dw9719_device {
struct v4l2_subdev sd;
struct device *dev;
struct regmap *regmap;
struct regulator *regulator;
enum dw9719_model model;
u32 mode_low_bits;
u32 sac_mode;
u32 vcm_freq;

Expand All @@ -52,47 +73,69 @@ struct dw9719_device {
} ctrls;
};

static int dw9719_detect(struct dw9719_device *dw9719)
{
int ret;
u64 val;

ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL);
if (ret < 0)
return ret;

if (val != DW9719_ID) {
dev_err(dw9719->dev, "Failed to detect correct id\n");
return -ENXIO;
}

return 0;
}

static int dw9719_power_down(struct dw9719_device *dw9719)
{
return regulator_disable(dw9719->regulator);
}

static int dw9719_power_up(struct dw9719_device *dw9719)
static int dw9719_power_up(struct dw9719_device *dw9719, bool detect)
{
u64 val;
int ret;

ret = regulator_enable(dw9719->regulator);
if (ret)
return ret;

/* Jiggle SCL pin to wake up device */
cci_write(dw9719->regmap, DW9719_CONTROL, 1, &ret);

cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_SHUTDOWN, &ret);
fsleep(100);
cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_STANDBY, &ret);
/* Need 100us to transit from SHUTDOWN to STANDBY */
fsleep(100);

if (detect) {
ret = cci_read(dw9719->regmap, DW9719_INFO, &val, NULL);
if (ret < 0)
return ret;

switch (val) {
case DW9719_ID:
dw9719->model = DW9719;
dw9719->mode_low_bits = 0x00;
dw9719->sac_mode = DW9719_DEFAULT_SAC;
dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ;
break;
case DW9761_ID:
dw9719->model = DW9761;
dw9719->mode_low_bits = 0x01;
dw9719->sac_mode = DW9761_DEFAULT_SAC;
dw9719->vcm_freq = DW9761_DEFAULT_VCM_FREQ;
break;
default:
dev_err(dw9719->dev,
"Error unknown device id 0x%02llx\n", val);
return -ENXIO;
}

/* Optional indication of SAC mode select */
device_property_read_u32(dw9719->dev, "dongwoon,sac-mode",
&dw9719->sac_mode);

/* Optional indication of VCM frequency */
device_property_read_u32(dw9719->dev, "dongwoon,vcm-freq",
&dw9719->vcm_freq);
}

cci_write(dw9719->regmap, DW9719_CONTROL, DW9719_ENABLE_RINGING, &ret);
cci_write(dw9719->regmap, DW9719_MODE,
dw9719->sac_mode << DW9719_MODE_SAC_SHIFT, &ret);
cci_write(dw9719->regmap, DW9719_MODE, dw9719->mode_low_bits |
(dw9719->sac_mode << DW9719_MODE_SAC_SHIFT), &ret);
cci_write(dw9719->regmap, DW9719_VCM_FREQ, dw9719->vcm_freq, &ret);

if (dw9719->model == DW9761)
cci_write(dw9719->regmap, DW9761_VCM_PRELOAD,
DW9761_DEFAULT_VCM_PRELOAD, &ret);

if (ret)
dw9719_power_down(dw9719);

Expand Down Expand Up @@ -159,7 +202,7 @@ static int dw9719_resume(struct device *dev)
int ret;
int val;

ret = dw9719_power_up(dw9719);
ret = dw9719_power_up(dw9719, false);
if (ret)
return ret;

Expand Down Expand Up @@ -237,16 +280,6 @@ static int dw9719_probe(struct i2c_client *client)
return PTR_ERR(dw9719->regmap);

dw9719->dev = &client->dev;
dw9719->sac_mode = DW9719_MODE_SAC3;
dw9719->vcm_freq = DW9719_DEFAULT_VCM_FREQ;

/* Optional indication of SAC mode select */
device_property_read_u32(&client->dev, "dongwoon,sac-mode",
&dw9719->sac_mode);

/* Optional indication of VCM frequency */
device_property_read_u32(&client->dev, "dongwoon,vcm-freq",
&dw9719->vcm_freq);

dw9719->regulator = devm_regulator_get(&client->dev, "vdd");
if (IS_ERR(dw9719->regulator))
Expand Down Expand Up @@ -274,14 +307,10 @@ static int dw9719_probe(struct i2c_client *client)
* will work.
*/

ret = dw9719_power_up(dw9719);
ret = dw9719_power_up(dw9719, true);
if (ret)
goto err_cleanup_media;

ret = dw9719_detect(dw9719);
if (ret)
goto err_powerdown;

pm_runtime_set_active(&client->dev);
pm_runtime_get_noresume(&client->dev);
pm_runtime_enable(&client->dev);
Expand All @@ -299,7 +328,6 @@ static int dw9719_probe(struct i2c_client *client)
err_pm_runtime:
pm_runtime_disable(&client->dev);
pm_runtime_put_noidle(&client->dev);
err_powerdown:
dw9719_power_down(dw9719);
err_cleanup_media:
media_entity_cleanup(&dw9719->sd.entity);
Expand Down Expand Up @@ -327,6 +355,7 @@ static void dw9719_remove(struct i2c_client *client)

static const struct i2c_device_id dw9719_id_table[] = {
{ "dw9719" },
{ "dw9761" },
{ }
};
MODULE_DEVICE_TABLE(i2c, dw9719_id_table);
Expand Down
Loading