OSDN Git Service

media: ccs: Read ireal numbers correctly
authorSakari Ailus <sakari.ailus@linux.intel.com>
Wed, 24 Jun 2020 13:39:05 +0000 (15:39 +0200)
committerMauro Carvalho Chehab <mchehab+huawei@kernel.org>
Thu, 3 Dec 2020 11:27:31 +0000 (12:27 +0100)
Some limit values are available in q16.q16 format, referred to as 32-bit
unsigned ireal in CCS. Read these correctly.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
drivers/media/i2c/ccs/ccs-core.c
drivers/media/i2c/ccs/ccs-reg-access.c
drivers/media/i2c/ccs/ccs.h

index 57efc34..074b246 100644 (file)
@@ -126,8 +126,8 @@ void ccs_replace_limit(struct ccs_sensor *sensor,
        ccs_assign_limit(ptr, ccs_reg_width(linfo->reg), val);
 }
 
-static u32 ccs_get_limit(struct ccs_sensor *sensor,
-                        unsigned int limit, unsigned int offset)
+u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
+                 unsigned int offset)
 {
        void *ptr;
        u32 val;
@@ -155,12 +155,6 @@ static u32 ccs_get_limit(struct ccs_sensor *sensor,
        return ccs_reg_conv(sensor, ccs_limits[limit].reg, val);
 }
 
-#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 ccs_sensor *sensor)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
index fe6112c..91ccbca 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/i2c.h>
 
 #include "ccs.h"
+#include "ccs-limits.h"
 
 static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
                                         uint32_t phloat)
@@ -143,12 +144,30 @@ unsigned int ccs_reg_width(u32 reg)
        return sizeof(uint8_t);
 }
 
+static u32 ireal32_to_u32_mul_1000000(struct i2c_client *client, u32 val)
+{
+       if (val >> 10 > U32_MAX / 15625) {
+               dev_warn(&client->dev, "value %u overflows!\n", val);
+               return U32_MAX;
+       }
+
+       return ((val >> 10) * 15625) +
+               (val & GENMASK(9, 0)) * 15625 / 1024;
+}
+
 u32 ccs_reg_conv(struct ccs_sensor *sensor, u32 reg, u32 val)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
 
-       if (reg & CCS_FL_FLOAT_IREAL)
-               val = float_to_u32_mul_1000000(client, val);
+       if (reg & CCS_FL_FLOAT_IREAL) {
+               if (CCS_LIM(sensor, CLOCK_CAPA_TYPE_CAPABILITY) &
+                   CCS_CLOCK_CAPA_TYPE_CAPABILITY_IREAL)
+                       val = ireal32_to_u32_mul_1000000(client, val);
+               else
+                       val = float_to_u32_mul_1000000(client, val);
+       } else if (reg & CCS_FL_IREAL) {
+               val = ireal32_to_u32_mul_1000000(client, val);
+       }
 
        return val;
 }
index cbcd93b..f60d180 100644 (file)
@@ -17,6 +17,7 @@
 #include <media/v4l2-subdev.h>
 
 #include "ccs-data.h"
+#include "ccs-limits.h"
 #include "ccs-quirk.h"
 #include "ccs-regs.h"
 #include "ccs-reg-access.h"
 #define CCS_DFL_I2C_ADDR       (0x20 >> 1) /* Default I2C Address */
 #define CCS_ALT_I2C_ADDR       (0x6e >> 1) /* Alternate I2C Address */
 
+#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))
+
 /*
  * Sometimes due to board layout considerations the camera module can be
  * mounted rotated. The typical rotation used is 180 degrees which can be
@@ -277,5 +284,7 @@ struct ccs_sensor {
 
 void ccs_replace_limit(struct ccs_sensor *sensor,
                       unsigned int limit, unsigned int offset, u32 val);
+u32 ccs_get_limit(struct ccs_sensor *sensor, unsigned int limit,
+                 unsigned int offset);
 
 #endif /* __CCS_H__ */