#define DW9768_NAME "dw9768" #define DW9768_MAX_FOCUS_POS (1024 - 1) /* * This sets the minimum granularity for the focus positions. * A value of 1 gives maximum accuracy for a desired focus position
*/ #define DW9768_FOCUS_STEPS 1
/* * Ring control and Power control register * Bit[1] RING_EN * 0: Direct mode * 1: AAC mode (ringing control mode) * Bit[0] PD * 0: Normal operation mode * 1: Power down mode * DW9768 requires waiting time of Topr after PD reset takes place.
*/ #define DW9768_RING_PD_CONTROL_REG 0x02 #define DW9768_PD_MODE_OFF 0x00 #define DW9768_PD_MODE_EN BIT(0) #define DW9768_AAC_MODE_EN BIT(1)
/* * DW9768 separates two registers to control the VCM position. * One for MSB value, another is LSB value. * DAC_MSB: D[9:8] (ADD: 0x03) * DAC_LSB: D[7:0] (ADD: 0x04) * D[9:0] DAC data input: positive output current = D[9:0] / 1023 * 100[mA]
*/ #define DW9768_MSB_ADDR 0x03 #define DW9768_LSB_ADDR 0x04 #define DW9768_STATUS_ADDR 0x05
/* * AAC mode control & prescale register * Bit[7:5] Namely AC[2:0], decide the VCM mode and operation time. * 001 AAC2 0.48 x Tvib * 010 AAC3 0.70 x Tvib * 011 AAC4 0.75 x Tvib * 101 AAC8 1.13 x Tvib * Bit[2:0] Namely PRESC[2:0], set the internal clock dividing rate as follow. * 000 2 * 001 1 * 010 1/2 * 011 1/4 * 100 8 * 101 4
*/ #define DW9768_AAC_PRESC_REG 0x06 #define DW9768_AAC_MODE_SEL_MASK GENMASK(7, 5) #define DW9768_CLOCK_PRE_SCALE_SEL_MASK GENMASK(2, 0)
/* * VCM period of vibration register * Bit[5:0] Defined as VCM rising periodic time (Tvib) together with PRESC[2:0] * Tvib = (6.3ms + AACT[5:0] * 0.1ms) * Dividing Rate * Dividing Rate is the internal clock dividing rate that is defined at * PRESCALE register (ADD: 0x06)
*/ #define DW9768_AAC_TIME_REG 0x07
/* * DW9768 requires waiting time (delay time) of t_OPR after power-up, * or in the case of PD reset taking place.
*/ #define DW9768_T_OPR_US 1000 #define DW9768_TVIB_MS_BASE10 (64 - 1) #define DW9768_AAC_MODE_DEFAULT 2 #define DW9768_AAC_TIME_DEFAULT 0x20 #define DW9768_CLOCK_PRE_SCALE_DEFAULT 1
/* * This acts as the minimum granularity of lens movement. * Keep this value power of 2, so the control steps can be * uniformly adjusted for gradual lens movement, with desired * number of control steps.
*/ #define DW9768_MOVE_STEPS 16
staticconstchar * const dw9768_supply_names[] = { "vin", /* Digital I/O power */ "vdd", /* Digital core power */
};
for (i = 0; i < ARRAY_SIZE(aac_mode_ot_multi); i++) { if (aac_mode_ot_multi[i].aac_mode_enum == aac_mode_param) {
cur_ot_multi_base100 =
aac_mode_ot_multi[i].ot_multi_base100;
}
}
for (i = 0; i < ARRAY_SIZE(presc_dividing_rate); i++) { if (presc_dividing_rate[i].clk_presc_enum == presc_param) {
cur_clk_dividing_rate_base100 =
presc_dividing_rate[i].dividing_rate_base100;
}
}
return cur_clk_dividing_rate_base100;
}
/* * DW9768_AAC_PRESC_REG & DW9768_AAC_TIME_REG determine VCM operation time. * For current VCM mode: AAC3, Operation Time would be 0.70 x Tvib. * Tvib = (6.3ms + AACT[5:0] * 0.1MS) * Dividing Rate. * Below is calculation of the operation delay for each step.
*/ staticinline u32 dw9768_cal_move_delay(u32 aac_mode_param, u32 presc_param,
u32 aac_timing_param)
{
u32 Tvib_us;
u32 ot_multi_base100;
u32 clk_dividing_rate_base100;
/* Reset DW9768_RING_PD_CONTROL_REG to default status 0x00 */
ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG,
DW9768_PD_MODE_OFF); if (ret < 0) return ret;
/* * DW9769 requires waiting delay time of t_OPR * after PD reset takes place.
*/
usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100);
/* Set DW9768_RING_PD_CONTROL_REG to DW9768_AAC_MODE_EN(0x01) */
ret = i2c_smbus_write_byte_data(client, DW9768_RING_PD_CONTROL_REG,
DW9768_AAC_MODE_EN); if (ret < 0) return ret;
/* Set AAC mode */
ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG,
DW9768_AAC_MODE_SEL_MASK,
dw9768->aac_mode << 5); if (ret < 0) return ret;
/* Set clock presc */ if (dw9768->clock_presc != DW9768_CLOCK_PRE_SCALE_DEFAULT) {
ret = dw9768_mod_reg(dw9768, DW9768_AAC_PRESC_REG,
DW9768_CLOCK_PRE_SCALE_SEL_MASK,
dw9768->clock_presc); if (ret < 0) return ret;
}
/* Set AAC Timing */ if (dw9768->aac_timing != DW9768_AAC_TIME_DEFAULT) {
ret = i2c_smbus_write_byte_data(client, DW9768_AAC_TIME_REG,
dw9768->aac_timing); if (ret < 0) return ret;
}
for (val = dw9768->focus->val % DW9768_MOVE_STEPS;
val <= dw9768->focus->val;
val += DW9768_MOVE_STEPS) {
ret = dw9768_set_dac(dw9768, val); if (ret) {
dev_err(&client->dev, "I2C failure: %d", ret); return ret;
}
usleep_range(dw9768->move_delay_us,
dw9768->move_delay_us + 1000);
}
ret = regulator_bulk_enable(ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies); if (ret < 0) {
dev_err(dev, "failed to enable regulators\n"); return ret;
}
/* * The datasheet refers to t_OPR that needs to be waited before sending * I2C commands after power-up.
*/
usleep_range(DW9768_T_OPR_US, DW9768_T_OPR_US + 100);
ret = dw9768_init(dw9768); if (ret < 0) goto disable_regulator;
for (i = 0; i < ARRAY_SIZE(dw9768_supply_names); i++)
dw9768->supplies[i].supply = dw9768_supply_names[i];
ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(dw9768_supply_names),
dw9768->supplies); if (ret) {
dev_err(dev, "failed to get regulators\n"); return ret;
}
/* Initialize controls */
ret = dw9768_init_controls(dw9768); if (ret) goto err_free_handler;
ret = media_entity_pads_init(&dw9768->sd.entity, 0, NULL); if (ret < 0) goto err_free_handler;
dw9768->sd.entity.function = MEDIA_ENT_F_LENS;
/* * Figure out whether we're going to power up the device here. Generally * this is done if CONFIG_PM is disabled in a DT system or the device is * to be powered on in an ACPI system. Similarly for power off in * remove.
*/
full_power = (is_acpi_node(dev_fwnode(dev)) &&
acpi_dev_state_d0(dev)) ||
(is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM)); if (full_power) {
ret = dw9768_runtime_resume(dev); if (ret < 0) {
dev_err(dev, "failed to power on: %d\n", ret); goto err_clean_entity;
}
pm_runtime_set_active(dev);
}
pm_runtime_enable(dev);
ret = v4l2_async_register_subdev(&dw9768->sd); if (ret < 0) {
dev_err(dev, "failed to register V4L2 subdev: %d", ret); goto err_power_off;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.