struct csis_drvdata { /* Mask of all used interrupts in S5PCSIS_INTMSK register */
u32 interrupt_mask;
};
/** * struct csis_state - the driver's internal state data structure * @lock: mutex serializing the subdev and power management operations, * protecting @format and @flags members * @pads: CSIS pads array * @sd: v4l2_subdev associated with CSIS device instance * @index: the hardware instance index * @pdev: CSIS platform device * @phy: pointer to the CSIS generic PHY * @regs: mmapped I/O registers memory * @supplies: CSIS regulator supplies * @clock: CSIS clocks * @irq: requested s5p-mipi-csis irq number * @interrupt_mask: interrupt mask of the all used interrupts * @flags: the state variable for power and streaming control * @clk_frequency: device bus clock frequency * @hs_settle: HS-RX settle time * @num_lanes: number of MIPI-CSI data lanes used * @max_num_lanes: maximum number of MIPI-CSI data lanes supported * @wclk_ext: CSI wrapper clock: 0 - bus clock, 1 - external SCLK_CAM * @csis_fmt: current CSIS pixel format * @format: common media bus format for the source and sink pad * @slock: spinlock protecting structure members below * @pkt_buf: the frame embedded (non-image) data buffer * @events: MIPI-CSIS event (error) counters
*/ struct csis_state { struct mutex lock; struct media_pad pads[CSIS_PADS_NUM]; struct v4l2_subdev sd;
u8 index; struct platform_device *pdev; struct phy *phy; void __iomem *regs; struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; struct clk *clock[NUM_CSIS_CLOCKS]; int irq;
u32 interrupt_mask;
u32 flags;
staticconststruct csis_pix_format *find_csis_format( struct v4l2_mbus_framefmt *mf)
{ int i;
for (i = 0; i < ARRAY_SIZE(s5pcsis_formats); i++) if (mf->code == s5pcsis_formats[i].code) return &s5pcsis_formats[i]; return NULL;
}
staticvoid s5pcsis_enable_interrupts(struct csis_state *state, bool on)
{
u32 val = s5pcsis_read(state, S5PCSIS_INTMSK); if (on)
val |= state->interrupt_mask; else
val &= ~state->interrupt_mask;
s5pcsis_write(state, S5PCSIS_INTMSK, val);
}
staticvoid s5pcsis_reset(struct csis_state *state)
{
u32 val = s5pcsis_read(state, S5PCSIS_CTRL);
s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_RESET);
udelay(10);
}
staticvoid s5pcsis_system_enable(struct csis_state *state, int on)
{
u32 val, mask;
val = s5pcsis_read(state, S5PCSIS_CTRL); if (on)
val |= S5PCSIS_CTRL_ENABLE; else
val &= ~S5PCSIS_CTRL_ENABLE;
s5pcsis_write(state, S5PCSIS_CTRL, val);
val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
val &= ~S5PCSIS_DPHYCTRL_ENABLE; if (on) {
mask = (1 << (state->num_lanes + 1)) - 1;
val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
}
s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
}
/* Called with the state.lock mutex held */ staticvoid __s5pcsis_set_format(struct csis_state *state)
{ struct v4l2_mbus_framefmt *mf = &state->format;
u32 val;
/* Color format */
val = s5pcsis_read(state, S5PCSIS_CONFIG);
val = (val & ~S5PCSIS_CFG_FMT_MASK) | state->csis_fmt->fmt_reg;
s5pcsis_write(state, S5PCSIS_CONFIG, val);
val = s5pcsis_read(state, S5PCSIS_CTRL); if (state->csis_fmt->data_alignment == 32)
val |= S5PCSIS_CTRL_ALIGN_32BIT; else/* 24-bits */
val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; if (state->wclk_ext)
val |= S5PCSIS_CTRL_WCLK_EXTCLK;
s5pcsis_write(state, S5PCSIS_CTRL, val);
/* Update the shadow register. */
val = s5pcsis_read(state, S5PCSIS_CTRL);
s5pcsis_write(state, S5PCSIS_CTRL, val | S5PCSIS_CTRL_UPDATE_SHADOW);
}
staticvoid s5pcsis_clk_put(struct csis_state *state)
{ int i;
for (i = 0; i < NUM_CSIS_CLOCKS; i++) { if (IS_ERR(state->clock[i])) continue;
clk_unprepare(state->clock[i]);
clk_put(state->clock[i]);
state->clock[i] = ERR_PTR(-EINVAL);
}
}
staticint s5pcsis_clk_get(struct csis_state *state)
{ struct device *dev = &state->pdev->dev; int i, ret;
for (i = 0; i < NUM_CSIS_CLOCKS; i++)
state->clock[i] = ERR_PTR(-EINVAL);
for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
state->clock[i] = clk_get(dev, csi_clock_name[i]); if (IS_ERR(state->clock[i])) {
ret = PTR_ERR(state->clock[i]); goto err;
}
ret = clk_prepare(state->clock[i]); if (ret < 0) {
clk_put(state->clock[i]);
state->clock[i] = ERR_PTR(-EINVAL); goto err;
}
} return 0;
err:
s5pcsis_clk_put(state);
dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); return ret;
}
if (of_property_read_u32(node, "clock-frequency",
&state->clk_frequency))
state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ; if (of_property_read_u32(node, "bus-width",
&state->max_num_lanes)) return -EINVAL;
/* from port@3 or port@4 */
node = of_graph_get_endpoint_by_regs(node, -1, -1); if (!node) {
dev_err(&pdev->dev, "No port node at %pOF\n",
pdev->dev.of_node); return -EINVAL;
} /* Get port node and validate MIPI-CSI channel id. */
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &endpoint); if (ret) goto err;
state->index = endpoint.base.port - FIMC_INPUT_MIPI_CSI2_0; if (state->index >= CSIS_MAX_ENTITIES) {
ret = -ENXIO; goto err;
}
/* Get MIPI CSI-2 bus configuration from the endpoint node. */
of_property_read_u32(node, "samsung,csis-hs-settle",
&state->hs_settle);
state->wclk_ext = of_property_read_bool(node, "samsung,csis-wclk");
ret = s5pcsis_parse_dt(pdev, state); if (ret < 0) return ret;
if (state->num_lanes == 0 || state->num_lanes > state->max_num_lanes) {
dev_err(dev, "Unsupported number of data lanes: %d (max. %d)\n",
state->num_lanes, state->max_num_lanes); return -EINVAL;
}
state->phy = devm_phy_get(dev, "csis"); if (IS_ERR(state->phy)) return PTR_ERR(state->phy);
state->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(state->regs)) return PTR_ERR(state->regs);
state->irq = platform_get_irq(pdev, 0); if (state->irq < 0) return state->irq;
for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
state->supplies[i].supply = csis_supply_name[i];
ret = devm_regulator_bulk_get(dev, CSIS_NUM_SUPPLIES,
state->supplies); if (ret) return ret;
ret = s5pcsis_clk_get(state); if (ret < 0) return ret;
if (state->clk_frequency)
ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
state->clk_frequency); else
dev_WARN(dev, "No clock frequency specified!\n"); if (ret < 0) goto e_clkput;
ret = clk_enable(state->clock[CSIS_CLK_MUX]); if (ret < 0) goto e_clkput;
ret = devm_request_irq(dev, state->irq, s5pcsis_irq_handler,
0, dev_name(dev), state); if (ret) {
dev_err(dev, "Interrupt request failed\n"); goto e_clkdis;
}
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.