// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2021 Sieć Badawcza Łukasiewicz * - Przemysłowy Instytut Automatyki i Pomiarów PIAP * Written by Krzysztof Hałasa
*/
/* Data must be BE16, the first value is the register address */ staticint ar0521_write_regs(struct ar0521_dev *sensor, const __be16 *data, unsignedint count)
{ struct i2c_client *client = sensor->i2c_client; struct i2c_msg msg; int ret;
staticint ar0521_set_gains(struct ar0521_dev *sensor)
{ int green = sensor->ctrls.gain->val; int red = max(green + sensor->ctrls.red_balance->val, 0); int blue = max(green + sensor->ctrls.blue_balance->val, 0); unsignedint gain = min(red, min(green, blue)); unsignedint analog = min(gain, 64u); /* range is 0 - 127 */
__be16 regs[5];
red = min(red - analog + 64, 511u);
green = min(green - analog + 64, 511u);
blue = min(blue - analog + 64, 511u);
regs[0] = be(AR0521_REG_GREEN1_GAIN);
regs[1] = be(green << 7 | analog);
regs[2] = be(blue << 7 | analog);
regs[3] = be(red << 7 | analog);
regs[4] = be(green << 7 | analog);
if (new_mult < 32) continue; /* Minimum value */ if (new_mult > 254) break; /* Maximum, larger pre won't work either */ if (sensor->extclk_freq * (u64)new_mult < (u64)AR0521_PLL_MIN *
new_pre) continue; if (sensor->extclk_freq * (u64)new_mult > (u64)AR0521_PLL_MAX *
new_pre) break; /* Larger pre won't work either */
new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult,
new_pre); if (new_pll < pll) {
pll = new_pll;
pre = new_pre;
mult = new_mult;
}
}
} else { /* * Reset gain, the sensor may produce all white pixels without * this
*/
ret = ar0521_write_reg(sensor, AR0521_REG_GLOBAL_GAIN, 0x2000); if (ret) return ret;
/* Stop streaming */
ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
AR0521_REG_RESET_DEFAULTS); if (ret) return ret;
/* * Update the exposure and blankings limits. Blankings are also reset * to the minimum.
*/
max_hblank = AR0521_TOTAL_WIDTH_MAX - sensor->fmt.width;
ret = __v4l2_ctrl_modify_range(sensor->ctrls.hblank,
sensor->ctrls.hblank->minimum,
max_hblank, sensor->ctrls.hblank->step,
sensor->ctrls.hblank->minimum); if (ret) goto unlock;
ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.hblank,
sensor->ctrls.hblank->minimum); if (ret) goto unlock;
max_vblank = AR0521_TOTAL_HEIGHT_MAX - sensor->fmt.height;
ret = __v4l2_ctrl_modify_range(sensor->ctrls.vblank,
sensor->ctrls.vblank->minimum,
max_vblank, sensor->ctrls.vblank->step,
sensor->ctrls.vblank->minimum); if (ret) goto unlock;
ret = __v4l2_ctrl_s_ctrl(sensor->ctrls.vblank,
sensor->ctrls.vblank->minimum); if (ret) goto unlock;
/* access the sensor only if it's powered up */ if (!pm_runtime_get_if_in_use(&sensor->i2c_client->dev)) return 0;
switch (ctrl->id) { case V4L2_CID_HBLANK: case V4L2_CID_VBLANK:
ret = ar0521_set_geometry(sensor); break; case V4L2_CID_ANALOGUE_GAIN:
ret = ar0521_write_reg(sensor, AR0521_REG_ANA_GAIN_CODE_GLOBAL,
ctrl->val); break; case V4L2_CID_GAIN: case V4L2_CID_RED_BALANCE: case V4L2_CID_BLUE_BALANCE:
ret = ar0521_set_gains(sensor); break; case V4L2_CID_EXPOSURE:
ret = ar0521_write_reg(sensor,
AR0521_REG_COARSE_INTEGRATION_TIME,
ctrl->val); break; case V4L2_CID_TEST_PATTERN:
ret = ar0521_write_reg(sensor, AR0521_REG_TEST_PATTERN_MODE,
ctrl->val); break; default:
dev_err(&sensor->i2c_client->dev, "Unsupported control %x\n", ctrl->id);
ret = -EINVAL; break;
}
REGS(be(0x30D2),
be(0x0000), /* 30D2: CRM/CC: enable crm on Visible and CC rows */
be(0x0000), /* 30D4: CC: CC enabled with 16 samples per column */ /* 30D6: CC: bw mode enabled/12 bit data resolution/bw mode */
be(0x2FFF)),
REGS(be(0x3EC0),
be(0x1E00), /* 3EC0: SFbin/SH mode settings */
be(0x100A), /* 3EC2: CLK divider for ramp for 10 bit 400MH */ /* 3EC4: FSC clamps for HDR mode and adc comp power down co */
be(0x3300),
be(0xEA44), /* 3EC6: VLN and clk gating controls */
be(0x6F6F), /* 3EC8: Txl0 and Txlo1 settings for normal mode */
be(0x2F4A), /* 3ECA: CDAC/Txlo2/RSTGHI/RSTGLO settings */
be(0x0506), /* 3ECC: RSTDHI/RSTDLO/CDAC/TXHI settings */ /* 3ECE: Ramp buffer settings and Booster enable (bits 0-5) */
be(0x203B),
be(0x13F0), /* 3ED0: TXLO from atest/sf bin settings */
be(0xA53D), /* 3ED2: Ramp offset */
be(0x862F), /* 3ED4: TXLO open loop/row driver settings */
be(0x4081), /* 3ED6: Txlatch fr cfpn rows/vln bias */
be(0x8003), /* 3ED8: Ramp step setting for 10 bit 400 Mhz */
be(0xA580), /* 3EDA: Ramp Offset */
be(0xC000), /* 3EDC: over range for rst and under range for sig */
be(0xC103)), /* 3EDE: over range for sig and col dec clk settings */
/* corrections_recommended_bayer */
REGS(be(0x3F00),
be(0x0017), /* 3F00: BM_T0 */
be(0x02DD), /* 3F02: BM_T1 */ /* 3F04: if Ana_gain less than 2, use noise_floor0, multiply */
be(0x0020), /* 3F06: if Ana_gain between 4 and 7, use noise_floor2 and */
be(0x0040), /* 3F08: if Ana_gain between 4 and 7, use noise_floor2 and */
be(0x0070), /* 3F0A: Define noise_floor0(low address) and noise_floor1 */
be(0x0101),
be(0x0302)), /* 3F0C: Define noise_floor2 and noise_floor3 */
REGS(be(0x3F10),
be(0x0505), /* 3F10: single k factor 0 */
be(0x0505), /* 3F12: single k factor 1 */
be(0x0505), /* 3F14: single k factor 2 */
be(0x01FF), /* 3F16: cross factor 0 */
be(0x01FF), /* 3F18: cross factor 1 */
be(0x01FF), /* 3F1A: cross factor 2 */
be(0x0022)), /* 3F1E */
/* GTH_THRES_RTN: 4max,4min filtered out of every 46 samples and */
REGS(be(0x3F2C), be(0x442E)),
REGS(be(0x3F3E),
be(0x0000), /* 3F3E: Switch ADC from 12 bit to 10 bit mode */
be(0x1511), /* 3F40: couple k factor 0 */
be(0x1511), /* 3F42: couple k factor 1 */
be(0x0707)), /* 3F44: couple k factor 2 */
};
for (cnt = 0; cnt < ARRAY_SIZE(ar0521_supply_names); cnt++) if (sensor->supplies[cnt]) {
ret = regulator_enable(sensor->supplies[cnt]); if (ret < 0) goto off;
usleep_range(1000, 1500); /* min 1 ms */
}
ret = clk_prepare_enable(sensor->extclk); if (ret < 0) {
v4l2_err(&sensor->sd, "error enabling sensor clock\n"); goto off;
}
usleep_range(1000, 1500); /* min 1 ms */
if (sensor->reset_gpio) /* deassert RESET signal */
gpiod_set_value_cansleep(sensor->reset_gpio, 0);
usleep_range(4500, 5000); /* min 45000 clocks */
for (cnt = 0; cnt < ARRAY_SIZE(initial_regs); cnt++) {
ret = ar0521_write_regs(sensor, initial_regs[cnt].data,
initial_regs[cnt].count); if (ret) goto off;
}
ret = ar0521_write_reg(sensor, AR0521_REG_SERIAL_FORMAT,
AR0521_REG_SERIAL_FORMAT_MIPI |
sensor->lane_count); if (ret) goto off;
/* set MIPI test mode - disabled for now */
ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_TEST_MODE,
((0x40 << sensor->lane_count) - 0x40) |
AR0521_REG_HISPI_TEST_MODE_LP11); if (ret) goto off;
ret = ar0521_write_reg(sensor, AR0521_REG_ROW_SPEED, 0x110 |
4 / sensor->lane_count); if (ret) goto off;
if (!(flags & V4L2_SUBDEV_PRE_STREAMON_FL_MANUAL_LP)) return -EACCES;
ret = pm_runtime_resume_and_get(&sensor->i2c_client->dev); if (ret < 0) return ret;
/* Set LP-11 on clock and data lanes */
ret = ar0521_write_reg(sensor, AR0521_REG_HISPI_CONTROL_STATUS,
AR0521_REG_HISPI_CONTROL_STATUS_FRAMER_TEST_MODE_ENABLE); if (ret) goto err;
/* Start streaming LP-11 */
ret = ar0521_write_reg(sensor, AR0521_REG_RESET,
AR0521_REG_RESET_DEFAULTS |
AR0521_REG_RESET_STREAM); if (ret) goto err; return 0;
endpoint = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
FWNODE_GRAPH_ENDPOINT_NEXT); if (!endpoint) {
dev_err(dev, "endpoint node not found\n"); return -EINVAL;
}
ret = v4l2_fwnode_endpoint_parse(endpoint, &ep);
fwnode_handle_put(endpoint); if (ret) {
dev_err(dev, "could not parse endpoint\n"); return ret;
}
if (ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
dev_err(dev, "invalid bus type, must be MIPI CSI2\n"); return -EINVAL;
}
sensor->lane_count = ep.bus.mipi_csi2.num_data_lanes; switch (sensor->lane_count) { case 1: case 2: case 4: break; default:
dev_err(dev, "invalid number of MIPI data lanes\n"); return -EINVAL;
}
/* Get master clock (extclk) */
sensor->extclk = devm_clk_get(dev, "extclk"); if (IS_ERR(sensor->extclk)) {
dev_err(dev, "failed to get extclk\n"); return PTR_ERR(sensor->extclk);
}
if (IS_ERR(supply)) {
dev_info(dev, "no %s regulator found: %li\n",
ar0521_supply_names[cnt], PTR_ERR(supply)); return PTR_ERR(supply);
}
sensor->supplies[cnt] = supply;
}
mutex_init(&sensor->lock);
ret = ar0521_init_controls(sensor); if (ret) goto entity_cleanup;
ar0521_adj_fmt(&sensor->fmt);
ret = v4l2_async_register_subdev(&sensor->sd); if (ret) goto free_ctrls;
/* Turn on the device and enable runtime PM */
ret = ar0521_power_on(&client->dev); if (ret) goto disable;
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev); return 0;
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.