summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorHugues Fruchet <hugues.fruchet@st.com>2018-06-18 12:29:19 +0200
committerMauro Carvalho Chehab <mchehab+samsung@kernel.org>2018-06-28 14:45:56 +0200
commitc3f3ba3e6f78ea2159fca284e18840c6b3c1bfb6 (patch)
tree8f24c3acae493d61f9f81f030c8ce676f5d5955b /drivers
parentmedia: dt-bindings: ov5640: Add "rotation" property (diff)
downloadlinux-c3f3ba3e6f78ea2159fca284e18840c6b3c1bfb6.tar.xz
linux-c3f3ba3e6f78ea2159fca284e18840c6b3c1bfb6.zip
media: ov5640: add support of module orientation
Add support of module being physically mounted upside down. In this case, mirror and flip are enabled to fix captured images orientation. [Sakari Ailus: Use dev_fwnode() instead of accessing device's of_node] Signed-off-by: Hugues Fruchet <hugues.fruchet@st.com> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/i2c/ov5640.c28
1 files changed, 26 insertions, 2 deletions
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 41039e535499..9e1078632375 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -215,6 +215,7 @@ struct ov5640_dev {
struct regulator_bulk_data supplies[OV5640_NUM_SUPPLIES];
struct gpio_desc *reset_gpio;
struct gpio_desc *pwdn_gpio;
+ bool upside_down;
/* lock to protect all members below */
struct mutex lock;
@@ -2222,6 +2223,8 @@ static int ov5640_set_ctrl_light_freq(struct ov5640_dev *sensor, int value)
static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
{
/*
+ * If sensor is mounted upside down, mirror logic is inversed.
+ *
* Sensor is a BSI (Back Side Illuminated) one,
* so image captured is physically mirrored.
* This is why mirror logic is inversed in
@@ -2235,11 +2238,14 @@ static int ov5640_set_ctrl_hflip(struct ov5640_dev *sensor, int value)
*/
return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG21,
BIT(2) | BIT(1),
- (!value) ? (BIT(2) | BIT(1)) : 0);
+ (!(value ^ sensor->upside_down)) ?
+ (BIT(2) | BIT(1)) : 0);
}
static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
{
+ /* If sensor is mounted upside down, flip logic is inversed */
+
/*
* TIMING TC REG20:
* - [2]: ISP vflip
@@ -2247,7 +2253,8 @@ static int ov5640_set_ctrl_vflip(struct ov5640_dev *sensor, int value)
*/
return ov5640_mod_reg(sensor, OV5640_REG_TIMING_TC_REG20,
BIT(2) | BIT(1),
- value ? (BIT(2) | BIT(1)) : 0);
+ (value ^ sensor->upside_down) ?
+ (BIT(2) | BIT(1)) : 0);
}
static int ov5640_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
@@ -2625,6 +2632,7 @@ static int ov5640_probe(struct i2c_client *client,
struct fwnode_handle *endpoint;
struct ov5640_dev *sensor;
struct v4l2_mbus_framefmt *fmt;
+ u32 rotation;
int ret;
sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
@@ -2650,6 +2658,22 @@ static int ov5640_probe(struct i2c_client *client,
sensor->ae_target = 52;
+ /* optional indication of physical rotation of sensor */
+ ret = fwnode_property_read_u32(dev_fwnode(&client->dev), "rotation",
+ &rotation);
+ if (!ret) {
+ switch (rotation) {
+ case 180:
+ sensor->upside_down = true;
+ /* fall through */
+ case 0:
+ break;
+ default:
+ dev_warn(dev, "%u degrees rotation is not supported, ignoring...\n",
+ rotation);
+ }
+ }
+
endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev),
NULL);
if (!endpoint) {