From f0f4ba112466bd5a111c3160d88be2de709b2a0b Mon Sep 17 00:00:00 2001 From: Eunyoung Lee Date: Mon, 22 Jan 2018 15:41:25 +0900 Subject: [PATCH] [COMMON] fimc-is2: Add LC898217 actuator files Change-Id: I9d3df91c7d8e63d4c4761cb6b674739158a7f050 Signed-off-by: Eunyoung Lee --- .../sensor/module_framework/actuator/Kconfig | 8 + .../sensor/module_framework/actuator/Makefile | 1 + .../actuator/fimc-is-actuator-lc898217.c | 442 ++++++++++++++++++ .../actuator/fimc-is-actuator-lc898217.h | 21 + 4 files changed, 472 insertions(+) create mode 100644 drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.c create mode 100644 drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.h diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Kconfig b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Kconfig index 8c82485ac0ee..4f18d087ecb5 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Kconfig +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Kconfig @@ -68,6 +68,14 @@ config CAMERA_ACT_AK7372_OBJ help Use to build AK7372 driver. +config CAMERA_ACT_LC898217_OBJ + bool "Use actuator LC898217" + depends on USE_DIRECT_IS_CONTROL + depends on CAMERA_ACT_SELECT + default n + help + Use to build LC898217 driver. + config CAMERA_ACT_AK737X_OBJ bool "Use actuator AK737X" depends on USE_DIRECT_IS_CONTROL diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Makefile b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Makefile index e141e62c7a77..f1dfe867ce4a 100644 --- a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Makefile +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/Makefile @@ -8,6 +8,7 @@ obj-$(CONFIG_CAMERA_ACT_DW9714_OBJ) += fimc-is-actuator-dw9714.o obj-$(CONFIG_CAMERA_ACT_DW9780_OBJ) += fimc-is-actuator-dw9780.o obj-$(CONFIG_CAMERA_ACT_DW9804_OBJ) += fimc-is-actuator-dw9804.o obj-$(CONFIG_CAMERA_ACT_DW9807_OBJ) += fimc-is-actuator-dw9807.o +obj-$(CONFIG_CAMERA_ACT_LC898217_OBJ) += fimc-is-actuator-lc898217.o obj-$(CONFIG_CAMERA_ACT_ZC533_OBJ) += fimc-is-actuator-zc533.o EXTRA_CFLAGS += -Idrivers/media/platform/exynos/fimc-is2 diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.c b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.c new file mode 100644 index 000000000000..190094de4705 --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.c @@ -0,0 +1,442 @@ +/* + * Samsung Exynos5 SoC series Actuator driver + * + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include +#include +#include + +#include "fimc-is-actuator-lc898217.h" +#include "fimc-is-device-sensor.h" +#include "fimc-is-device-sensor-peri.h" +#include "fimc-is-core.h" + +#include "fimc-is-helper-i2c.h" + +#include "interface/fimc-is-interface-library.h" + +#define ACTUATOR_NAME "LC898217" + +#define DEF_LC898217_FIRST_POSITION 120 +#define DEF_LC898217_FIRST_DELAY 30 + +/* register definition */ +#define REG_TARGET_HIGH 0x84 +#define REG_TARGET_LOW 0x85 +#define REG_SRV_STATE1 0xB0 +#define REG_TGT_CNVTIM 0xB2 + +extern struct fimc_is_lib_support gPtr_lib_support; +extern struct fimc_is_sysfs_actuator sysfs_actuator; + +static int sensor_lc898217_write_position(struct i2c_client *client, u32 val) +{ + int ret = 0; + u8 val_high = 0, val_low = 0; + + BUG_ON(!client); + + if (!client->adapter) { + err("Could not find adapter!\n"); + ret = -ENODEV; + goto p_err; + } + + if (val > LC898217_POS_MAX_SIZE) { + err("Invalid af position(position : %d, Max : %d).\n", + val, LC898217_POS_MAX_SIZE); + ret = -EINVAL; + goto p_err; + } + + val_high = (val >> 8) & 0xFF; + val_low = val & 0xFF; + + ret = fimc_is_sensor_addr8_write8(client, REG_TARGET_HIGH, val_high); + if (ret < 0) + goto p_err; + ret = fimc_is_sensor_addr8_write8(client, REG_TARGET_LOW, val_low); + +p_err: + return ret; +} + +int sensor_lc898217_actuator_init(struct v4l2_subdev *subdev, u32 val) +{ + int ret = 0; + u8 product_id = 0; + struct fimc_is_actuator *actuator; + struct i2c_client *client = NULL; +#ifdef DEBUG_ACTUATOR_TIME + struct timeval st, end; + do_gettimeofday(&st); +#endif + + long cal_addr; + u32 cal_data; + + int first_position = DEF_LC898217_FIRST_POSITION; + + BUG_ON(!subdev); + + dbg_actuator("%s\n", __func__); + + actuator = (struct fimc_is_actuator *)v4l2_get_subdevdata(subdev); + if (!actuator) { + err("actuator is not detect!\n"); + goto p_err; + } + + client = actuator->client; + if (unlikely(!client)) { + err("client is NULL"); + ret = -EINVAL; + goto p_err; + } + + I2C_MUTEX_LOCK(actuator->i2c_lock); + ret = fimc_is_sensor_addr8_read8(client, 0x03, &product_id); + if (ret < 0) + goto p_err_mutex; + +#if 0 + if (product_id != LC898217_PRODUCT_ID) { + err("LC898217 is not detected(%d), Slave: %d\n", product_id, client->addr); + goto p_err_mutex; + } +#endif + + /* EEPROM AF calData address */ + if (gPtr_lib_support.binary_load_flg) { + /* get pan_focus */ + cal_addr = gPtr_lib_support.minfo->kvaddr_rear_cal + EEPROM_OEM_BASE; + memcpy((void *)&cal_data, (void *)cal_addr, sizeof(cal_data)); + + if (cal_data > 0) + first_position = cal_data; + } else { + warn("SDK library is not loaded"); + } + + ret = sensor_lc898217_write_position(client, first_position); + if (ret < 0) + goto p_err_mutex; + actuator->position = first_position; + + /* Go active mode */ + ret = fimc_is_sensor_addr8_write8(client, 0x02, 0); + if (ret < 0) + goto p_err_mutex; + + dbg_actuator("initial position: %d\n", first_position); + + mdelay(DEF_LC898217_FIRST_DELAY); + +#ifdef DEBUG_ACTUATOR_TIME + do_gettimeofday(&end); + pr_info("[%s] time %lu us", __func__, (end.tv_sec - st.tv_sec) * 1000000 + (end.tv_usec - st.tv_usec)); +#endif + +p_err_mutex: + I2C_MUTEX_UNLOCK(actuator->i2c_lock); + +p_err: + return ret; +} + +int sensor_lc898217_actuator_get_status(struct v4l2_subdev *subdev, u32 *info) +{ + int ret = 0; + struct fimc_is_actuator *actuator = NULL; + struct i2c_client *client = NULL; + enum fimc_is_actuator_status status = ACTUATOR_STATUS_NO_BUSY; +#ifdef DEBUG_ACTUATOR_TIME + struct timeval st, end; + do_gettimeofday(&st); +#endif + + dbg_actuator("%s\n", __func__); + + BUG_ON(!subdev); + BUG_ON(!info); + + actuator = (struct fimc_is_actuator *)v4l2_get_subdevdata(subdev); + BUG_ON(!actuator); + + client = actuator->client; + if (unlikely(!client)) { + err("client is NULL"); + ret = -EINVAL; + goto p_err; + } + + /* + * The info is busy flag. + * But, this module can't get busy flag. + */ + status = ACTUATOR_STATUS_NO_BUSY; + *info = status; + +#ifdef DEBUG_ACTUATOR_TIME + do_gettimeofday(&end); + pr_info("[%s] time %lu us", __func__, (end.tv_sec - st.tv_sec) * 1000000 + (end.tv_usec - st.tv_usec)); +#endif + +p_err: + return ret; +} + +int sensor_lc898217_actuator_set_position(struct v4l2_subdev *subdev, u32 *info) +{ + int ret = 0; + struct fimc_is_actuator *actuator; + struct i2c_client *client; + u32 position = 0; +#ifdef DEBUG_ACTUATOR_TIME + struct timeval st, end; + do_gettimeofday(&st); +#endif + + BUG_ON(!subdev); + BUG_ON(!info); + + actuator = (struct fimc_is_actuator *)v4l2_get_subdevdata(subdev); + BUG_ON(!actuator); + + client = actuator->client; + if (unlikely(!client)) { + err("client is NULL"); + ret = -EINVAL; + goto p_err; + } + + I2C_MUTEX_LOCK(actuator->i2c_lock); + position = *info; + if (position > LC898217_POS_MAX_SIZE) { + err("Invalid af position(position : %d, Max : %d).\n", + position, LC898217_POS_MAX_SIZE); + ret = -EINVAL; + goto p_err; + } + + /* debug option : fixed position testing */ + if (sysfs_actuator.enable_fixed) + position = sysfs_actuator.fixed_position; + + /* position Set */ + ret = sensor_lc898217_write_position(client, position); + if (ret < 0) + goto p_err; + actuator->position = position; + + dbg_actuator("%s: position(%d)\n", __func__, position); + +#ifdef DEBUG_ACTUATOR_TIME + do_gettimeofday(&end); + pr_info("[%s] time %lu us", __func__, (end.tv_sec - st.tv_sec) * 1000000 + (end.tv_usec - st.tv_usec)); +#endif +p_err: + I2C_MUTEX_UNLOCK(actuator->i2c_lock); + return ret; +} + +static int sensor_lc898217_actuator_g_ctrl(struct v4l2_subdev *subdev, struct v4l2_control *ctrl) +{ + int ret = 0; + u32 val = 0; + + switch (ctrl->id) { + case V4L2_CID_ACTUATOR_GET_STATUS: + ret = sensor_lc898217_actuator_get_status(subdev, &val); + if (ret < 0) { + err("err!!! ret(%d), actuator status(%d)", ret, val); + ret = -EINVAL; + goto p_err; + } + break; + default: + err("err!!! Unknown CID(%#x)", ctrl->id); + ret = -EINVAL; + goto p_err; + } + + ctrl->value = val; + +p_err: + return ret; +} + +static int sensor_lc898217_actuator_s_ctrl(struct v4l2_subdev *subdev, struct v4l2_control *ctrl) +{ + int ret = 0; + + switch (ctrl->id) { + case V4L2_CID_ACTUATOR_SET_POSITION: + ret = sensor_lc898217_actuator_set_position(subdev, &ctrl->value); + if (ret) { + err("failed to actuator set position: %d, (%d)\n", ctrl->value, ret); + ret = -EINVAL; + goto p_err; + } + break; + default: + err("err!!! Unknown CID(%#x)", ctrl->id); + ret = -EINVAL; + goto p_err; + } + +p_err: + return ret; +} + +static const struct v4l2_subdev_core_ops core_ops = { + .init = sensor_lc898217_actuator_init, + .g_ctrl = sensor_lc898217_actuator_g_ctrl, + .s_ctrl = sensor_lc898217_actuator_s_ctrl, +}; + +static const struct v4l2_subdev_ops subdev_ops = { + .core = &core_ops, +}; + +static int sensor_lc898217_actuator_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct fimc_is_core *core = NULL; + struct v4l2_subdev *subdev_actuator = NULL; + struct fimc_is_actuator *actuator = NULL; + struct fimc_is_device_sensor *device = NULL; + u32 sensor_id = 0; + u32 place = 0; + struct device *dev; + struct device_node *dnode; + + BUG_ON(!fimc_is_dev); + BUG_ON(!client); + + core = (struct fimc_is_core *)dev_get_drvdata(fimc_is_dev); + if (!core) { + err("core device is not yet probed"); + ret = -EPROBE_DEFER; + goto p_err; + } + + dev = &client->dev; + dnode = dev->of_node; + + ret = of_property_read_u32(dnode, "id", &sensor_id); + if (ret) { + err("id read is fail(%d)", ret); + goto p_err; + } + + ret = of_property_read_u32(dnode, "place", &place); + if (ret) { + pr_info("place read is fail(%d)", ret); + place = 0; + } + probe_info("%s sensor_id(%d) actuator_place(%d)\n", __func__, sensor_id, place); + + device = &core->sensor[sensor_id]; + if (!test_bit(FIMC_IS_SENSOR_PROBE, &device->state)) { + err("sensor device is not yet probed"); + ret = -EPROBE_DEFER; + goto p_err; + } + + actuator = kzalloc(sizeof(struct fimc_is_actuator), GFP_KERNEL); + if (!actuator) { + err("actuator is NULL"); + ret = -ENOMEM; + goto p_err; + } + + subdev_actuator = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL); + if (!subdev_actuator) { + err("subdev_actuator is NULL"); + ret = -ENOMEM; + goto p_err; + } + + /* This name must is match to sensor_open_extended actuator name */ + actuator->id = ACTUATOR_NAME_LC898217; + actuator->subdev = subdev_actuator; + actuator->device = sensor_id; + actuator->client = client; + actuator->position = 0; + actuator->max_position = LC898217_POS_MAX_SIZE; + actuator->pos_size_bit = LC898217_POS_SIZE_BIT; + actuator->pos_direction = LC898217_POS_DIRECTION; + actuator->i2c_lock = NULL; + actuator->need_softlanding = 0; + actuator->actuator_ops = NULL; + + device->subdev_actuator[place] = subdev_actuator; + device->actuator[place] = actuator; + + v4l2_i2c_subdev_init(subdev_actuator, client, &subdev_ops); + v4l2_set_subdevdata(subdev_actuator, actuator); + v4l2_set_subdev_hostdata(subdev_actuator, device); + + snprintf(subdev_actuator->name, V4L2_SUBDEV_NAME_SIZE, "actuator-subdev.%d", actuator->id); + + probe_info("%s done\n", __func__); + return ret; + +p_err: + if (!actuator) + kzfree(actuator); + + if (!subdev_actuator) + kzfree(subdev_actuator); + + return ret; +} + +static const struct of_device_id sensor_actuator_lc898217_match[] = { + { + .compatible = "samsung,exynos5-fimc-is-actuator-lc898217", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, sensor_actuator_lc898217_match); + +static const struct i2c_device_id sensor_actuator_lc898217_idt[] = { + { ACTUATOR_NAME, 0 }, + {}, +}; + +static struct i2c_driver sensor_actuator_lc898217_driver = { + .probe = sensor_lc898217_actuator_probe, + .driver = { + .name = ACTUATOR_NAME, + .owner = THIS_MODULE, + .of_match_table = sensor_actuator_lc898217_match, + .suppress_bind_attrs = true, + }, + .id_table = sensor_actuator_lc898217_idt, +}; + +static int __init sensor_actuator_lc898217_init(void) +{ + int ret; + + ret = i2c_add_driver(&sensor_actuator_lc898217_driver); + if (ret) + err("failed to add %s driver: %d\n", + sensor_actuator_lc898217_driver.driver.name, ret); + + return ret; +} +late_initcall_sync(sensor_actuator_lc898217_init); diff --git a/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.h b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.h new file mode 100644 index 000000000000..25fa4a729b7b --- /dev/null +++ b/drivers/media/platform/exynos/fimc-is2/sensor/module_framework/actuator/fimc-is-actuator-lc898217.h @@ -0,0 +1,21 @@ +/* + * Samsung Exynos5 SoC series Actuator driver + * + * + * Copyright (c) 2014 Samsung Electronics Co., Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef FIMC_IS_DEVICE_LC898217_H +#define FIMC_IS_DEVICE_LC898217_H + +#define LC898217_POS_SIZE_BIT ACTUATOR_POS_SIZE_10BIT +#define LC898217_POS_MAX_SIZE ((1 << LC898217_POS_SIZE_BIT) - 1) +#define LC898217_POS_DIRECTION ACTUATOR_RANGE_INF_TO_MAC +#define LC898217_REG_POS_HIGH 0x00 +#define LC898217_REG_POS_LOW 0x01 + +#endif -- 2.20.1