Commit 8cc0f5cf authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab

media: atomisp-mt9m114: use v4l2_find_nearest_size()

Instead of reinventing the wheel, use v4l2_find_nearest_size()
in order to get the closest resolution.

This should address a bug where the wrong resolution was
selected.
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent c286a3a0
......@@ -579,107 +579,6 @@ static int mt9m114_s_power(struct v4l2_subdev *sd, int power)
return mt9m114_init_common(sd);
}
/*
* distance - calculate the distance
* @res: resolution
* @w: width
* @h: height
*
* Get the gap between resolution and w/h.
* res->width/height smaller than w/h wouldn't be considered.
* Returns the value of gap or -1 if fail.
*/
#define LARGEST_ALLOWED_RATIO_MISMATCH 600
static int distance(struct mt9m114_res_struct const *res, u32 w, u32 h)
{
unsigned int w_ratio;
unsigned int h_ratio;
int match;
if (w == 0)
return -1;
w_ratio = (res->width << 13) / w;
if (h == 0)
return -1;
h_ratio = (res->height << 13) / h;
if (h_ratio == 0)
return -1;
match = abs(((w_ratio << 13) / h_ratio) - 8192);
if ((w_ratio < 8192) || (h_ratio < 8192) ||
(match > LARGEST_ALLOWED_RATIO_MISMATCH))
return -1;
return w_ratio + h_ratio;
}
/* Return the nearest higher resolution index */
static int nearest_resolution_index(int w, int h)
{
int i;
int idx = -1;
int dist;
int min_dist = INT_MAX;
const struct mt9m114_res_struct *tmp_res = NULL;
for (i = 0; i < ARRAY_SIZE(mt9m114_res); i++) {
tmp_res = &mt9m114_res[i];
dist = distance(tmp_res, w, h);
if (dist == -1)
continue;
if (dist < min_dist) {
min_dist = dist;
idx = i;
}
}
return idx;
}
static int mt9m114_try_res(u32 *w, u32 *h)
{
int idx = 0;
if ((*w > MT9M114_RES_960P_SIZE_H)
|| (*h > MT9M114_RES_960P_SIZE_V)) {
*w = MT9M114_RES_960P_SIZE_H;
*h = MT9M114_RES_960P_SIZE_V;
} else {
idx = nearest_resolution_index(*w, *h);
/*
* nearest_resolution_index() doesn't return smaller
* resolutions. If it fails, it means the requested
* resolution is higher than wecan support. Fallback
* to highest possible resolution in this case.
*/
if (idx == -1)
idx = ARRAY_SIZE(mt9m114_res) - 1;
*w = mt9m114_res[idx].width;
*h = mt9m114_res[idx].height;
}
return 0;
}
static struct mt9m114_res_struct *mt9m114_to_res(u32 w, u32 h)
{
int index;
for (index = 0; index < N_RES; index++) {
if ((mt9m114_res[index].width == w) &&
(mt9m114_res[index].height == h))
break;
}
/* No mode found */
if (index >= N_RES)
return NULL;
return &mt9m114_res[index];
}
static int mt9m114_res2size(struct v4l2_subdev *sd, int *h_size, int *v_size)
{
struct mt9m114_device *dev = to_mt9m114_sensor(sd);
......@@ -829,7 +728,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *fmt = &format->format;
struct i2c_client *c = v4l2_get_subdevdata(sd);
struct mt9m114_device *dev = to_mt9m114_sensor(sd);
struct mt9m114_res_struct *res_index;
struct mt9m114_res_struct *res;
u32 width = fmt->width;
u32 height = fmt->height;
struct camera_mipi_info *mt9m114_info = NULL;
......@@ -845,20 +744,21 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
if (!mt9m114_info)
return -EINVAL;
mt9m114_try_res(&width, &height);
res = v4l2_find_nearest_size(mt9m114_res,
ARRAY_SIZE(mt9m114_res), width,
height, fmt->width, fmt->height);
if (!res)
res = &mt9m114_res[N_RES - 1];
fmt->width = res->width;
fmt->height = res->height;
if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
sd_state->pads->try_fmt = *fmt;
return 0;
}
res_index = mt9m114_to_res(width, height);
/* Sanity check */
if (unlikely(!res_index)) {
WARN_ON(1);
return -EINVAL;
}
switch (res_index->res) {
switch (res->res) {
case MT9M114_RES_736P:
ret = mt9m114_write_reg_array(c, mt9m114_736P_init, NO_POLLING);
ret += misensor_rmw_reg(c, MISENSOR_16BIT, MISENSOR_READ_MODE,
......@@ -876,7 +776,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
MISENSOR_R_MODE_MASK, MISENSOR_NORMAL_SET);
break;
default:
v4l2_err(sd, "set resolution: %d failed!\n", res_index->res);
v4l2_err(sd, "set resolution: %d failed!\n", res->res);
return -EINVAL;
}
......@@ -890,7 +790,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
if (mt9m114_set_suspend(sd))
return -EINVAL;
if (dev->res != res_index->res) {
if (dev->res != res->res) {
int index;
/* Switch to different size */
......@@ -922,7 +822,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
}
}
ret = mt9m114_get_intg_factor(c, mt9m114_info,
&mt9m114_res[res_index->res]);
&mt9m114_res[res->res]);
if (ret) {
dev_err(&c->dev, "failed to get integration_factor\n");
return -EINVAL;
......@@ -931,7 +831,7 @@ static int mt9m114_set_fmt(struct v4l2_subdev *sd,
* mt9m114 - we don't poll for context switch
* because it does not happen with streaming disabled.
*/
dev->res = res_index->res;
dev->res = res->res;
fmt->width = width;
fmt->height = height;
......
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