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

media: smiapp: Read CCS limit values

Read limit and capability values into a driver allocated buffer. This will
later replace (most of) the existing SMIA limits.
Signed-off-by: default avatarSakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 503a8842
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include "ccs-limits.h" #include "ccs-limits.h"
#include "ccs-regs.h"
#include "smiapp.h" #include "smiapp.h"
#define SMIAPP_ALIGN_DIM(dim, flags) \ #define SMIAPP_ALIGN_DIM(dim, flags) \
...@@ -102,6 +103,164 @@ static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor) ...@@ -102,6 +103,164 @@ static int smiapp_read_all_smia_limits(struct smiapp_sensor *sensor)
return 0; return 0;
} }
static void ccs_assign_limit(void *ptr, unsigned int width, u32 val)
{
switch (width) {
case sizeof(u8):
*(u8 *)ptr = val;
break;
case sizeof(u16):
*(u16 *)ptr = val;
break;
case sizeof(u32):
*(u32 *)ptr = val;
break;
}
}
static int ccs_limit_ptr(struct smiapp_sensor *sensor, unsigned int limit,
unsigned int offset, void **__ptr)
{
const struct ccs_limit *linfo;
if (WARN_ON(limit >= CCS_L_LAST))
return -EINVAL;
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
if (WARN_ON(!sensor->ccs_limits) ||
WARN_ON(offset + ccs_reg_width(linfo->reg) >
ccs_limit_offsets[limit + 1].lim))
return -EINVAL;
*__ptr = sensor->ccs_limits + ccs_limit_offsets[limit].lim + offset;
return 0;
}
void ccs_replace_limit(struct smiapp_sensor *sensor,
unsigned int limit, unsigned int offset, u32 val)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
const struct ccs_limit *linfo;
void *ptr;
int ret;
ret = ccs_limit_ptr(sensor, limit, offset, &ptr);
if (ret)
return;
linfo = &ccs_limits[ccs_limit_offsets[limit].info];
dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" %u = %d, 0x%x\n",
linfo->reg, linfo->name, offset, val, val);
ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val);
}
static u32 ccs_get_limit(struct smiapp_sensor *sensor,
unsigned int limit, unsigned int offset)
{
void *ptr;
int ret;
ret = ccs_limit_ptr(sensor, limit, offset, &ptr);
if (ret)
return 0;
switch (ccs_reg_width(ccs_limits[ccs_limit_offsets[limit].info].reg)) {
case sizeof(u8):
return *(u8 *)ptr;
case sizeof(u16):
return *(u16 *)ptr;
case sizeof(u32):
return *(u32 *)ptr;
}
WARN_ON(1);
return 0;
}
#define CCS_LIM(sensor, limit) \
ccs_get_limit(sensor, CCS_L_##limit, 0)
#define CCS_LIM_AT(sensor, limit, offset) \
ccs_get_limit(sensor, CCS_L_##limit, CCS_L_##limit##_OFFSET(offset))
static int ccs_read_all_limits(struct smiapp_sensor *sensor)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
void *ptr, *alloc, *end;
unsigned int i, l;
int ret;
kfree(sensor->ccs_limits);
sensor->ccs_limits = NULL;
alloc = kzalloc(ccs_limit_offsets[CCS_L_LAST].lim, GFP_KERNEL);
if (!alloc)
return -ENOMEM;
end = alloc + ccs_limit_offsets[CCS_L_LAST].lim;
for (i = 0, l = 0, ptr = alloc; ccs_limits[i].size; i++) {
u32 reg = ccs_limits[i].reg;
unsigned int width = ccs_reg_width(reg);
unsigned int j;
if (l == CCS_L_LAST) {
dev_err(&client->dev,
"internal error --- end of limit array\n");
ret = -EINVAL;
goto out_err;
}
for (j = 0; j < ccs_limits[i].size / width;
j++, reg += width, ptr += width) {
u32 val;
ret = smiapp_read(sensor, reg, &val);
if (ret)
goto out_err;
if (ptr + width > end) {
dev_err(&client->dev,
"internal error --- no room for regs\n");
ret = -EINVAL;
goto out_err;
}
ccs_assign_limit(ptr, width, val);
dev_dbg(&client->dev, "0x%8.8x \"%s\" = %u, 0x%x\n",
reg, ccs_limits[i].name, val, val);
}
if (ccs_limits[i].flags & CCS_L_FL_SAME_REG)
continue;
l++;
ptr = alloc + ccs_limit_offsets[l].lim;
}
if (l != CCS_L_LAST) {
dev_err(&client->dev,
"internal error --- insufficient limits\n");
ret = -EINVAL;
goto out_err;
}
sensor->ccs_limits = alloc;
return 0;
out_err:
kfree(alloc);
return ret;
}
static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor)
{ {
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
...@@ -2970,10 +3129,14 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -2970,10 +3129,14 @@ static int smiapp_probe(struct i2c_client *client)
goto out_power_off; goto out_power_off;
} }
rval = ccs_read_all_limits(sensor);
if (rval)
goto out_power_off;
rval = smiapp_read_frame_fmt(sensor); rval = smiapp_read_frame_fmt(sensor);
if (rval) { if (rval) {
rval = -ENODEV; rval = -ENODEV;
goto out_power_off; goto out_free_ccs_limits;
} }
/* /*
...@@ -2997,7 +3160,7 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -2997,7 +3160,7 @@ static int smiapp_probe(struct i2c_client *client)
rval = smiapp_call_quirk(sensor, limits); rval = smiapp_call_quirk(sensor, limits);
if (rval) { if (rval) {
dev_err(&client->dev, "limits quirks failed\n"); dev_err(&client->dev, "limits quirks failed\n");
goto out_power_off; goto out_free_ccs_limits;
} }
if (SMIA_LIM(sensor, BINNING_CAPABILITY)) { if (SMIA_LIM(sensor, BINNING_CAPABILITY)) {
...@@ -3007,7 +3170,7 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -3007,7 +3170,7 @@ static int smiapp_probe(struct i2c_client *client)
SMIAPP_REG_U8_BINNING_SUBTYPES, &val); SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
if (rval < 0) { if (rval < 0) {
rval = -ENODEV; rval = -ENODEV;
goto out_power_off; goto out_free_ccs_limits;
} }
sensor->nbinning_subtypes = min_t(u8, val, sensor->nbinning_subtypes = min_t(u8, val,
SMIAPP_BINNING_SUBTYPES); SMIAPP_BINNING_SUBTYPES);
...@@ -3017,7 +3180,7 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -3017,7 +3180,7 @@ static int smiapp_probe(struct i2c_client *client)
sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
if (rval < 0) { if (rval < 0) {
rval = -ENODEV; rval = -ENODEV;
goto out_power_off; goto out_free_ccs_limits;
} }
sensor->binning_subtypes[i] = sensor->binning_subtypes[i] =
*(struct smiapp_binning_subtype *)&val; *(struct smiapp_binning_subtype *)&val;
...@@ -3033,7 +3196,7 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -3033,7 +3196,7 @@ static int smiapp_probe(struct i2c_client *client)
if (device_create_file(&client->dev, &dev_attr_ident) != 0) { if (device_create_file(&client->dev, &dev_attr_ident) != 0) {
dev_err(&client->dev, "sysfs ident entry creation failed\n"); dev_err(&client->dev, "sysfs ident entry creation failed\n");
rval = -ENOENT; rval = -ENOENT;
goto out_power_off; goto out_free_ccs_limits;
} }
if (sensor->minfo.smiapp_version && if (sensor->minfo.smiapp_version &&
...@@ -3150,6 +3313,9 @@ static int smiapp_probe(struct i2c_client *client) ...@@ -3150,6 +3313,9 @@ static int smiapp_probe(struct i2c_client *client)
out_cleanup: out_cleanup:
smiapp_cleanup(sensor); smiapp_cleanup(sensor);
out_free_ccs_limits:
kfree(sensor->ccs_limits);
out_power_off: out_power_off:
smiapp_power_off(&client->dev); smiapp_power_off(&client->dev);
mutex_destroy(&sensor->mutex); mutex_destroy(&sensor->mutex);
...@@ -3176,6 +3342,7 @@ static int smiapp_remove(struct i2c_client *client) ...@@ -3176,6 +3342,7 @@ static int smiapp_remove(struct i2c_client *client)
} }
smiapp_cleanup(sensor); smiapp_cleanup(sensor);
mutex_destroy(&sensor->mutex); mutex_destroy(&sensor->mutex);
kfree(sensor->ccs_limits);
return 0; return 0;
} }
......
...@@ -228,6 +228,7 @@ struct smiapp_sensor { ...@@ -228,6 +228,7 @@ struct smiapp_sensor {
struct clk *ext_clk; struct clk *ext_clk;
struct gpio_desc *xshutdown; struct gpio_desc *xshutdown;
u32 limits[SMIAPP_LIMIT_LAST]; u32 limits[SMIAPP_LIMIT_LAST];
void *ccs_limits;
u8 nbinning_subtypes; u8 nbinning_subtypes;
struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
u32 mbus_frame_fmts; u32 mbus_frame_fmts;
...@@ -281,4 +282,7 @@ struct smiapp_sensor { ...@@ -281,4 +282,7 @@ struct smiapp_sensor {
#define to_smiapp_sensor(_sd) \ #define to_smiapp_sensor(_sd) \
(to_smiapp_subdev(_sd)->sensor) (to_smiapp_subdev(_sd)->sensor)
void ccs_replace_limit(struct smiapp_sensor *sensor,
unsigned int limit, unsigned int offset, u32 val);
#endif /* __SMIAPP_PRIV_H_ */ #endif /* __SMIAPP_PRIV_H_ */
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