<html><body><p>
<pre>
On Mon, 2025-07-07 at 09:31 +0800, shangyao lin wrote:
> From: "shangyao.lin" <shangyao.lin@mediatek.com>
>
> Introduce support for the MediaTek sensor interface (seninf) in the SoC camera
> subsystem, focusing on CSI and stream control. The driver manages parameter
> control, metering, status tracking, and interrupt handling for the camera sensor
> interface hardware. It integrates with the MediaTek ISP CAMSYS, bridging camera
> sensors and the ISP system, and provides V4L2 framework support for dynamic
> stream configuration and virtual channel management.
>
> ---

[snip]

> .../isp_7x/camsys/kd_imgsensor_define_v4l2.h | 86 +
> .../isp/isp_7x/camsys/mtk_cam-seninf-def.h | 237 ++
> .../isp/isp_7x/camsys/mtk_cam-seninf-drv.c | 1441 ++++++++++++
> .../isp/isp_7x/camsys/mtk_cam-seninf-drv.h | 16 +
> .../isp/isp_7x/camsys/mtk_cam-seninf-hw.h | 108 +
> .../isp/isp_7x/camsys/mtk_cam-seninf-if.h | 24 +
> .../isp/isp_7x/camsys/mtk_cam-seninf-regs.h | 44 +
> .../isp/isp_7x/camsys/mtk_cam-seninf-route.c | 279 +++
> .../isp/isp_7x/camsys/mtk_cam-seninf-route.h | 20 +
> .../isp/isp_7x/camsys/mtk_cam-seninf.h | 161 ++

Add Makefile to build mtk-cam-seninfo-xxx.c in this patch.
Make this patch could be built.

> .../isp_7x/camsys/mtk_csi_phy_2_0/Makefile | 5 +
> .../mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h | 679 ++++++
> .../mtk_cam-seninf-csi0-cphy.h | 51 +
> .../mtk_cam-seninf-csi0-dphy.h | 98 +
> .../mtk_cam-seninf-hw_phy_2_0.c | 1932 +++++++++++++++++
> .../mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h | 165 ++
> .../mtk_cam-seninf-seninf1-csi2.h | 264 +++
> .../mtk_cam-seninf-seninf1-mux.h | 120 +
> .../mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h | 46 +
> .../mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h | 43 +
> .../mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h | 76 +
> 21 files changed, 5895 insertions(+)
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h
> create mode 100755 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h
>
> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
> new file mode 100755
> index 000000000000..54c23afe64bd
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (c) 2019 MediaTek Inc.
> + */
> +
> +#ifndef _KD_IMGSENSOR_DATA_V4L2_H
> +#define _KD_IMGSENSOR_DATA_V4L2_H
> +
> +enum VC_FEATURE {

Because mtk_cam_seninf_get_vc_feature() is useless, so VC_FEATURE is useless.
Drop these.

> +VC_NONE = 0,
> +VC_MIN_NUM,
> +VC_RAW_DATA = VC_MIN_NUM,
> +VC_RAW_DATA_MAX,
> +
> +VC_PDAF_MIN_NUM = VC_RAW_DATA_MAX,
> +VC_PDAF_STATS = VC_PDAF_MIN_NUM,
> +VC_PDAF_STATS_NE,
> +VC_PDAF_STATS_ME,
> +VC_PDAF_STATS_SE,
> +VC_PDAF_STATS_PIX_1,
> +VC_PDAF_STATS_PIX_2,
> +VC_PDAF_STATS_NE_PIX_1 = VC_PDAF_STATS_PIX_1,
> +VC_PDAF_STATS_NE_PIX_2 = VC_PDAF_STATS_PIX_2,
> +VC_PDAF_STATS_ME_PIX_1,
> +VC_PDAF_STATS_ME_PIX_2,
> +VC_PDAF_STATS_SE_PIX_2,
> +VC_PDAF_MAX_NUM,
> +
> +VC_HDR_MIN_NUM = VC_PDAF_MAX_NUM,
> +VC_HDR_MVHDR = VC_HDR_MIN_NUM,
> +VC_HDR_MAX_NUM,
> +
> +VC_3HDR_MIN_NUM = VC_HDR_MAX_NUM,
> +VC_3HDR_EMBEDDED = VC_3HDR_MIN_NUM,
> +VC_3HDR_FLICKER,
> +VC_3HDR_Y,
> +VC_3HDR_AE,
> +VC_3HDR_MAX_NUM,
> +
> +VC_STAGGER_MIN_NUM = VC_3HDR_MAX_NUM,
> +VC_STAGGER_EMBEDDED = VC_STAGGER_MIN_NUM,
> +VC_STAGGER_NE,
> +VC_STAGGER_ME,
> +VC_STAGGER_SE,
> +VC_STAGGER_MAX_NUM,
> +
> +VC_YUV_MIN_NUM = VC_STAGGER_MAX_NUM,
> +VC_YUV_Y = VC_YUV_MIN_NUM,
> +VC_YUV_UV,
> +VC_YUV_MAX_NUM,
> +
> +VC_RAW_EXT_MIN_NUM = VC_YUV_MAX_NUM,
> +VC_RAW_W_DATA = VC_RAW_EXT_MIN_NUM,
> +VC_RAW_PROCESSED_DATA,
> +VC_RAW_EXT_MAX_NUM,
> +
> +VC_GENERAL_DATA_MIN_NUM = VC_RAW_EXT_MAX_NUM,
> +VC_GENERAL_EMBEDDED = VC_GENERAL_DATA_MIN_NUM,
> +VC_GENERAL_DATA_MAX_NUM,
> +
> +VC_MAX_NUM = VC_GENERAL_DATA_MAX_NUM,
> +};
> +

[snip]

> +
> +#endif /* _KD_IMGSENSOR_DATA_H */
> diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
> new file mode 100755
> index 000000000000..39f6005c8227
> --- /dev/null
> +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h
> @@ -0,0 +1,237 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +// Copyright (c) 2022 MediaTek Inc.
> +
> +#ifndef __MTK_CAM_SENINF_DEF_H__
> +#define __MTK_CAM_SENINF_DEF_H__
> +
> +#include <linux/bitfield.h>
> +
> +#define SENINF_VC_MAXCNT 8
> +#define SENINF_DEF_PIXEL_MODE 2
> +
> +#define SENINF_CLK_MARGIN_IN_PERCENT 0
> +#define HW_BUF_EFFECT 10
> +
> +#define SENINF_HS_TRAIL_EN_CONDITION 1450000000

SENINF_HS_TRAIL_EN_CONDITION is useless. Drop it.

> +#define SENINF_TIMESTAMP_CLK 1000

SENINF_TIMESTAMP_CLK is useless. Drop it.

> +#define ISP_CLK_LOW 273000000
> +
> +#define SENINF_CPHY_SETTLE_DELAY_DT 0x10
> +#define SENINF_DPHY_SETTLE_DELAY_DT 0x10
> +#define SENINF_SETTLE_DELAY_CK 0x11
> +#define SENINF_HS_TRAIL_PARAMETER 0x34
> +
> +#define SENSOR_CLOCK_POLARITY_HIGH0

SENSOR_CLOCK_POLARITY_HIGH is useless. Drop it.

> +#define SENSOR_CLOCK_POLARITY_LOW1

SENSOR_CLOCK_POLARITY_LOW is useless. Drop it.

> +#define NUM_PORTS2

NUM_PORTS is useless. Drop it.

> +#define DEFAULT_WIDTH1600
> +#define DEFAULT_HEIGHT1200
> +#define CSI_PORT_A_MASK GENMASK(3, 1)
> +#define SENINF_MAX_STREAM 7
> +

[snip]

> +
> +enum SENINF_PHY_VER_ENUM {
> +SENINF_PHY_2_0,
> +SENINF_PHY_VER_NUM,
> +};

SENINF_PHY_VER_ENUM, SENINF_PHY_2_0 and SENINF_PHY_VER_NUM are useless.
Drop them.

> +
> +#define MTK_CSI_PHY_VERSIONS "mtk_csi_phy_2_0"
> +

[snip]

> +
> +static const char * const csi_port_names[] = {
> +SENINF_CSI_PORT_NAMES

Drop SENINF_CSI_PORT_NAMES and place string here.

> +};
> +
> +static const char * const clk_names[] = {
> +SENINF_CLK_NAMES

Drop SENINF_CLK_NAMES and place string here.

> +};
> +
> +static const char * const set_reg_names[] = {
> +SET_REG_KEYS_NAMES

Drop SET_REG_KEYS_NAMES and place string here.

> +};
> +
> +enum REG_OPS_CMD {
> +REG_OPS_CMD_ID,
> +REG_OPS_CMD_CSI,
> +REG_OPS_CMD_RG,
> +REG_OPS_CMD_VAL,
> +REG_OPS_CMD_MAX_NUM,
> +};

REG_OPS_CMD_XXX is not defined. Drop all of them.

> +

[snip]

> +
> +static int seninf_core_probe(struct platform_device *pdev)
> +{
> +int i, ret, irq;
> +struct resource *res;
> +struct seninf_core *core;
> +struct device *dev = &pdev->dev;
> +
> +core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL);
> +if (!core)
> +return -ENOMEM;
> +
> +dev_set_drvdata(dev, core);
> +core->dev = dev;
> +mutex_init(&core->mutex);
> +INIT_LIST_HEAD(&core->list);
> +
> +res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base");
> +core->reg_if = devm_ioremap_resource(dev, res);
> +if (IS_ERR(core->reg_if))
> +return PTR_ERR(core->reg_if);
> +
> +res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ana-rx");

"ana-rx" is not defined in binding document. Drop this.

> +core->reg_ana = devm_ioremap_resource(dev, res);
> +if (IS_ERR(core->reg_ana))
> +return PTR_ERR(core->reg_ana);
> +
> +ret = get_seninf_cfg(dev, core);
> +if (ret) {
> +dev_err(dev, "failed to get seninf ops\n");
> +return ret;
> +}
> +mtk_cam_seninf_init_res(core);
> +
> +spin_lock_init(&core->spinlock_irq);
> +irq = platform_get_irq(pdev, 0);
> +if (!irq) {
> +dev_err(dev, "failed to get irq\n");
> +return -ENODEV;
> +}
> +
> +ret = devm_request_irq(dev, irq, mtk_irq_seninf, 0,
> + dev_name(dev), core);
> +if (ret) {
> +dev_err(dev, "failed to request irq=%d\n", irq);
> +return ret;
> +}
> +
> +/* default platform properties */
> +core->cphy_settle_delay_dt = SENINF_CPHY_SETTLE_DELAY_DT;
> +core->dphy_settle_delay_dt = SENINF_DPHY_SETTLE_DELAY_DT;
> +core->settle_delay_ck = SENINF_SETTLE_DELAY_CK;
> +core->hs_trail_parameter = SENINF_HS_TRAIL_PARAMETER;
> +
> +/* read platform properties from device tree */
> +of_property_read_u32(dev->of_node, "cphy_settle_delay_dt",
> + &core->cphy_settle_delay_dt);

"cphy_settle_delay_dt" is not defined in binding document. Drop this.

> +of_property_read_u32(dev->of_node, "dphy_settle_delay_dt",
> + &core->dphy_settle_delay_dt);

"dphy_settle_delay_dt" is not defined in binding document. Drop this.

> +of_property_read_u32(dev->of_node, "settle_delay_ck",
> + &core->settle_delay_ck);

"settle_delay_ck" is not defined in binding document. Drop this.

> +of_property_read_u32(dev->of_node, "hs_trail_parameter",
> + &core->hs_trail_parameter);

"hs_trail_parameter" is not defined in binding document. Drop this.

> +
> +core->dfs.cnt = 0;
> +core->dfs.reg = NULL;
> +
> +ret = seninf_core_pm_runtime_enable(core);
> +if (ret) {
> +dev_info(dev, "failed to enable seninf_core_pm_runtime\n");
> +return ret;
> +}
> +
> +for (i = 0; i < CLK_MAXCNT; i++) {
> +core->clk[i] = devm_clk_get(dev, clk_names[i]);
> +if (IS_ERR(core->clk[i])) {
> +dev_info(dev, "failed to get %s\n", clk_names[i]);
> +core->clk[i] = NULL;
> +/* ignore not define seninf */
> +}
> +}
> +
> +ret = of_platform_populate(dev->of_node, NULL, NULL, dev);

It seems "mediatek,mt8188-seninf-core" would probe "mediatek,mt8188-seninf",
but I does not find any relation between them.
How "mediatek,mt8188-seninf-core" proble "mediatek,mt8188-seninf"?

> +if (ret) {
> +dev_info(dev, "%s: failed to create sub devices\n", __func__);
> +return ret;
> +}
> +
> +return 0;
> +}
> +

[snip]

> +
> +int update_isp_clk(struct seninf_ctx *ctx)
> +{
> +int i, pixelmode;
> +struct seninf_dfs *dfs = &ctx->core->dfs;
> +s64 pixel_rate = -1;
> +u64 dfs_freq;
> +struct seninf_vc *vc;
> +int ret = 0;
> +
> +if (!dfs->cnt) {

dfs->cnt is always zero, so drop dfs and drop this function.

> +dev_info(ctx->dev, "dfs not ready.\n");
> +return ret;
> +}
> +
> +vc = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0);
> +if (!vc) {
> +dev_info(ctx->dev, "failed to get vc\n");
> +return -1;
> +}
> +dev_info(ctx->dev,
> + "%s dfs->cnt %d pixel mode %d customized_pixel_rate %lld, buffered_pixel_rate %lld mipi_pixel_rate %lld\n",
> + __func__, dfs->cnt, vc->pixel_mode, ctx->customized_pixel_rate,
> + ctx->buffered_pixel_rate, ctx->mipi_pixel_rate);
> +
> +/* Use SensorPixelrate */
> +if (ctx->customized_pixel_rate) {
> +pixel_rate = ctx->customized_pixel_rate;
> +} else if (ctx->buffered_pixel_rate) {
> +pixel_rate = ctx->buffered_pixel_rate;
> +} else if (ctx->mipi_pixel_rate) {
> +pixel_rate = ctx->mipi_pixel_rate;
> +} else {
> +dev_info(ctx->dev, "failed to get pixel_rate\n");
> +return -EINVAL;
> +}
> +
> +pixelmode = vc->pixel_mode;
> +for (i = 0; i < dfs->cnt; i++) {
> +dfs_freq = dfs->freqs[i];
> +dfs_freq = dfs_freq * (100 - SENINF_CLK_MARGIN_IN_PERCENT);
> +do_div(dfs_freq, 100);
> +if ((dfs_freq << pixelmode) >= pixel_rate)
> +break;
> +}
> +
> +if (i == dfs->cnt) {
> +dev_info(ctx->dev, "mux is overrun. please adjust pixelmode\n");
> +return -EINVAL;
> +}
> +
> +return 0;
> +}
> +

[snip]

> +
> +int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height,
> + s64 hblank, s64 vblank,
> + int fps_n, int fps_d,
> + s64 sensor_pixel_rate)
> +{
> +int ret;
> +s64 p_pixel_rate = sensor_pixel_rate;
> +
> +ret = calc_buffered_pixel_rate(dev, width, height, hblank, vblank,
> + fps_n, fps_d, &p_pixel_rate);
> +if (ret)
> +return sensor_pixel_rate;
> +
> +return p_pixel_rate;
> +}
> +
> +int mtk_cam_seninf_dump(struct v4l2_subdev *sd)

This function does nothing. Drop it.

> +{
> +int ret = 0;
> +//TODO debug patch
> +return ret;
> +}
> +
> +void mtk_cam_seninf_set_secure(struct v4l2_subdev *sd,
> + int enable, unsigned int sec_info_addr)

This function is useless. Drop it.

> +{
> +struct seninf_ctx *ctx = sd_to_ctx(sd);
> +
> +ctx->sec_info_addr = sec_info_addr;
> +dev_info(ctx->dev, "[%s]: %x, enable: %d\n",
> + __func__, sec_info_addr, enable);
> +ctx->is_secure = enable ? 1 : 0;
> +}
>

[snip]

> +
> +enum SET_REG_KEYS {
> +REG_KEY_MIN = 0,
> +REG_KEY_SETTLE_CK = REG_KEY_MIN,
> +REG_KEY_SETTLE_DT,
> +REG_KEY_HS_TRAIL_EN,
> +REG_KEY_HS_TRAIL_PARAM,
> +REG_KEY_CSI_IRQ_STAT,
> +REG_KEY_CSI_RESYNC_CYCLE,
> +REG_KEY_MUX_IRQ_STAT,
> +REG_KEY_CAMMUX_IRQ_STAT,
> +REG_KEY_CAMMUX_VSYNC_IRQ_EN,
> +REG_KEY_CSI_IRQ_EN,
> +REG_KEY_MAX_NUM

Because mtk_cam_seninf_set_reg() is useless and drop,
these enum is also useless. Drop these.

> +};
> +
> +#define SET_REG_KEYS_NAMES \
> +"RG_SETTLE_CK", \
> +"RG_SETTLE_DT", \
> +"RG_HS_TRAIL_EN", \
> +"RG_HS_TRAIL_PARAM", \
> +"RG_CSI_IRQ_STAT", \
> +"RG_CSI_RESYNC_CYCLE", \
> +"RG_MUX_IRQ_STAT", \
> +"RG_CAMMUX_IRQ_STAT", \
> +"REG_VSYNC_IRQ_EN", \
> +"RG_CSI_IRQ_EN", \
> +
> +struct mtk_cam_seninf_mux_meter {

mtk_cam_seninf_mux_meter is useless. Drop it.

> +u32 width;
> +u32 height;
> +u32 h_valid;
> +u32 h_blank;
> +u32 v_valid;
> +u32 v_blank;
> +s64 mipi_pixel_rate;
> +s64 vb_in_us;
> +s64 hb_in_us;
> +s64 line_time_in_us;
> +};
> +

[snip]

> +
> +#define to_std_fmt_code(code) \
> +((code) & 0xFFFF)

to_std_fmt_code() is not necessary. Drop it.

> +
> +

[snip]

> +
> +void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux)
> +{
> +struct seninf_core *core = ctx->core;
> +
> +mutex_lock(&core->mutex);
> +list_move_tail(&mux->list, &core->list_mux);
> +mutex_unlock(&core->mutex);
> +}

I think using list to manage mux resource is a little over coding.
An array could be more simple.

struct sensor_core {
...
bool *mux_used;
...
};

void mtk_cam_seninf_init_res(struct seninf_core *core)
{
int i;

core->mux_used = kzalloc(g_seninf_cfg->mux_num * sizeof(*core->mux_used));
}

int mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx,
int pref_cnt)
{
int mux;

mutex_lock(&core->mutex);

if (!core->mux_used[pref_cnt]) {
core->mux_used[pref_cnt] = true;
mutex_unlock(&core->mutex);
return pref_cnt;
}

for (mux = 0; mux < g_seninf_cfg->mux_num; mux++)
if (!core->mux_used[mux]) {
core->mux_used[mux] = true;
mutex_unlock(&core->mutex);
return mux
}

mutex_unlock(&core->mutex);

return -1;
}

void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx)
{
int mux;

mutex_lock(&core->mutex);
for (mux = 0; mux < g_seninf_cfg->mux_num; mux++)
core->mux_used[mux] = false;
mutex_unlock(&core->mutex);
}

> +
> +struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx)
> +{
> +int i;
> +struct seninf_vcinfo *vcinfo = &ctx->vcinfo;
> +
> +for (i = 0; i < vcinfo->cnt; i++) {
> +if (vcinfo->vc[i].out_pad == idx)
> +return &vcinfo->vc[i];
> +}
> +
> +return NULL;
> +}
> +
> +unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd,
> + unsigned int pad)

This function is useless. Drop it.

> +{
> +struct seninf_vc *pvc = NULL;
> +struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
> +
> +pvc = mtk_cam_seninf_get_vc_by_pad(ctx, pad);
> +if (pvc)
> +return pvc->feature;
> +
> +return VC_NONE;
> +}
> +

[snip]

> +
> +void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx)
> +{
> +struct seninf_mux *ent, *tmp;
> +
> +list_for_each_entry_safe(ent, tmp, &ctx->list_mux, list) {
> +mtk_cam_seninf_mux_put(ctx, ent);
> +}
> +}
> +
> +int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd,
> + int pad_id, int *pixel_mode)

This function is useless. Drop it.

> +{
> +struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev);
> +struct seninf_vc *vc;
> +
> +vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id);
> +if (!vc) {
> +pr_info("%s: invalid pad=%d\n", __func__, pad_id);
> +return -1;
> +}
> +
> +*pixel_mode = vc->pixel_mode;
> +
> +return 0;
> +}
> +

[snip]

> +int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg)
> +{
> +return _mtk_cam_seninf_set_camtg(sd, pad_id, camtg, true);

Squash _mtk_cam_seninf_set_camtg() into mtk_cam_seninf_set_camtg().

> +}
>

[snip]

> +
> +struct seninf_vc {
> +u8 dt;
> +u8 feature;

Because mtk_cam_seninf_get_vc_feature() is useless, so feature is useless.
Drop it.

> +u8 out_pad;
> +u8 pixel_mode;
> +u8 mux; /* allocated per group */
> +u8 cam; /* assigned by cam driver */
> +u8 enable;
> +};
> +

[snip]

> +
> +struct seninf_ctx {
> +struct v4l2_subdev subdev;
> +struct v4l2_async_notifier notifier;
> +struct device *dev;
> +struct v4l2_ctrl_handler ctrl_handler;
> +struct media_pad pads[PAD_MAXCNT];
> +struct v4l2_subdev_format fmt[PAD_MAXCNT];
> +struct seninf_core *core;
> +struct list_head list;
> +
> +u32 port;
> +u32 port_a;
> +u32 port_b;
> +u32 port_num;
> +u32 num_data_lanes;
> +s64 mipi_pixel_rate;

mipi_pixel_rate is never initialized. Drop it.

> +s64 buffered_pixel_rate;

buffered_pixel_rate is used only in update_isp_clk().
update_isp_clk() is useless and drop, so buffered_pixel_rate is useless.
Drop it.

> +s64 customized_pixel_rate;

customized_pixel_rate is useless. Drop it.

> +unsigned int m_csi_efuse;
> +
> +unsigned int is_4d1c:1;
> +unsigned int is_cphy:1;
> +unsigned int is_test_model:4;

is_test_model is useless. Drop it.

> +unsigned int is_secure:1;
> +unsigned int sec_info_addr;

Because mtk_cam_seninf_set_secure() is useless, so is_secure and sec_info_addr are useless.
Drop them.

> +u32 seninf_idx;
> +int pad2cam[PAD_MAXCNT];
> +
> +/* remote sensor */
> +struct v4l2_subdev *sensor_sd;
> +u32 sensor_pad_idx;
> +
> +/* provided by sensor */
> +struct seninf_vcinfo vcinfo;
> +int fps_n;
> +int fps_d;
> +
> +/* dfs */
> +int isp_freq;

isp_freq is useless. Drop it.

> +
> +void __iomem *reg_ana_csi_rx[CSI_PORT_MAX_NUM];
> +void __iomem *reg_ana_dphy_top[CSI_PORT_MAX_NUM];
> +void __iomem *reg_ana_cphy_top[CSI_PORT_MAX_NUM];
> +void __iomem *reg_if_top;
> +void __iomem *reg_if_ctrl[SENINF_NUM];
> +void __iomem *reg_if_cam_mux;
> +void __iomem *reg_if_cam_mux_gcsr;
> +void __iomem *reg_if_cam_mux_pcsr[SENINF_CAM_MUX_NUM];
> +void __iomem *reg_if_tg[SENINF_NUM];
> +void __iomem *reg_if_csi2[SENINF_NUM];
> +void __iomem *reg_if_mux[SENINF_MUX_NUM];
> +
> +/* resources */
> +struct list_head list_mux; /* work mux */
> +struct list_head list_cam_mux;
> +
> +/* flags */
> +unsigned int streaming:1;
> +
> +int cphy_settle_delay_dt;
> +int dphy_settle_delay_dt;
> +int settle_delay_ck;
> +int hs_trail_parameter;
> +
> +int open_refcnt;
> +struct mutex mutex; /* protect seninf context */
> +
> +/* csi irq */
> +unsigned int data_not_enough_cnt;
> +unsigned int err_lane_resync_cnt;
> +unsigned int crc_err_cnt;
> +unsigned int ecc_err_double_cnt;
> +unsigned int ecc_err_corrected_cnt;
> +/* seninf_mux fifo overrun irq */
> +unsigned int fifo_overrun_cnt;
> +/* cam_mux h/v size irq */
> +unsigned int size_err_cnt;
> +/* error flag */
> +unsigned int data_not_enough_flag;
> +unsigned int err_lane_resync_flag;
> +unsigned int crc_err_flag;
> +unsigned int ecc_err_double_flag;
> +unsigned int ecc_err_corrected_flag;
> +unsigned int fifo_overrun_flag;
> +unsigned int size_err_flag;
> +};
> +

[snip]

> +
> +int mtk_cam_seninf_set_cammux_vc(struct seninf_ctx *ctx, int cam_mux,
> + int vc_sel, int dt_sel, int vc_en,
> + int dt_en)

vc_sel is always zero, so just assign 0 in this function and drop vc_sel parameter.
vc_en and dt_en are always !!dt_sel, so it's not necessary to pass vc_en and dt_en as parameter.
Drop these two parameter and use !!dt_sel in this function.

> +{
> +void __iomem *seninf_cam_mux_vc_addr = ctx->reg_if_cam_mux + (cam_mux << 0x2);
> +
> +SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> + RG_SENINF_CAM_MUX0_VC_SEL, vc_sel);
> +SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> + RG_SENINF_CAM_MUX0_DT_SEL, dt_sel);
> +SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> + RG_SENINF_CAM_MUX0_VC_EN, vc_en);
> +SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT,
> + RG_SENINF_CAM_MUX0_DT_EN, dt_en);
> +
> +return 0;
> +}
> +

[snip]

> +int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx,
> + struct seninf_vcinfo *vcinfo)
> +{
> +void __iomem *seninf_csi2 = ctx->reg_if_csi2[seninf_idx];
> +int i;
> +struct seninf_vc *vc;
> +
> +if (WARN_ON(!vcinfo || !vcinfo->cnt))
> +return -EINVAL;
> +
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S0_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S1_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S2_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S3_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S4_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S5_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S6_DI_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S7_DI_CTRL, 0);
> +
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH0_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH1_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH2_CTRL, 0);
> +SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH3_CTRL, 0);
> +
> +for (i = 0; i < vcinfo->cnt; i++) {
> +vc = &vcinfo->vc[i];
> +
> +/* General Long Packet Data Types: 0x10-0x17 */
> +if (vc->dt >= 0x10 && vc->dt <= 0x17) {

vc->dt would only be 0, 0x2a, 0x2b, 0x2c, so this checking would always be false.
Drop this.

> +SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT,
> + RG_CSI2_GENERIC_LONG_PACKET_EN, 1);
> +}
> +
> +mtk_cam_seninf_set_di_ch_ctrl(seninf_csi2, i, vc);
> +}
> +
> +dev_dbg(ctx->dev, "DI_CTRL 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
> +readl(seninf_csi2 + SENINF_CSI2_S0_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S1_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S2_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S3_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S4_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S5_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S6_DI_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_S7_DI_CTRL));
> +
> +dev_dbg(ctx->dev, "CH_CTRL 0x%x 0x%x 0x%x 0x%x\n",
> +readl(seninf_csi2 + SENINF_CSI2_CH0_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_CH1_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_CH2_CTRL),
> +readl(seninf_csi2 + SENINF_CSI2_CH3_CTRL));
> +
> +return 0;
> +}
> +

[snip]

> +
> +int mtk_cam_seninf_irq_handler(int irq, void *data)
> +{
> +struct seninf_core *core = (struct seninf_core *)data;
> +unsigned long flags; /* for mipi err detection */
> +struct seninf_ctx *ctx;
> +struct seninf_vc *vc;
> +void __iomem *csi2, *pmux, *seninf_cam_mux;
> +int i;
> +unsigned int csi_irq_ro;
> +unsigned int mux_irq_ro;
> +unsigned int cam_irq_exp_ro;
> +unsigned int cam_irq_res_ro;
> +
> +spin_lock_irqsave(&core->spinlock_irq, flags);
> +
> +/* debug for set_reg case: REG_KEY_CSI_IRQ_EN */
> +if (core->csi_irq_en_flag) {

Because mtk_cam_seninf_set_reg() is useless, so core->csi_irq_en_flag is always zero.
Drop these code.

> +list_for_each_entry(ctx, &core->list, list) {
> +csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
> +csi_irq_ro =
> +readl(csi2 + SENINF_CSI2_IRQ_STATUS);
> +
> +if (csi_irq_ro) {
> +SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
> + 0xFFFFFFFF);
> +}
> +
> +if (csi_irq_ro & RO_CSI2_ECC_ERR_CORRECTED_IRQ)
> +ctx->ecc_err_corrected_cnt++;
> +if (csi_irq_ro & RO_CSI2_ECC_ERR_DOUBLE_IRQ)
> +ctx->ecc_err_double_cnt++;
> +if (csi_irq_ro & RO_CSI2_CRC_ERR_IRQ)
> +ctx->crc_err_cnt++;
> +if (csi_irq_ro & RO_CSI2_ERR_LANE_RESYNC_IRQ)
> +ctx->err_lane_resync_cnt++;
> +if (csi_irq_ro & RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ)
> +ctx->data_not_enough_cnt++;
> +
> +for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +vc = &ctx->vcinfo.vc[i];
> +pmux = ctx->reg_if_mux[vc->mux];
> +seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +mux_irq_ro = readl(pmux +
> + SENINF_MUX_IRQ_STATUS);
> +
> +cam_irq_exp_ro = readl(seninf_cam_mux +
> + SENINF_CAM_MUX0_CHK_CTL_1 +
> + (0x10 * (vc->cam)));
> +
> +cam_irq_res_ro = readl(seninf_cam_mux +
> + SENINF_CAM_MUX0_CHK_RES +
> + (0x10 * (vc->cam)));
> +
> +if (mux_irq_ro)
> +SENINF_WRITE_REG(pmux,
> + SENINF_MUX_IRQ_STATUS,
> + 0xFFFFFFFF);
> +
> +if (cam_irq_res_ro != cam_irq_exp_ro)
> +SENINF_WRITE_REG(seninf_cam_mux,
> + SENINF_CAM_MUX0_CHK_RES +
> + (0x10 * (vc->cam)),
> + 0xFFFFFFFF);
> +
> +if (mux_irq_ro & (0x1 << 0))
> +ctx->fifo_overrun_cnt++;
> +
> +if (cam_irq_res_ro != cam_irq_exp_ro)
> +ctx->size_err_cnt++;
> +}
> +
> +/* dump status counter: debug for electrical signal */
> +if (ctx->data_not_enough_cnt >= core->detection_cnt ||
> + ctx->err_lane_resync_cnt >= core->detection_cnt ||
> + ctx->crc_err_cnt >= core->detection_cnt ||
> + ctx->ecc_err_double_cnt >= core->detection_cnt ||
> + ctx->ecc_err_corrected_cnt >= core->detection_cnt ||
> + ctx->fifo_overrun_cnt >= core->detection_cnt ||
> + ctx->size_err_cnt >= core->detection_cnt) {
> +/* disable all interrupts */
> +SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_EN, 0x80000000);
> +
> +if (ctx->data_not_enough_cnt >= core->detection_cnt)
> +ctx->data_not_enough_flag = 1;
> +if (ctx->err_lane_resync_cnt >= core->detection_cnt)
> +ctx->err_lane_resync_flag = 1;
> +if (ctx->crc_err_cnt >= core->detection_cnt)
> +ctx->crc_err_flag = 1;
> +if (ctx->ecc_err_double_cnt >= core->detection_cnt)
> +ctx->ecc_err_double_flag = 1;
> +if (ctx->ecc_err_corrected_cnt >= core->detection_cnt)
> +ctx->ecc_err_corrected_flag = 1;
> +if (ctx->fifo_overrun_cnt >= core->detection_cnt)
> +ctx->fifo_overrun_flag = 1;
> +if (ctx->size_err_cnt >= core->detection_cnt)
> +ctx->size_err_flag = 1;
> +}
> +}
> +}
> +
> +spin_unlock_irqrestore(&core->spinlock_irq, flags);
> +
> +return 0;
> +}
> +
> +int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable, int index)

This function is useless, drop it.

> +{
> + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> + unsigned int mask;
> +
> + mask = index ? RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1 : RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0;
> +
> + SENINF_BITS_VAR(seninf_cam_mux, SENINF_CAM_MUX_DYN_CTRL, mask, enable);
> +
> + return 0;
> +}
> +
> +int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index)

This function is useless, drop it.

> +{
> +void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +if (index == 0)
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
> + RG_SENINF_CAM_MUX_DYN_SWITCH_EN0, 0);
> +else
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN,
> + RG_SENINF_CAM_MUX_DYN_SWITCH_EN1, 0);
> +return 0;
> +}
> +
> +int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable,
> + int index)

This function is useless, drop it.

> +{
> +void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +if (index == 0)
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
> + RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN, enable);
> +else
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN,
> + RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN, enable);
> +return 0;
> +}
> +
> +int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable,
> + int cam_mux)

This function is useless, drop it.

> +{
> +void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +int tmp = 0;
> +
> +tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN);
> +if (enable)
> +tmp |= (enable << cam_mux);
> +else
> +tmp &= ~(enable << cam_mux);
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, tmp);
> +return 0;
> +}
> +
> +int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx)

This function is useless, drop it.

> +{
> +void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux;
> +
> +SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN,
> + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, 0);
> +return 0;
> +}
> +
> +int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val)

This function is useless, drop it.

Regards,
CK

> +{
> +int i;
> +void __iomem *base = ctx->reg_ana_dphy_top[ctx->port];
> +void __iomem *csi2 = ctx->reg_if_csi2[ctx->seninf_idx];
> +void __iomem *pmux, *pcammux;
> +struct seninf_vc *vc;
> +struct seninf_core *core;
> +struct seninf_ctx *ctx_;
> +void __iomem *csi2_;
> +
> +core = dev_get_drvdata(ctx->dev->parent);
> +
> +if (!ctx->streaming)
> +return 0;
> +
> +dev_dbg(ctx->dev, "%s key = 0x%x, val = 0x%x\n", __func__, key, val);
> +
> +switch (key) {
> +case REG_KEY_SETTLE_CK:
> +SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER,
> + RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER,
> + RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER, val);
> +break;
> +case REG_KEY_SETTLE_DT:
> +SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> + RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> + RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> + RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> + RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER, val);
> +break;
> +case REG_KEY_HS_TRAIL_EN:
> +SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> + RG_DPHY_RX_LD0_HS_TRAIL_EN, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> + RG_DPHY_RX_LD1_HS_TRAIL_EN, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> + RG_DPHY_RX_LD2_HS_TRAIL_EN, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> + RG_DPHY_RX_LD3_HS_TRAIL_EN, val);
> +break;
> +case REG_KEY_HS_TRAIL_PARAM:
> +SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER,
> + RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER,
> + RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER,
> + RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, val);
> +SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER,
> + RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, val);
> +break;
> +case REG_KEY_CSI_IRQ_STAT:
> +SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS,
> + val & 0xFFFFFFFF);
> +break;
> +case REG_KEY_MUX_IRQ_STAT:
> +for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +vc = &ctx->vcinfo.vc[i];
> +pmux = ctx->reg_if_mux[vc->mux];
> +SENINF_WRITE_REG(pmux, SENINF_MUX_IRQ_STATUS,
> + val & 0xFFFFFFFF);
> +}
> +break;
> +case REG_KEY_CAMMUX_IRQ_STAT:
> +for (i = 0; i < ctx->vcinfo.cnt; i++) {
> +vc = &ctx->vcinfo.vc[i];
> +pcammux = ctx->reg_if_cam_mux;
> +SENINF_WRITE_REG(pcammux, SENINF_CAM_MUX_IRQ_STATUS,
> + val & 0xFFFFFFFF);
> +}
> +break;
> +case REG_KEY_CSI_IRQ_EN:
> +{
> +if (!val) {
> +core->csi_irq_en_flag = 0;
> +return 0;
> +}
> +
> +core->csi_irq_en_flag = 1;
> +core->detection_cnt = val;
> +list_for_each_entry(ctx_, &core->list, list) {
> +csi2_ = ctx_->reg_if_csi2[ctx_->seninf_idx];
> +SENINF_WRITE_REG(csi2_, SENINF_CSI2_IRQ_EN,
> + 0xA0002058);
> +}
> +}
> +break;
> +}
> +
> +return 0;
> +}
>


</pre>
</p></body></html><!--type:text--><!--{--><pre>************* MEDIATEK Confidentiality Notice
 ********************
The information contained in this e-mail message (including any 
attachments) may be confidential, proprietary, privileged, or otherwise
exempt from disclosure under applicable laws. It is intended to be 
conveyed only to the designated recipient(s). Any use, dissemination, 
distribution, printing, retaining or copying of this e-mail (including its 
attachments) by unintended recipient(s) is strictly prohibited and may 
be unlawful. If you are not an intended recipient of this e-mail, or believe
 
that you have received this e-mail in error, please notify the sender 
immediately (by replying to this e-mail), delete any and all copies of 
this e-mail (including any attachments) from your system, and do not
disclose the content of this e-mail to any other person. Thank you!
</pre><!--}-->