18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// Copyright (c) 2020 MediaTek Inc. 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include <linux/delay.h> 58c2ecf20Sopenharmony_ci#include <linux/i2c.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 88c2ecf20Sopenharmony_ci#include <linux/regulator/consumer.h> 98c2ecf20Sopenharmony_ci#include <media/v4l2-async.h> 108c2ecf20Sopenharmony_ci#include <media/v4l2-ctrls.h> 118c2ecf20Sopenharmony_ci#include <media/v4l2-device.h> 128c2ecf20Sopenharmony_ci#include <media/v4l2-fwnode.h> 138c2ecf20Sopenharmony_ci#include <media/v4l2-subdev.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define DW9768_NAME "dw9768" 168c2ecf20Sopenharmony_ci#define DW9768_MAX_FOCUS_POS (1024 - 1) 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * This sets the minimum granularity for the focus positions. 198c2ecf20Sopenharmony_ci * A value of 1 gives maximum accuracy for a desired focus position 208c2ecf20Sopenharmony_ci */ 218c2ecf20Sopenharmony_ci#define DW9768_FOCUS_STEPS 1 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* 248c2ecf20Sopenharmony_ci * Ring control and Power control register 258c2ecf20Sopenharmony_ci * Bit[1] RING_EN 268c2ecf20Sopenharmony_ci * 0: Direct mode 278c2ecf20Sopenharmony_ci * 1: AAC mode (ringing control mode) 288c2ecf20Sopenharmony_ci * Bit[0] PD 298c2ecf20Sopenharmony_ci * 0: Normal operation mode 308c2ecf20Sopenharmony_ci * 1: Power down mode 318c2ecf20Sopenharmony_ci * DW9768 requires waiting time of Topr after PD reset takes place. 328c2ecf20Sopenharmony_ci */ 338c2ecf20Sopenharmony_ci#define DW9768_RING_PD_CONTROL_REG 0x02 348c2ecf20Sopenharmony_ci#define DW9768_PD_MODE_OFF 0x00 358c2ecf20Sopenharmony_ci#define DW9768_PD_MODE_EN BIT(0) 368c2ecf20Sopenharmony_ci#define DW9768_AAC_MODE_EN BIT(1) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* 398c2ecf20Sopenharmony_ci * DW9768 separates two registers to control the VCM position. 408c2ecf20Sopenharmony_ci * One for MSB value, another is LSB value. 418c2ecf20Sopenharmony_ci * DAC_MSB: D[9:8] (ADD: 0x03) 428c2ecf20Sopenharmony_ci * DAC_LSB: D[7:0] (ADD: 0x04) 438c2ecf20Sopenharmony_ci * D[9:0] DAC data input: positive output current = D[9:0] / 1023 * 100[mA] 448c2ecf20Sopenharmony_ci */ 458c2ecf20Sopenharmony_ci#define DW9768_MSB_ADDR 0x03 468c2ecf20Sopenharmony_ci#define DW9768_LSB_ADDR 0x04 478c2ecf20Sopenharmony_ci#define DW9768_STATUS_ADDR 0x05 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * AAC mode control & prescale register 518c2ecf20Sopenharmony_ci * Bit[7:5] Namely AC[2:0], decide the VCM mode and operation time. 528c2ecf20Sopenharmony_ci * 001 AAC2 0.48 x Tvib 538c2ecf20Sopenharmony_ci * 010 AAC3 0.70 x Tvib 548c2ecf20Sopenharmony_ci * 011 AAC4 0.75 x Tvib 558c2ecf20Sopenharmony_ci * 101 AAC8 1.13 x Tvib 568c2ecf20Sopenharmony_ci * Bit[2:0] Namely PRESC[2:0], set the internal clock dividing rate as follow. 578c2ecf20Sopenharmony_ci * 000 2 588c2ecf20Sopenharmony_ci * 001 1 598c2ecf20Sopenharmony_ci * 010 1/2 608c2ecf20Sopenharmony_ci * 011 1/4 618c2ecf20Sopenharmony_ci * 100 8 628c2ecf20Sopenharmony_ci * 101 4 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_ci#define DW9768_AAC_PRESC_REG 0x06 658c2ecf20Sopenharmony_ci#define DW9768_AAC_MODE_SEL_MASK GENMASK(7, 5) 668c2ecf20Sopenharmony_ci#define DW9768_CLOCK_PRE_SCALE_SEL_MASK GENMASK(2, 0) 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* 698c2ecf20Sopenharmony_ci * VCM period of vibration register 708c2ecf20Sopenharmony_ci * Bit[5:0] Defined as VCM rising periodic time (Tvib) together with PRESC[2:0] 718c2ecf20Sopenharmony_ci * Tvib = (6.3ms + AACT[5:0] * 0.1ms) * Dividing Rate 728c2ecf20Sopenharmony_ci * Dividing Rate is the internal clock dividing rate that is defined at 738c2ecf20Sopenharmony_ci * PRESCALE register (ADD: 0x06) 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_ci#define DW9768_AAC_TIME_REG 0x07 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci/* 788c2ecf20Sopenharmony_ci * DW9768 requires waiting time (delay time) of t_OPR after power-up, 798c2ecf20Sopenharmony_ci * or in the case of PD reset taking place. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci#define DW9768_T_OPR_US 1000 828c2ecf20Sopenharmony_ci#define DW9768_TVIB_MS_BASE10 (64 - 1) 838c2ecf20Sopenharmony_ci#define DW9768_AAC_MODE_DEFAULT 2 848c2ecf20Sopenharmony_ci#define DW9768_AAC_TIME_DEFAULT 0x20 858c2ecf20Sopenharmony_ci#define DW9768_CLOCK_PRE_SCALE_DEFAULT 1 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci/* 888c2ecf20Sopenharmony_ci * This acts as the minimum granularity of lens movement. 898c2ecf20Sopenharmony_ci * Keep this value power of 2, so the control steps can be 908c2ecf20Sopenharmony_ci * uniformly adjusted for gradual lens movement, with desired 918c2ecf20Sopenharmony_ci * number of control steps. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci#define DW9768_MOVE_STEPS 16 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_cistatic const char * const dw9768_supply_names[] = { 968c2ecf20Sopenharmony_ci "vin", /* Digital I/O power */ 978c2ecf20Sopenharmony_ci "vdd", /* Digital core power */ 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* dw9768 device structure */ 1018c2ecf20Sopenharmony_cistruct dw9768 { 1028c2ecf20Sopenharmony_ci struct regulator_bulk_data supplies[ARRAY_SIZE(dw9768_supply_names)]; 1038c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler ctrls; 1048c2ecf20Sopenharmony_ci struct v4l2_ctrl *focus; 1058c2ecf20Sopenharmony_ci struct v4l2_subdev sd; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci u32 aac_mode; 1088c2ecf20Sopenharmony_ci u32 aac_timing; 1098c2ecf20Sopenharmony_ci u32 clock_presc; 1108c2ecf20Sopenharmony_ci u32 move_delay_us; 1118c2ecf20Sopenharmony_ci}; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_cistatic inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci return container_of(subdev, struct dw9768, sd); 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistruct regval_list { 1198c2ecf20Sopenharmony_ci u8 reg_num; 1208c2ecf20Sopenharmony_ci u8 value; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistruct dw9768_aac_mode_ot_multi { 1248c2ecf20Sopenharmony_ci u32 aac_mode_enum; 1258c2ecf20Sopenharmony_ci u32 ot_multi_base100; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistruct dw9768_clk_presc_dividing_rate { 1298c2ecf20Sopenharmony_ci u32 clk_presc_enum; 1308c2ecf20Sopenharmony_ci u32 dividing_rate_base100; 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic const struct dw9768_aac_mode_ot_multi aac_mode_ot_multi[] = { 1348c2ecf20Sopenharmony_ci {1, 48}, 1358c2ecf20Sopenharmony_ci {2, 70}, 1368c2ecf20Sopenharmony_ci {3, 75}, 1378c2ecf20Sopenharmony_ci {5, 113}, 1388c2ecf20Sopenharmony_ci}; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_cistatic const struct dw9768_clk_presc_dividing_rate presc_dividing_rate[] = { 1418c2ecf20Sopenharmony_ci {0, 200}, 1428c2ecf20Sopenharmony_ci {1, 100}, 1438c2ecf20Sopenharmony_ci {2, 50}, 1448c2ecf20Sopenharmony_ci {3, 25}, 1458c2ecf20Sopenharmony_ci {4, 800}, 1468c2ecf20Sopenharmony_ci {5, 400}, 1478c2ecf20Sopenharmony_ci}; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic u32 dw9768_find_ot_multi(u32 aac_mode_param) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci u32 cur_ot_multi_base100 = 70; 1528c2ecf20Sopenharmony_ci unsigned int i; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(aac_mode_ot_multi); i++) { 1558c2ecf20Sopenharmony_ci if (aac_mode_ot_multi[i].aac_mode_enum == aac_mode_param) { 1568c2ecf20Sopenharmony_ci cur_ot_multi_base100 = 1578c2ecf20Sopenharmony_ci aac_mode_ot_multi[i].ot_multi_base100; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci return cur_ot_multi_base100; 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_cistatic u32 dw9768_find_dividing_rate(u32 presc_param) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci u32 cur_clk_dividing_rate_base100 = 100; 1678c2ecf20Sopenharmony_ci unsigned int i; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(presc_dividing_rate); i++) { 1708c2ecf20Sopenharmony_ci if (presc_dividing_rate[i].clk_presc_enum == presc_param) { 1718c2ecf20Sopenharmony_ci cur_clk_dividing_rate_base100 = 1728c2ecf20Sopenharmony_ci presc_dividing_rate[i].dividing_rate_base100; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return cur_clk_dividing_rate_base100; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci/* 1808c2ecf20Sopenharmony_ci * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time. 1818c2ecf20Sopenharmony_ci * For current VCM mode: AAC3, Operation Time would be 0.70 x Tvib. 1828c2ecf20Sopenharmony_ci * Tvib = (6.3ms + AACT[5:0] * 0.1MS) * Dividing Rate. 1838c2ecf20Sopenharmony_ci * Below is calculation of the operation delay for each step. 1848c2ecf20Sopenharmony_ci */ 1858c2ecf20Sopenharmony_cistatic inline u32 dw9768_cal_move_delay(u32 aac_mode_param, u32 presc_param, 1868c2ecf20Sopenharmony_ci u32 aac_timing_param) 1878c2ecf20Sopenharmony_ci{ 1888c2ecf20Sopenharmony_ci u32 Tvib_us; 1898c2ecf20Sopenharmony_ci u32 ot_multi_base100; 1908c2ecf20Sopenharmony_ci u32 clk_dividing_rate_base100; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci ot_multi_base100 = dw9768_find_ot_multi(aac_mode_param); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci clk_dividing_rate_base100 = dw9768_find_dividing_rate(presc_param); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci Tvib_us = (DW9768_TVIB_MS_BASE10 + aac_timing_param) * 1978c2ecf20Sopenharmony_ci clk_dividing_rate_base100; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return Tvib_us * ot_multi_base100 / 100; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic int dw9768_mod_reg(struct dw9768 *dw9768, u8 reg, u8 mask, u8 val) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); 2058c2ecf20Sopenharmony_ci int ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci ret = i2c_smbus_read_byte_data(client, reg); 2088c2ecf20Sopenharmony_ci if (ret < 0) 2098c2ecf20Sopenharmony_ci return ret; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci val = ((unsigned char)ret & ~mask) | (val & mask); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci return i2c_smbus_write_byte_data(client, reg, val); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int dw9768_set_dac(struct dw9768 *dw9768, u16 val) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* Write VCM position to registers */ 2218c2ecf20Sopenharmony_ci return i2c_smbus_write_word_swapped(client, DW9768_MSB_ADDR, val); 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_cistatic int dw9768_init(struct dw9768 *dw9768) 2258c2ecf20Sopenharmony_ci{ 2268c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); 2278c2ecf20Sopenharmony_ci int ret, val; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Reset DW9768_RING_PD_CONTROL_REG to default status 0x00 */ 2308c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, 2318c2ecf20Sopenharmony_ci DW9768_PD_MODE_OFF); 2328c2ecf20Sopenharmony_ci if (ret < 0) 2338c2ecf20Sopenharmony_ci return ret; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci /* 2368c2ecf20Sopenharmony_ci * DW9769 requires waiting delay time of t_OPR 2378c2ecf20Sopenharmony_ci * after PD reset takes place. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_ci usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* Set DW9768_RING_PD_CONTROL_REG to DW9768_AAC_MODE_EN(0x01) */ 2428c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, 2438c2ecf20Sopenharmony_ci DW9768_AAC_MODE_EN); 2448c2ecf20Sopenharmony_ci if (ret < 0) 2458c2ecf20Sopenharmony_ci return ret; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Set AAC mode */ 2488c2ecf20Sopenharmony_ci ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG, 2498c2ecf20Sopenharmony_ci DW9768_AAC_MODE_SEL_MASK, 2508c2ecf20Sopenharmony_ci dw9768->aac_mode << 5); 2518c2ecf20Sopenharmony_ci if (ret < 0) 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci /* Set clock presc */ 2558c2ecf20Sopenharmony_ci if (dw9768->clock_presc != DW9768_CLOCK_PRE_SCALE_DEFAULT) { 2568c2ecf20Sopenharmony_ci ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG, 2578c2ecf20Sopenharmony_ci DW9768_CLOCK_PRE_SCALE_SEL_MASK, 2588c2ecf20Sopenharmony_ci dw9768->clock_presc); 2598c2ecf20Sopenharmony_ci if (ret < 0) 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci /* Set AAC Timing */ 2648c2ecf20Sopenharmony_ci if (dw9768->aac_timing != DW9768_AAC_TIME_DEFAULT) { 2658c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, DW9768_AAC_TIME_REG, 2668c2ecf20Sopenharmony_ci dw9768->aac_timing); 2678c2ecf20Sopenharmony_ci if (ret < 0) 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci for (val = dw9768->focus->val % DW9768_MOVE_STEPS; 2728c2ecf20Sopenharmony_ci val <= dw9768->focus->val; 2738c2ecf20Sopenharmony_ci val += DW9768_MOVE_STEPS) { 2748c2ecf20Sopenharmony_ci ret = dw9768_set_dac(dw9768, val); 2758c2ecf20Sopenharmony_ci if (ret) { 2768c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C failure: %d", ret); 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci usleep_range(dw9768->move_delay_us, 2808c2ecf20Sopenharmony_ci dw9768->move_delay_us + 1000); 2818c2ecf20Sopenharmony_ci } 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic int dw9768_release(struct dw9768 *dw9768) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct i2c_client *client = v4l2_get_subdevdata(&dw9768->sd); 2898c2ecf20Sopenharmony_ci int ret, val; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci val = round_down(dw9768->focus->val, DW9768_MOVE_STEPS); 2928c2ecf20Sopenharmony_ci for ( ; val >= 0; val -= DW9768_MOVE_STEPS) { 2938c2ecf20Sopenharmony_ci ret = dw9768_set_dac(dw9768, val); 2948c2ecf20Sopenharmony_ci if (ret) { 2958c2ecf20Sopenharmony_ci dev_err(&client->dev, "I2C write fail: %d", ret); 2968c2ecf20Sopenharmony_ci return ret; 2978c2ecf20Sopenharmony_ci } 2988c2ecf20Sopenharmony_ci usleep_range(dw9768->move_delay_us, 2998c2ecf20Sopenharmony_ci dw9768->move_delay_us + 1000); 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG, 3038c2ecf20Sopenharmony_ci DW9768_PD_MODE_EN); 3048c2ecf20Sopenharmony_ci if (ret < 0) 3058c2ecf20Sopenharmony_ci return ret; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci /* 3088c2ecf20Sopenharmony_ci * DW9769 requires waiting delay time of t_OPR 3098c2ecf20Sopenharmony_ci * after PD reset takes place. 3108c2ecf20Sopenharmony_ci */ 3118c2ecf20Sopenharmony_ci usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic int dw9768_runtime_suspend(struct device *dev) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 3198c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 3208c2ecf20Sopenharmony_ci struct dw9768 *dw9768 = sd_to_dw9768(sd); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci dw9768_release(dw9768); 3238c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names), 3248c2ecf20Sopenharmony_ci dw9768->supplies); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic int dw9768_runtime_resume(struct device *dev) 3308c2ecf20Sopenharmony_ci{ 3318c2ecf20Sopenharmony_ci struct i2c_client *client = to_i2c_client(dev); 3328c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 3338c2ecf20Sopenharmony_ci struct dw9768 *dw9768 = sd_to_dw9768(sd); 3348c2ecf20Sopenharmony_ci int ret; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = regulator_bulk_enable(ARRAY_SIZE(dw9768_supply_names), 3378c2ecf20Sopenharmony_ci dw9768->supplies); 3388c2ecf20Sopenharmony_ci if (ret < 0) { 3398c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable regulators\n"); 3408c2ecf20Sopenharmony_ci return ret; 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * The datasheet refers to t_OPR that needs to be waited before sending 3458c2ecf20Sopenharmony_ci * I2C commands after power-up. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = dw9768_init(dw9768); 3508c2ecf20Sopenharmony_ci if (ret < 0) 3518c2ecf20Sopenharmony_ci goto disable_regulator; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return 0; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cidisable_regulator: 3568c2ecf20Sopenharmony_ci regulator_bulk_disable(ARRAY_SIZE(dw9768_supply_names), 3578c2ecf20Sopenharmony_ci dw9768->supplies); 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci return ret; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int dw9768_set_ctrl(struct v4l2_ctrl *ctrl) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct dw9768 *dw9768 = container_of(ctrl->handler, 3658c2ecf20Sopenharmony_ci struct dw9768, ctrls); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci if (ctrl->id == V4L2_CID_FOCUS_ABSOLUTE) 3688c2ecf20Sopenharmony_ci return dw9768_set_dac(dw9768, ctrl->val); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci return 0; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_cistatic const struct v4l2_ctrl_ops dw9768_ctrl_ops = { 3748c2ecf20Sopenharmony_ci .s_ctrl = dw9768_set_ctrl, 3758c2ecf20Sopenharmony_ci}; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_cistatic int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 3788c2ecf20Sopenharmony_ci{ 3798c2ecf20Sopenharmony_ci int ret; 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(sd->dev); 3828c2ecf20Sopenharmony_ci if (ret < 0) { 3838c2ecf20Sopenharmony_ci pm_runtime_put_noidle(sd->dev); 3848c2ecf20Sopenharmony_ci return ret; 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_cistatic int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci pm_runtime_put(sd->dev); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci return 0; 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_internal_ops dw9768_int_ops = { 3988c2ecf20Sopenharmony_ci .open = dw9768_open, 3998c2ecf20Sopenharmony_ci .close = dw9768_close, 4008c2ecf20Sopenharmony_ci}; 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic const struct v4l2_subdev_ops dw9768_ops = { }; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_cistatic int dw9768_init_controls(struct dw9768 *dw9768) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct v4l2_ctrl_handler *hdl = &dw9768->ctrls; 4078c2ecf20Sopenharmony_ci const struct v4l2_ctrl_ops *ops = &dw9768_ctrl_ops; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci v4l2_ctrl_handler_init(hdl, 1); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci dw9768->focus = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_FOCUS_ABSOLUTE, 0, 4128c2ecf20Sopenharmony_ci DW9768_MAX_FOCUS_POS, 4138c2ecf20Sopenharmony_ci DW9768_FOCUS_STEPS, 0); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci if (hdl->error) 4168c2ecf20Sopenharmony_ci return hdl->error; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci dw9768->sd.ctrl_handler = hdl; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci return 0; 4218c2ecf20Sopenharmony_ci} 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_cistatic int dw9768_probe(struct i2c_client *client) 4248c2ecf20Sopenharmony_ci{ 4258c2ecf20Sopenharmony_ci struct device *dev = &client->dev; 4268c2ecf20Sopenharmony_ci struct dw9768 *dw9768; 4278c2ecf20Sopenharmony_ci unsigned int i; 4288c2ecf20Sopenharmony_ci int ret; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci dw9768 = devm_kzalloc(dev, sizeof(*dw9768), GFP_KERNEL); 4318c2ecf20Sopenharmony_ci if (!dw9768) 4328c2ecf20Sopenharmony_ci return -ENOMEM; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Initialize subdev */ 4358c2ecf20Sopenharmony_ci v4l2_i2c_subdev_init(&dw9768->sd, client, &dw9768_ops); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci dw9768->aac_mode = DW9768_AAC_MODE_DEFAULT; 4388c2ecf20Sopenharmony_ci dw9768->aac_timing = DW9768_AAC_TIME_DEFAULT; 4398c2ecf20Sopenharmony_ci dw9768->clock_presc = DW9768_CLOCK_PRE_SCALE_DEFAULT; 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Optional indication of AAC mode select */ 4428c2ecf20Sopenharmony_ci fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-mode", 4438c2ecf20Sopenharmony_ci &dw9768->aac_mode); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* Optional indication of clock pre-scale select */ 4468c2ecf20Sopenharmony_ci fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,clock-presc", 4478c2ecf20Sopenharmony_ci &dw9768->clock_presc); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Optional indication of AAC Timing */ 4508c2ecf20Sopenharmony_ci fwnode_property_read_u32(dev_fwnode(dev), "dongwoon,aac-timing", 4518c2ecf20Sopenharmony_ci &dw9768->aac_timing); 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci dw9768->move_delay_us = dw9768_cal_move_delay(dw9768->aac_mode, 4548c2ecf20Sopenharmony_ci dw9768->clock_presc, 4558c2ecf20Sopenharmony_ci dw9768->aac_timing); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++) 4588c2ecf20Sopenharmony_ci dw9768->supplies[i].supply = dw9768_supply_names[i]; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names), 4618c2ecf20Sopenharmony_ci dw9768->supplies); 4628c2ecf20Sopenharmony_ci if (ret) { 4638c2ecf20Sopenharmony_ci dev_err(dev, "failed to get regulators\n"); 4648c2ecf20Sopenharmony_ci return ret; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Initialize controls */ 4688c2ecf20Sopenharmony_ci ret = dw9768_init_controls(dw9768); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci goto err_free_handler; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci /* Initialize subdev */ 4738c2ecf20Sopenharmony_ci dw9768->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 4748c2ecf20Sopenharmony_ci dw9768->sd.internal_ops = &dw9768_int_ops; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL); 4778c2ecf20Sopenharmony_ci if (ret < 0) 4788c2ecf20Sopenharmony_ci goto err_free_handler; 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci dw9768->sd.entity.function = MEDIA_ENT_F_LENS; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 4838c2ecf20Sopenharmony_ci if (!pm_runtime_enabled(dev)) { 4848c2ecf20Sopenharmony_ci ret = dw9768_runtime_resume(dev); 4858c2ecf20Sopenharmony_ci if (ret < 0) { 4868c2ecf20Sopenharmony_ci dev_err(dev, "failed to power on: %d\n", ret); 4878c2ecf20Sopenharmony_ci goto err_clean_entity; 4888c2ecf20Sopenharmony_ci } 4898c2ecf20Sopenharmony_ci } 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci ret = v4l2_async_register_subdev(&dw9768->sd); 4928c2ecf20Sopenharmony_ci if (ret < 0) { 4938c2ecf20Sopenharmony_ci dev_err(dev, "failed to register V4L2 subdev: %d", ret); 4948c2ecf20Sopenharmony_ci goto err_power_off; 4958c2ecf20Sopenharmony_ci } 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_cierr_power_off: 5008c2ecf20Sopenharmony_ci if (pm_runtime_enabled(dev)) 5018c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 5028c2ecf20Sopenharmony_ci else 5038c2ecf20Sopenharmony_ci dw9768_runtime_suspend(dev); 5048c2ecf20Sopenharmony_cierr_clean_entity: 5058c2ecf20Sopenharmony_ci media_entity_cleanup(&dw9768->sd.entity); 5068c2ecf20Sopenharmony_cierr_free_handler: 5078c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&dw9768->ctrls); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci return ret; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic int dw9768_remove(struct i2c_client *client) 5138c2ecf20Sopenharmony_ci{ 5148c2ecf20Sopenharmony_ci struct v4l2_subdev *sd = i2c_get_clientdata(client); 5158c2ecf20Sopenharmony_ci struct dw9768 *dw9768 = sd_to_dw9768(sd); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci v4l2_async_unregister_subdev(&dw9768->sd); 5188c2ecf20Sopenharmony_ci v4l2_ctrl_handler_free(&dw9768->ctrls); 5198c2ecf20Sopenharmony_ci media_entity_cleanup(&dw9768->sd.entity); 5208c2ecf20Sopenharmony_ci pm_runtime_disable(&client->dev); 5218c2ecf20Sopenharmony_ci if (!pm_runtime_status_suspended(&client->dev)) 5228c2ecf20Sopenharmony_ci dw9768_runtime_suspend(&client->dev); 5238c2ecf20Sopenharmony_ci pm_runtime_set_suspended(&client->dev); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic const struct of_device_id dw9768_of_table[] = { 5298c2ecf20Sopenharmony_ci { .compatible = "dongwoon,dw9768" }, 5308c2ecf20Sopenharmony_ci { .compatible = "giantec,gt9769" }, 5318c2ecf20Sopenharmony_ci {} 5328c2ecf20Sopenharmony_ci}; 5338c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, dw9768_of_table); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic const struct dev_pm_ops dw9768_pm_ops = { 5368c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 5378c2ecf20Sopenharmony_ci pm_runtime_force_resume) 5388c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(dw9768_runtime_suspend, dw9768_runtime_resume, NULL) 5398c2ecf20Sopenharmony_ci}; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic struct i2c_driver dw9768_i2c_driver = { 5428c2ecf20Sopenharmony_ci .driver = { 5438c2ecf20Sopenharmony_ci .name = DW9768_NAME, 5448c2ecf20Sopenharmony_ci .pm = &dw9768_pm_ops, 5458c2ecf20Sopenharmony_ci .of_match_table = dw9768_of_table, 5468c2ecf20Sopenharmony_ci }, 5478c2ecf20Sopenharmony_ci .probe_new = dw9768_probe, 5488c2ecf20Sopenharmony_ci .remove = dw9768_remove, 5498c2ecf20Sopenharmony_ci}; 5508c2ecf20Sopenharmony_cimodule_i2c_driver(dw9768_i2c_driver); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Dongchun Zhu <dongchun.zhu@mediatek.com>"); 5538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DW9768 VCM driver"); 5548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 555