Commit 6970d37c authored by Sakari Ailus's avatar Sakari Ailus Committed by Mauro Carvalho Chehab

media: v4l: fwnode: Let the caller provide V4L2 fwnode endpoint

Instead of allocating the V4L2 fwnode endpoint in
v4l2_fwnode_endpoint_alloc_parse, let the caller to do this. This allows
setting default parameters for the endpoint which is a very common need
for drivers.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Tested-by: default avatarSteve Longerbeam <steve_longerbeam@mentor.com>
Tested-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 2d95e7ed
...@@ -1347,8 +1347,9 @@ static struct ov2659_platform_data * ...@@ -1347,8 +1347,9 @@ static struct ov2659_platform_data *
ov2659_get_pdata(struct i2c_client *client) ov2659_get_pdata(struct i2c_client *client)
{ {
struct ov2659_platform_data *pdata; struct ov2659_platform_data *pdata;
struct v4l2_fwnode_endpoint *bus_cfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct device_node *endpoint; struct device_node *endpoint;
int ret;
if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node) if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
return client->dev.platform_data; return client->dev.platform_data;
...@@ -1357,8 +1358,9 @@ ov2659_get_pdata(struct i2c_client *client) ...@@ -1357,8 +1358,9 @@ ov2659_get_pdata(struct i2c_client *client)
if (!endpoint) if (!endpoint)
return NULL; return NULL;
bus_cfg = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint)); ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(endpoint),
if (IS_ERR(bus_cfg)) { &bus_cfg);
if (ret) {
pdata = NULL; pdata = NULL;
goto done; goto done;
} }
...@@ -1367,17 +1369,17 @@ ov2659_get_pdata(struct i2c_client *client) ...@@ -1367,17 +1369,17 @@ ov2659_get_pdata(struct i2c_client *client)
if (!pdata) if (!pdata)
goto done; goto done;
if (!bus_cfg->nr_of_link_frequencies) { if (!bus_cfg.nr_of_link_frequencies) {
dev_err(&client->dev, dev_err(&client->dev,
"link-frequencies property not found or too many\n"); "link-frequencies property not found or too many\n");
pdata = NULL; pdata = NULL;
goto done; goto done;
} }
pdata->link_frequency = bus_cfg->link_frequencies[0]; pdata->link_frequency = bus_cfg.link_frequencies[0];
done: done:
v4l2_fwnode_endpoint_free(bus_cfg); v4l2_fwnode_endpoint_free(&bus_cfg);
of_node_put(endpoint); of_node_put(endpoint);
return pdata; return pdata;
} }
......
...@@ -2757,7 +2757,7 @@ static int __maybe_unused smiapp_resume(struct device *dev) ...@@ -2757,7 +2757,7 @@ static int __maybe_unused smiapp_resume(struct device *dev)
static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
{ {
struct smiapp_hwconfig *hwcfg; struct smiapp_hwconfig *hwcfg;
struct v4l2_fwnode_endpoint *bus_cfg; struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
struct fwnode_handle *ep; struct fwnode_handle *ep;
struct fwnode_handle *fwnode = dev_fwnode(dev); struct fwnode_handle *fwnode = dev_fwnode(dev);
u32 rotation; u32 rotation;
...@@ -2771,27 +2771,27 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) ...@@ -2771,27 +2771,27 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
if (!ep) if (!ep)
return NULL; return NULL;
bus_cfg = v4l2_fwnode_endpoint_alloc_parse(ep); rval = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
if (IS_ERR(bus_cfg)) if (rval)
goto out_err; goto out_err;
hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL); hwcfg = devm_kzalloc(dev, sizeof(*hwcfg), GFP_KERNEL);
if (!hwcfg) if (!hwcfg)
goto out_err; goto out_err;
switch (bus_cfg->bus_type) { switch (bus_cfg.bus_type) {
case V4L2_MBUS_CSI2_DPHY: case V4L2_MBUS_CSI2_DPHY:
hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2; hwcfg->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2;
hwcfg->lanes = bus_cfg->bus.mipi_csi2.num_data_lanes; hwcfg->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
break; break;
case V4L2_MBUS_CCP2: case V4L2_MBUS_CCP2:
hwcfg->csi_signalling_mode = (bus_cfg->bus.mipi_csi1.strobe) ? hwcfg->csi_signalling_mode = (bus_cfg.bus.mipi_csi1.strobe) ?
SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE : SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE :
SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK; SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK;
hwcfg->lanes = 1; hwcfg->lanes = 1;
break; break;
default: default:
dev_err(dev, "unsupported bus %u\n", bus_cfg->bus_type); dev_err(dev, "unsupported bus %u\n", bus_cfg.bus_type);
goto out_err; goto out_err;
} }
...@@ -2823,28 +2823,28 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev) ...@@ -2823,28 +2823,28 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
dev_dbg(dev, "nvm %d, clk %d, mode %d\n", dev_dbg(dev, "nvm %d, clk %d, mode %d\n",
hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode); hwcfg->nvm_size, hwcfg->ext_clk, hwcfg->csi_signalling_mode);
if (!bus_cfg->nr_of_link_frequencies) { if (!bus_cfg.nr_of_link_frequencies) {
dev_warn(dev, "no link frequencies defined\n"); dev_warn(dev, "no link frequencies defined\n");
goto out_err; goto out_err;
} }
hwcfg->op_sys_clock = devm_kcalloc( hwcfg->op_sys_clock = devm_kcalloc(
dev, bus_cfg->nr_of_link_frequencies + 1 /* guardian */, dev, bus_cfg.nr_of_link_frequencies + 1 /* guardian */,
sizeof(*hwcfg->op_sys_clock), GFP_KERNEL); sizeof(*hwcfg->op_sys_clock), GFP_KERNEL);
if (!hwcfg->op_sys_clock) if (!hwcfg->op_sys_clock)
goto out_err; goto out_err;
for (i = 0; i < bus_cfg->nr_of_link_frequencies; i++) { for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) {
hwcfg->op_sys_clock[i] = bus_cfg->link_frequencies[i]; hwcfg->op_sys_clock[i] = bus_cfg.link_frequencies[i];
dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]); dev_dbg(dev, "freq %d: %lld\n", i, hwcfg->op_sys_clock[i]);
} }
v4l2_fwnode_endpoint_free(bus_cfg); v4l2_fwnode_endpoint_free(&bus_cfg);
fwnode_handle_put(ep); fwnode_handle_put(ep);
return hwcfg; return hwcfg;
out_err: out_err:
v4l2_fwnode_endpoint_free(bus_cfg); v4l2_fwnode_endpoint_free(&bus_cfg);
fwnode_handle_put(ep); fwnode_handle_put(ep);
return NULL; return NULL;
} }
......
...@@ -1895,11 +1895,11 @@ static void tc358743_gpio_reset(struct tc358743_state *state) ...@@ -1895,11 +1895,11 @@ static void tc358743_gpio_reset(struct tc358743_state *state)
static int tc358743_probe_of(struct tc358743_state *state) static int tc358743_probe_of(struct tc358743_state *state)
{ {
struct device *dev = &state->i2c_client->dev; struct device *dev = &state->i2c_client->dev;
struct v4l2_fwnode_endpoint *endpoint; struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
struct device_node *ep; struct device_node *ep;
struct clk *refclk; struct clk *refclk;
u32 bps_pr_lane; u32 bps_pr_lane;
int ret = -EINVAL; int ret;
refclk = devm_clk_get(dev, "refclk"); refclk = devm_clk_get(dev, "refclk");
if (IS_ERR(refclk)) { if (IS_ERR(refclk)) {
...@@ -1915,26 +1915,28 @@ static int tc358743_probe_of(struct tc358743_state *state) ...@@ -1915,26 +1915,28 @@ static int tc358743_probe_of(struct tc358743_state *state)
return -EINVAL; return -EINVAL;
} }
endpoint = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep)); ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(ep), &endpoint);
if (IS_ERR(endpoint)) { if (ret) {
dev_err(dev, "failed to parse endpoint\n"); dev_err(dev, "failed to parse endpoint\n");
ret = PTR_ERR(endpoint); ret = ret;
goto put_node; goto put_node;
} }
if (endpoint->bus_type != V4L2_MBUS_CSI2_DPHY || if (endpoint.bus_type != V4L2_MBUS_CSI2_DPHY ||
endpoint->bus.mipi_csi2.num_data_lanes == 0 || endpoint.bus.mipi_csi2.num_data_lanes == 0 ||
endpoint->nr_of_link_frequencies == 0) { endpoint.nr_of_link_frequencies == 0) {
dev_err(dev, "missing CSI-2 properties in endpoint\n"); dev_err(dev, "missing CSI-2 properties in endpoint\n");
ret = -EINVAL;
goto free_endpoint; goto free_endpoint;
} }
if (endpoint->bus.mipi_csi2.num_data_lanes > 4) { if (endpoint.bus.mipi_csi2.num_data_lanes > 4) {
dev_err(dev, "invalid number of lanes\n"); dev_err(dev, "invalid number of lanes\n");
ret = -EINVAL;
goto free_endpoint; goto free_endpoint;
} }
state->bus = endpoint->bus.mipi_csi2; state->bus = endpoint.bus.mipi_csi2;
ret = clk_prepare_enable(refclk); ret = clk_prepare_enable(refclk);
if (ret) { if (ret) {
...@@ -1967,7 +1969,7 @@ static int tc358743_probe_of(struct tc358743_state *state) ...@@ -1967,7 +1969,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
* The CSI bps per lane must be between 62.5 Mbps and 1 Gbps. * The CSI bps per lane must be between 62.5 Mbps and 1 Gbps.
* The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60. * The default is 594 Mbps for 4-lane 1080p60 or 2-lane 720p60.
*/ */
bps_pr_lane = 2 * endpoint->link_frequencies[0]; bps_pr_lane = 2 * endpoint.link_frequencies[0];
if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) { if (bps_pr_lane < 62500000U || bps_pr_lane > 1000000000U) {
dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane); dev_err(dev, "unsupported bps per lane: %u bps\n", bps_pr_lane);
goto disable_clk; goto disable_clk;
...@@ -2013,7 +2015,7 @@ static int tc358743_probe_of(struct tc358743_state *state) ...@@ -2013,7 +2015,7 @@ static int tc358743_probe_of(struct tc358743_state *state)
disable_clk: disable_clk:
clk_disable_unprepare(refclk); clk_disable_unprepare(refclk);
free_endpoint: free_endpoint:
v4l2_fwnode_endpoint_free(endpoint); v4l2_fwnode_endpoint_free(&endpoint);
put_node: put_node:
of_node_put(ep); of_node_put(ep);
return ret; return ret;
......
...@@ -290,23 +290,17 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep) ...@@ -290,23 +290,17 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
return; return;
kfree(vep->link_frequencies); kfree(vep->link_frequencies);
kfree(vep);
} }
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free); EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( int v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode) struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep)
{ {
struct v4l2_fwnode_endpoint *vep;
int rval; int rval;
vep = kzalloc(sizeof(*vep), GFP_KERNEL);
if (!vep)
return ERR_PTR(-ENOMEM);
rval = __v4l2_fwnode_endpoint_parse(fwnode, vep); rval = __v4l2_fwnode_endpoint_parse(fwnode, vep);
if (rval < 0) if (rval < 0)
goto out_err; return rval;
rval = fwnode_property_read_u64_array(fwnode, "link-frequencies", rval = fwnode_property_read_u64_array(fwnode, "link-frequencies",
NULL, 0); NULL, 0);
...@@ -316,18 +310,18 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( ...@@ -316,18 +310,18 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
vep->link_frequencies = vep->link_frequencies =
kmalloc_array(rval, sizeof(*vep->link_frequencies), kmalloc_array(rval, sizeof(*vep->link_frequencies),
GFP_KERNEL); GFP_KERNEL);
if (!vep->link_frequencies) { if (!vep->link_frequencies)
rval = -ENOMEM; return -ENOMEM;
goto out_err;
}
vep->nr_of_link_frequencies = rval; vep->nr_of_link_frequencies = rval;
rval = fwnode_property_read_u64_array( rval = fwnode_property_read_u64_array(
fwnode, "link-frequencies", vep->link_frequencies, fwnode, "link-frequencies", vep->link_frequencies,
vep->nr_of_link_frequencies); vep->nr_of_link_frequencies);
if (rval < 0) if (rval < 0) {
goto out_err; v4l2_fwnode_endpoint_free(vep);
return rval;
}
for (i = 0; i < vep->nr_of_link_frequencies; i++) for (i = 0; i < vep->nr_of_link_frequencies; i++)
pr_info("link-frequencies %u value %llu\n", i, pr_info("link-frequencies %u value %llu\n", i,
...@@ -336,11 +330,7 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( ...@@ -336,11 +330,7 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
pr_debug("===== end V4L2 endpoint properties\n"); pr_debug("===== end V4L2 endpoint properties\n");
return vep; return 0;
out_err:
v4l2_fwnode_endpoint_free(vep);
return ERR_PTR(rval);
} }
EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse); EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
...@@ -392,9 +382,9 @@ static int v4l2_async_notifier_fwnode_parse_endpoint( ...@@ -392,9 +382,9 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
struct v4l2_fwnode_endpoint *vep, struct v4l2_fwnode_endpoint *vep,
struct v4l2_async_subdev *asd)) struct v4l2_async_subdev *asd))
{ {
struct v4l2_fwnode_endpoint vep = { .bus_type = 0 };
struct v4l2_async_subdev *asd; struct v4l2_async_subdev *asd;
struct v4l2_fwnode_endpoint *vep; int ret;
int ret = 0;
asd = kzalloc(asd_struct_size, GFP_KERNEL); asd = kzalloc(asd_struct_size, GFP_KERNEL);
if (!asd) if (!asd)
...@@ -409,23 +399,22 @@ static int v4l2_async_notifier_fwnode_parse_endpoint( ...@@ -409,23 +399,22 @@ static int v4l2_async_notifier_fwnode_parse_endpoint(
goto out_err; goto out_err;
} }
vep = v4l2_fwnode_endpoint_alloc_parse(endpoint); ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &vep);
if (IS_ERR(vep)) { if (ret) {
ret = PTR_ERR(vep);
dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n", dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
ret); ret);
goto out_err; goto out_err;
} }
ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0; ret = parse_endpoint ? parse_endpoint(dev, &vep, asd) : 0;
if (ret == -ENOTCONN) if (ret == -ENOTCONN)
dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port, dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep.base.port,
vep->base.id); vep.base.id);
else if (ret < 0) else if (ret < 0)
dev_warn(dev, dev_warn(dev,
"driver could not parse port@%u/endpoint@%u (%d)\n", "driver could not parse port@%u/endpoint@%u (%d)\n",
vep->base.port, vep->base.id, ret); vep.base.port, vep.base.id, ret);
v4l2_fwnode_endpoint_free(vep); v4l2_fwnode_endpoint_free(&vep);
if (ret < 0) if (ret < 0)
goto out_err; goto out_err;
......
...@@ -161,6 +161,7 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); ...@@ -161,6 +161,7 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
/** /**
* v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
* @fwnode: pointer to the endpoint's fwnode handle * @fwnode: pointer to the endpoint's fwnode handle
* @vep: pointer to the V4L2 fwnode data structure
* *
* All properties are optional. If none are found, we don't set any flags. This * All properties are optional. If none are found, we don't set any flags. This
* means the port has a static configuration and no properties have to be * means the port has a static configuration and no properties have to be
...@@ -170,6 +171,8 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); ...@@ -170,6 +171,8 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
* set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
* reference to @fwnode. * reference to @fwnode.
* *
* The caller must set the bus_type field of @vep to zero.
*
* v4l2_fwnode_endpoint_alloc_parse() has two important differences to * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
* v4l2_fwnode_endpoint_parse(): * v4l2_fwnode_endpoint_parse():
* *
...@@ -178,11 +181,10 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep); ...@@ -178,11 +181,10 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
* 2. The memory it has allocated to store the variable size data must be freed * 2. The memory it has allocated to store the variable size data must be freed
* using v4l2_fwnode_endpoint_free() when no longer needed. * using v4l2_fwnode_endpoint_free() when no longer needed.
* *
* Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer * Return: 0 on success or a negative error code on failure.
* on error.
*/ */
struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse( int v4l2_fwnode_endpoint_alloc_parse(
struct fwnode_handle *fwnode); struct fwnode_handle *fwnode, struct v4l2_fwnode_endpoint *vep);
/** /**
* v4l2_fwnode_parse_link() - parse a link between two endpoints * v4l2_fwnode_parse_link() - parse a link between two endpoints
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment