kernel-brax3-ubuntu-touch/drivers/misc/mediatek/imgsensor/src-v4l2/adaptor-hw.c
erascape f319b992b1 kernel-5.15: Initial import brax3 UT kernel
* halium configs enabled

Signed-off-by: erascape <erascape@proton.me>
2025-09-23 15:17:10 +00:00

609 lines
14 KiB
C

// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2019 MediaTek Inc.
//#define DEBUG
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/clk.h>
#include <linux/gpio/consumer.h>
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include "kd_imgsensor_define_v4l2.h"
#include "adaptor.h"
#include "adaptor-hw.h"
#include <linux/clk-provider.h>
#define INST_OPS(__ctx, __field, __idx, __hw_id, __set, __unset) do {\
if (__ctx->__field[__idx]) { \
__ctx->hw_ops[__hw_id].set = __set; \
__ctx->hw_ops[__hw_id].unset = __unset; \
__ctx->hw_ops[__hw_id].data = (void *)__idx; \
} \
} while (0)
static const char * const clk_names[] = {
ADAPTOR_CLK_NAMES
};
static const char * const reg_names[] = {
ADAPTOR_REGULATOR_NAMES
};
static const char * const state_names[] = {
ADAPTOR_STATE_NAMES
};
static struct clk *get_clk_by_idx_freq(struct adaptor_ctx *ctx,
unsigned long long idx, int freq)
{
if (idx == CLK_MCLK) {
switch (freq) {
case 6:
return ctx->clk[CLK_6M];
case 12:
return ctx->clk[CLK_12M];
case 13:
return ctx->clk[CLK_13M];
case 19:
return ctx->clk[CLK_19_2M];
case 24:
return ctx->clk[CLK_24M];
case 26:
return ctx->clk[CLK_26M];
case 52:
return ctx->clk[CLK_52M];
}
} else if (idx == CLK1_MCLK1) {
switch (freq) {
case 6:
return ctx->clk[CLK1_6M];
case 12:
return ctx->clk[CLK1_12M];
case 13:
return ctx->clk[CLK1_13M];
case 19:
return ctx->clk[CLK1_19_2M];
case 24:
return ctx->clk[CLK1_24M];
case 26:
if (ctx->aov_mclk_ulposc_flag)
return ctx->clk[CLK1_26M_ULPOSC];
else
return ctx->clk[CLK1_26M];
case 52:
return ctx->clk[CLK1_52M];
}
}
return NULL;
}
static int set_mclk(struct adaptor_ctx *ctx, void *data, int val)
{
int ret;
struct clk *mclk, *mclk_src;
unsigned long long idx;
idx = (unsigned long long)data;
mclk = ctx->clk[idx];
mclk_src = get_clk_by_idx_freq(ctx, idx, val);
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+ idx(%llu),val(%d)\n", __func__, idx, val);
#endif
ret = clk_prepare_enable(mclk);
if (ret) {
dev_info(ctx->dev,
"clk_prepare_enable(%s),ret(%d)(fail)\n",
clk_names[idx], ret);
return ret;
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"clk_prepare_enable(%s),ret(%d)(correct)\n",
clk_names[idx], ret);
#endif
ret = clk_set_parent(mclk, mclk_src);
if (ret) {
dev_info(ctx->dev,
"mclk(%s) clk_set_parent (%s),ret(%d)(fail)\n",
__clk_get_name(mclk), __clk_get_name(mclk_src), ret);
return ret;
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"[%s]- clk_set_parent(%s),ret(%d)(correct)\n",
__func__, __clk_get_name(mclk_src), ret);
#endif
return 0;
}
static int unset_mclk(struct adaptor_ctx *ctx, void *data, int val)
{
struct clk *mclk, *mclk_src;
unsigned long long idx;
idx = (unsigned long long)data;
mclk = ctx->clk[idx];
mclk_src = get_clk_by_idx_freq(ctx, idx, val);
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+ idx(%llu),val(%d)\n", __func__, idx, val);
#endif
clk_disable_unprepare(mclk);
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"[%s]- clk_disable_unprepare(%s)\n",
__func__, clk_names[idx]);
#endif
return 0;
}
static int set_reg(struct adaptor_ctx *ctx, void *data, int val)
{
unsigned long long ret, idx;
struct regulator *reg;
idx = (unsigned long long)data;
// re-get reg everytime due to pmic limitation
ctx->regulator[idx] = devm_regulator_get_optional(ctx->dev, reg_names[idx]);
if (IS_ERR(ctx->regulator[idx])) {
ctx->regulator[idx] = NULL;
dev_info(ctx->dev, "no reg %s\n", reg_names[idx]);
return -EINVAL;
}
reg = ctx->regulator[idx];
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+ idx(%llu),val(%d)\n", __func__, idx, val);
#endif
ret = regulator_set_voltage(reg, val, val);
if (ret) {
dev_info(ctx->dev,
"regulator_set_voltage(%s),val(%d),ret(%llu)(fail)\n",
reg_names[idx], val, ret);
}
#if IMGSENSOR_LOG_MORE
else
dev_info(ctx->dev,
"regulator_set_voltage(%s),val(%d),ret(%llu)(correct)\n",
reg_names[idx], val, ret);
#endif
ret = regulator_enable(reg);
if (ret) {
dev_info(ctx->dev,
"regulator_enable(%s),ret(%llu)(fail)\n",
reg_names[idx], ret);
return ret;
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"[%s]- regulator_enable(%s),ret(%llu)(correct)\n",
__func__, reg_names[idx], ret);
#endif
return 0;
}
static int unset_reg(struct adaptor_ctx *ctx, void *data, int val)
{
unsigned long long ret, idx;
struct regulator *reg;
idx = (unsigned long long)data;
reg = ctx->regulator[idx];
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+ idx(%llu),val(%d)\n", __func__, idx, val);
#endif
ret = regulator_disable(reg);
if (ret) {
dev_info(ctx->dev,
"disable(%s),ret(%llu)(fail)\n",
reg_names[idx], ret);
return ret;
}
// always put reg due to pmic limitation
devm_regulator_put(ctx->regulator[idx]);
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"[%s]- disable(%s),ret(%llu)(correct)\n",
__func__, reg_names[idx], ret);
#endif
return 0;
}
static int set_state(struct adaptor_ctx *ctx, void *data, int val)
{
unsigned long long idx, x;
int ret;
idx = (unsigned long long)data;
x = idx + val;
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+ idx(%llu),val(%d)\n", __func__, idx, val);
#endif
ret = pinctrl_select_state(ctx->pinctrl, ctx->state[x]);
if (ret < 0) {
dev_info(ctx->dev,
"select(%s),ret(%d)(fail)\n",
state_names[x], ret);
return ret;
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev,
"[%s]- select(%s),ret(%d)(correct)\n",
__func__, state_names[x], ret);
#endif
return 0;
}
static int unset_state(struct adaptor_ctx *ctx, void *data, int val)
{
return set_state(ctx, data, 0);
}
static int set_state_div2(struct adaptor_ctx *ctx, void *data, int val)
{
return set_state(ctx, data, val >> 1);
}
static int set_state_boolean(struct adaptor_ctx *ctx, void *data, int val)
{
return set_state(ctx, data, !!val);
}
static int set_state_mipi_switch(struct adaptor_ctx *ctx, void *data, int val)
{
return set_state(ctx, (void *)STATE_MIPI_SWITCH_ON, 0);
}
static int unset_state_mipi_switch(struct adaptor_ctx *ctx, void *data,
int val)
{
return set_state(ctx, (void *)STATE_MIPI_SWITCH_OFF, 0);
}
static int reinit_pinctrl(struct adaptor_ctx *ctx)
{
int i;
struct device *dev = ctx->dev;
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
/* pinctrl */
ctx->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(ctx->pinctrl)) {
dev_err(dev, "fail to get pinctrl\n");
return PTR_ERR(ctx->pinctrl);
}
/* pinctrl states */
for (i = 0; i < STATE_MAXCNT; i++) {
ctx->state[i] = pinctrl_lookup_state(
ctx->pinctrl, state_names[i]);
if (IS_ERR(ctx->state[i])) {
ctx->state[i] = NULL;
dev_info(dev, "no state %s\n", state_names[i]);
}
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return 0;
}
int do_hw_power_on(struct adaptor_ctx *ctx)
{
int i;
const struct subdrv_pw_seq_entry *ent;
struct adaptor_hw_ops *op;
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
if (ctx->sensor_ws) {
if (ctx->aov_pm_ops_flag == 0) {
ctx->aov_pm_ops_flag = 1;
__pm_stay_awake(ctx->sensor_ws);
}
}
#if IMGSENSOR_LOG_MORE
else
dev_info(ctx->dev, "__pm_stay_awake(fail)\n");
#endif
/* may be released for mipi switch */
if (!ctx->pinctrl)
reinit_pinctrl(ctx);
op = &ctx->hw_ops[HW_ID_MIPI_SWITCH];
if (op->set)
op->set(ctx, op->data, 0);
for (i = 0; i < ctx->subdrv->pw_seq_cnt; i++) {
if (ctx->ctx_pw_seq)
ent = &ctx->ctx_pw_seq[i]; // use ctx pw seq
else
ent = &ctx->subdrv->pw_seq[i];
op = &ctx->hw_ops[ent->id];
if (!op->set) {
dev_dbg(ctx->dev, "cannot set comp %d val %d\n",
ent->id, ent->val);
continue;
}
op->set(ctx, op->data, ent->val);
if (ent->delay)
mdelay(ent->delay);
}
if (ctx->subdrv->ops->power_on)
subdrv_call(ctx, power_on, NULL);
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return 0;
}
int adaptor_hw_power_on(struct adaptor_ctx *ctx)
{
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
#ifndef IMGSENSOR_USE_PM_FRAMEWORK
dev_dbg(ctx->dev, "%s power ref cnt = %d\n", __func__, ctx->power_refcnt);
ctx->power_refcnt++;
if (ctx->power_refcnt > 1) {
dev_dbg(ctx->dev, "%s already powered, cnt = %d\n", __func__, ctx->power_refcnt);
return 0;
}
#endif
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return do_hw_power_on(ctx);
}
int do_hw_power_off(struct adaptor_ctx *ctx)
{
int i;
const struct subdrv_pw_seq_entry *ent;
struct adaptor_hw_ops *op;
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
/* call subdrv close function before pwr off */
subdrv_call(ctx, close);
if (ctx->subdrv->ops->power_off)
subdrv_call(ctx, power_off, NULL);
for (i = ctx->subdrv->pw_seq_cnt - 1; i >= 0; i--) {
if (ctx->ctx_pw_seq)
ent = &ctx->ctx_pw_seq[i]; // use ctx pw seq
else
ent = &ctx->subdrv->pw_seq[i];
op = &ctx->hw_ops[ent->id];
if (!op->unset)
continue;
op->unset(ctx, op->data, ent->val);
//msleep(ent->delay);
}
op = &ctx->hw_ops[HW_ID_MIPI_SWITCH];
if (op->unset)
op->unset(ctx, op->data, 0);
/* the pins of mipi switch are shared. free it for another users */
if (ctx->state[STATE_MIPI_SWITCH_ON] ||
ctx->state[STATE_MIPI_SWITCH_OFF]) {
devm_pinctrl_put(ctx->pinctrl);
ctx->pinctrl = NULL;
}
if (ctx->sensor_ws) {
if (ctx->aov_pm_ops_flag == 1) {
ctx->aov_pm_ops_flag = 0;
__pm_relax(ctx->sensor_ws);
}
}
#if IMGSENSOR_LOG_MORE
else
dev_info(ctx->dev, "__pm_relax(fail)\n");
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return 0;
}
int adaptor_hw_power_off(struct adaptor_ctx *ctx)
{
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
#ifndef IMGSENSOR_USE_PM_FRAMEWORK
if (!ctx->power_refcnt) {
dev_dbg(ctx->dev, "%s power ref cnt = %d, skip due to not power on yet\n",
__func__, ctx->power_refcnt);
return 0;
}
dev_dbg(ctx->dev, "%s power ref cnt = %d\n", __func__, ctx->power_refcnt);
ctx->power_refcnt--;
if (ctx->power_refcnt > 0) {
dev_dbg(ctx->dev, "%s skip due to cnt = %d\n", __func__, ctx->power_refcnt);
return 0;
}
ctx->power_refcnt = 0;
ctx->is_sensor_inited = 0;
ctx->is_sensor_scenario_inited = 0;
ctx->is_streaming = 0;
#endif
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return do_hw_power_off(ctx);
}
int adaptor_hw_init(struct adaptor_ctx *ctx)
{
int i;
struct device *dev = ctx->dev;
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]+\n", __func__);
#endif
/* clocks */
for (i = 0; i < CLK_MAXCNT; i++) {
ctx->clk[i] = devm_clk_get(dev, clk_names[i]);
if (IS_ERR(ctx->clk[i])) {
ctx->clk[i] = NULL;
dev_dbg(dev, "no clk %s\n", clk_names[i]);
}
}
/* supplies */
for (i = 0; i < REGULATOR_MAXCNT; i++) {
ctx->regulator[i] = devm_regulator_get_optional(
dev, reg_names[i]);
if (IS_ERR(ctx->regulator[i])) {
ctx->regulator[i] = NULL;
dev_dbg(dev, "no reg %s\n", reg_names[i]);
}
}
/* pinctrl */
ctx->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(ctx->pinctrl)) {
dev_err(dev, "fail to get pinctrl\n");
return PTR_ERR(ctx->pinctrl);
}
/* pinctrl states */
for (i = 0; i < STATE_MAXCNT; i++) {
ctx->state[i] = pinctrl_lookup_state(
ctx->pinctrl, state_names[i]);
if (IS_ERR(ctx->state[i])) {
ctx->state[i] = NULL;
dev_dbg(dev, "no state %s\n", state_names[i]);
}
}
/* install operations */
INST_OPS(ctx, clk, CLK_MCLK, HW_ID_MCLK, set_mclk, unset_mclk);
INST_OPS(ctx, clk, CLK1_MCLK1, HW_ID_MCLK1, set_mclk, unset_mclk);
INST_OPS(ctx, regulator, REGULATOR_AVDD, HW_ID_AVDD,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_DVDD, HW_ID_DVDD,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_DOVDD, HW_ID_DOVDD,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_AFVDD, HW_ID_AFVDD,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_AFVDD1, HW_ID_AFVDD1,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_AVDD1, HW_ID_AVDD1,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_AVDD2, HW_ID_AVDD2,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_DVDD1, HW_ID_DVDD1,
set_reg, unset_reg);
INST_OPS(ctx, regulator, REGULATOR_RST, HW_ID_RST,
set_reg, unset_reg);
if (ctx->state[STATE_MIPI_SWITCH_ON])
ctx->hw_ops[HW_ID_MIPI_SWITCH].set = set_state_mipi_switch;
if (ctx->state[STATE_MIPI_SWITCH_OFF])
ctx->hw_ops[HW_ID_MIPI_SWITCH].unset = unset_state_mipi_switch;
INST_OPS(ctx, state, STATE_MCLK_OFF, HW_ID_MCLK_DRIVING_CURRENT,
set_state_div2, unset_state);
INST_OPS(ctx, state, STATE_MCLK1_OFF, HW_ID_MCLK1_DRIVING_CURRENT,
set_state_div2, unset_state);
INST_OPS(ctx, state, STATE_RST_LOW, HW_ID_RST,
set_state, unset_state);
INST_OPS(ctx, state, STATE_PDN_LOW, HW_ID_PDN,
set_state, unset_state);
INST_OPS(ctx, state, STATE_AVDD_OFF, HW_ID_AVDD,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_DVDD_OFF, HW_ID_DVDD,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_DOVDD_OFF, HW_ID_DOVDD,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_AFVDD_OFF, HW_ID_AFVDD,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_AFVDD1_OFF, HW_ID_AFVDD1,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_AVDD1_OFF, HW_ID_AVDD1,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_AVDD2_OFF, HW_ID_AVDD2,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_DVDD1_OFF, HW_ID_DVDD1,
set_state_boolean, unset_state);
INST_OPS(ctx, state, STATE_RST1_LOW, HW_ID_RST1,
set_state, unset_state);
INST_OPS(ctx, state, STATE_PONV_LOW, HW_ID_PONV,
set_state, unset_state);
INST_OPS(ctx, state, STATE_SCL_AP, HW_ID_SCL,
set_state, unset_state);
INST_OPS(ctx, state, STATE_SDA_AP, HW_ID_SDA,
set_state, unset_state);
INST_OPS(ctx, state, STATE_EINT, HW_ID_EINT,
set_state, unset_state);
/* the pins of mipi switch are shared. free it for another users */
if (ctx->state[STATE_MIPI_SWITCH_ON] ||
ctx->state[STATE_MIPI_SWITCH_OFF]) {
devm_pinctrl_put(ctx->pinctrl);
ctx->pinctrl = NULL;
}
#if IMGSENSOR_LOG_MORE
dev_info(ctx->dev, "[%s]-\n", __func__);
#endif
return 0;
}
int adaptor_hw_sensor_reset(struct adaptor_ctx *ctx)
{
dev_info(ctx->dev, "%s %d|%d|%d\n",
__func__,
ctx->is_streaming,
ctx->is_sensor_inited,
ctx->power_refcnt);
if (ctx->is_streaming == 1 &&
ctx->is_sensor_inited == 1 &&
ctx->power_refcnt > 0) {
do_hw_power_off(ctx);
do_hw_power_on(ctx);
return 0;
}
dev_info(ctx->dev, "%s skip to reset due to either integration or else\n",
__func__);
return -1;
}