diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt index f884ada0bffc88..3920f25a912356 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -85,10 +85,374 @@ Optional properties - lens-focus: A phandle to the node of the focus lens controller. -- rotation: The device, typically an image sensor, is not mounted upright, - but a number of degrees counter clockwise. Typical values are 0 and 180 - (upside down). - +- rotation: The camera rotation is expressed as the angular difference in + degrees between two reference systems, one relative to the camera module, and + one defined on the external world scene to be captured when projected on the + image sensor pixel array. + + A camera sensor has a 2-dimensional reference system 'Rc' defined by + its pixel array read-out order. The origin is set to the first pixel + being read out, the X-axis points along the column read-out direction + towards the last columns, and the Y-axis along the row read-out + direction towards the last row. + + A typical example for a sensor with a 2592x1944 pixel array matrix + observed from the front is: + + 2591 X-axis 0 + <------------------------+ 0 + .......... ... ..........! + .......... ... ..........! Y-axis + ... ! + .......... ... ..........! + .......... ... ..........! 1943 + V + + The external world scene reference system 'Rs' is a 2-dimensional + reference system on the focal plane of the camera module. The origin is + placed on the top-left corner of the visible scene, the X-axis points + towards the right, and the Y-axis points towards the bottom of the + scene. The top, bottom, left and right directions are intentionally not + defined and depend on the environment in which the camera is used. + + A typical example of a (very common) picture of a shark swimming from + left to right, as seen from the camera, is: + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\____)\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + + with the reference system 'Rs' placed on the camera focal plane: + + ¸.·˙! + ¸.·˙ ! + _ ¸.·˙ ! + +-/ \-+¸.·˙ ! + | (o) | ! Camera focal plane + +-----+˙·.¸ ! + ˙·.¸ ! + ˙·.¸ ! + ˙·.¸! + + When projected on the sensor's pixel array, the image and the associated + reference system 'Rs' are typically (but not always) inverted, due to + the camera module's lens optical inversion effect. + + Assuming the above represented scene of the swimming shark, the lens + inversion projects the scene and its reference system onto the sensor + pixel array, seen from the front of the camera sensor, as follows: + + Y-axis + ^ + ! + ! + ! + ! |\_____)\__ + ! ) ____ ___.< + ! |/ )/ + ! + ! + ! + 0 +-------------------------------------> + 0 X-axis + + Note the shark being upside-down. + + The resulting projected reference system is named 'Rp'. + + The camera rotation property is then defined as the angular difference + in the counter-clockwise direction between the camera reference system + 'Rc' and the projected scene reference system 'Rp'. It is expressed in + degrees as a number in the range [0, 360[. + + Examples + + 0 degrees camera rotation: + + + Y-Rp + ^ + Y-Rc ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + + X-Rc 0 + <------------------------------------+ 0 + X-Rp 0 ! + <------------------------------------+ 0 ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + V + Y-Rp + + 90 degrees camera rotation: + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + 180 degrees camera rotation: + + 0 + <------------------------------------+ 0 + X-Rc ! + Y-Rp ! + ^ ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + 270 degrees camera rotation: + + 0 Y-Rc + 0 +--------------------> + ! 0 + ! <-----------------------------------+ 0 + ! X-Rp ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! ! + ! V + ! Y-Rp + ! + ! + ! + ! + V + X-Rc + + + Example one - Webcam + + A camera module installed on the user facing part of a laptop screen + casing used for video calls. The captured images are meant to be + displayed in landscape mode (width > height) on the laptop screen. + + The camera is typically mounted upside-down to compensate the lens + optical inversion effect: + + Y-Rp + Y-Rc ^ + ^ ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + 0 +-------------------------------------> + 0 X-Rc + + The two reference systems are aligned, the resulting camera rotation is + 0 degrees, no rotation correction needs to be applied to the resulting + image once captured to memory buffers to correctly display it to users: + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + If the camera sensor is not mounted upside-down to compensate for the + lens optical inversion, the two reference systems will not be aligned, + with 'Rp' being rotated 180 degrees relatively to 'Rc': + + + X-Rc 0 + <------------------------------------+ 0 + ! + Y-Rp ! + ^ ! + ! ! + ! |\_____)\__ ! + ! ) ____ ___.< ! + ! |/ )/ ! + ! ! + ! ! + ! V + ! Y-Rc + 0 +-------------------------------------> + 0 X-Rp + + The image once captured to memory will then be rotated by 180 degrees: + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \( \| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + A software rotation correction of 180 degrees should be applied to + correctly display the image: + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + Example two - Phone camera + + A camera installed on the back side of a mobile device facing away from + the user. The captured images are meant to be displayed in portrait mode + (height > width) to match the device screen orientation and the device + usage orientation used when taking the picture. + + The camera sensor is typically mounted with its pixel array longer side + aligned to the device longer side, upside-down mounted to compensate for + the lens optical inversion effect: + + 0 Y-Rc + 0 +--------------------> + ! Y-Rp + ! ^ + ! ! + ! ! + ! ! + ! ! |\_____)\__ + ! ! ) ____ ___.< + ! ! |/ )/ + ! ! + ! ! + ! ! + ! 0 +-------------------------------------> + ! 0 X-Rp + ! + ! + ! + ! + V + X-Rc + + The two reference systems are not aligned and the 'Rp' reference + system is rotated by 90 degrees in the counter-clockwise direction + relatively to the 'Rc' reference system. + + The image once captured to memory will be rotated: + + +-------------------------------------+ + | _ _ | + | \ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + + A correction of 90 degrees in counter-clockwise direction has to be + applied to correctly display the image in portrait mode on the device + screen: + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\____)\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ + +- orientation: The orientation of a device (typically an image sensor or a flash + LED) describing its mounting position relative to the usage orientation of the + system where the device is installed on. + Possible values are: + 0 - Front. The device is mounted on the front facing side of the system. + For mobile devices such as smartphones, tablets and laptops the front side is + the user facing side. + 1 - Back. The device is mounted on the back side of the system, which is + defined as the opposite side of the front facing one. + 2 - External. The device is not attached directly to the system but is + attached in a way that allows it to move freely. Optional endpoint properties ---------------------------- diff --git a/Documentation/media/uapi/v4l/ext-ctrls-camera.rst b/Documentation/media/uapi/v4l/ext-ctrls-camera.rst index 51c1d5c9eb0026..e64c1b2c01e843 100644 --- a/Documentation/media/uapi/v4l/ext-ctrls-camera.rst +++ b/Documentation/media/uapi/v4l/ext-ctrls-camera.rst @@ -510,6 +510,157 @@ enum v4l2_scene_mode - value down. A value of zero stops the motion if one is in progress and has no effect otherwise. +``V4L2_CID_CAMERA_ORIENTATION (menu)`` + This read-only control describes the camera orientation by reporting its + mounting position on the device where the camera is installed. The control + value is constant and not modifiable by software. This control is + particularly meaningful for devices which have a well defined orientation, + such as phones, laptops and portable devices since the control is expressed + as a position relative to the device's intended usage orientation. For + example, a camera installed on the user-facing side of a phone, a tablet or + a laptop device is said to be have ``V4L2_CAMERA_ORIENTATION_FRONT`` + orientation, while a camera installed on the opposite side of the front one + is said to be have ``V4L2_CAMERA_ORIENTATION_BACK`` orientation. Camera + sensors not directly attached to the device, or attached in a way that + allows them to move freely, such as webcams and digital cameras, are said to + have the ``V4L2_CAMERA_ORIENTATION_EXTERNAL`` orientation. + + + +.. flat-table:: + :header-rows: 0 + :stub-columns: 0 + + * - ``V4L2_CAMERA_ORIENTATION_FRONT`` + - The camera is oriented towards the user facing side of the device. + * - ``V4L2_CAMERA_ORIENTATION_BACK`` + - The camera is oriented towards the back facing side of the device. + * - ``V4L2_CAMERA_ORIENTATION_EXTERNAL`` + - The camera is not directly attached to the device and is freely movable. + + + +``V4L2_CID_CAMERA_SENSOR_ROTATION (integer)`` + This read-only control describes the rotation correction in degrees in the + counter-clockwise direction to be applied to the captured images once + captured to memory to compensate for the camera sensor mounting rotation. + + For a precise definition of the sensor mounting rotation refer to the + extensive description of the 'rotation' properties in the device tree + bindings file 'video-interfaces.txt'. + + A few examples are below reported, using a shark swimming from left to + right in front of the user as the example scene to capture. :: + + 0 X-axis + 0 +-------------------------------------> + ! + ! + ! + ! |\____)\___ + ! ) _____ __`< + ! |/ )/ + ! + ! + ! + V + Y-axis + + Example one - Webcam + + Assuming you can bring your laptop with you while swimming with sharks, + the camera module of the laptop is installed on the user facing part of a + laptop screen casing, and is typically used for video calls. The captured + images are meant to be displayed in landscape mode (width > height) on the + laptop screen. + + The camera is typically mounted upside-down to compensate the lens optical + inversion effect. In this case the value of the + V4L2_CID_CAMERA_SENSOR_ROTATION control is 0, no rotation is required to + display images correctly to the user. + + If the camera sensor is not mounted upside-down it is required to compensate + the lens optical inversion effect and the value of the + V4L2_CID_CAMERA_SENSOR_ROTATION control is 180 degrees, as images will + result rotated when captured to memory. :: + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! __/(_____/| ! + ! >.___ ____ ( ! + ! \( \| ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + A software rotation correction of 180 degrees has to be applied to correctly + display the image on the user screen. :: + + +--------------------------------------+ + ! ! + ! ! + ! ! + ! |\____)\___ ! + ! ) _____ __`< ! + ! |/ )/ ! + ! ! + ! ! + ! ! + +--------------------------------------+ + + Example two - Phone camera + + It is more handy to go and swim with sharks with only your mobile phone + with you and take pictures with the camera that is installed on the back + side of the device, facing away from the user. The captured images are meant + to be displayed in portrait mode (height > width) to match the device screen + orientation and the device usage orientation used when taking the picture. + + The camera sensor is typically mounted with its pixel array longer side + aligned to the device longer side, upside-down mounted to compensate for + the lens optical inversion effect. + + The images once captured to memory will be rotated and the value of the + V4L2_CID_CAMERA_SENSOR_ROTATION will report a 90 degree rotation. :: + + + +-------------------------------------+ + | _ _ | + | \ / | + | | | | + | | | | + | | > | + | < | | + | | | | + | . | + | V | + +-------------------------------------+ + + A correction of 90 degrees in counter-clockwise direction has to be + applied to correctly display the image in portrait mode on the device + screen. :: + + +--------------------+ + | | + | | + | | + | | + | | + | | + | |\____)\___ | + | ) _____ __`< | + | |/ )/ | + | | + | | + | | + | | + | | + +--------------------+ + + .. [#f1] This control may be changed to a menu control in the future, if more options are required. diff --git a/arch/arm/boot/dts/overlays/README b/arch/arm/boot/dts/overlays/README index eb561ef272e0f9..69892d01faae1f 100644 --- a/arch/arm/boot/dts/overlays/README +++ b/arch/arm/boot/dts/overlays/README @@ -1433,8 +1433,9 @@ Name: imx219 Info: Sony IMX219 camera module. Uses Unicam 1, which is the standard camera connector on most Pi variants. -Load: dtoverlay=imx219 -Params: +Load: dtoverlay=imx219,= +Params: rotation Mounting rotation of the camera sensor (0 or + 180, default 180) Name: imx290 @@ -1457,8 +1458,9 @@ Name: imx477 Info: Sony IMX477 camera module. Uses Unicam 1, which is the standard camera connector on most Pi variants. -Load: dtoverlay=imx477 -Params: +Load: dtoverlay=imx477,= +Params: rotation Mounting rotation of the camera sensor (0 or + 180, default 180) Name: iqaudio-codec @@ -1809,8 +1811,9 @@ Name: ov5647 Info: Omnivision OV5647 camera module. Uses Unicam 1, which is the standard camera connector on most Pi variants. -Load: dtoverlay=ov5647 -Params: +Load: dtoverlay=ov5647,= +Params: rotation Mounting rotation of the camera sensor (0 or + 180, default 0) Name: ov7251 diff --git a/arch/arm/boot/dts/overlays/imx219-overlay.dts b/arch/arm/boot/dts/overlays/imx219-overlay.dts index 3c2d3fac93d21f..dce07b335c4e87 100644 --- a/arch/arm/boot/dts/overlays/imx219-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx219-overlay.dts @@ -27,6 +27,8 @@ VDIG-supply = <&imx219_vdig>; /* 1.8v */ VDDL-supply = <&imx219_vddl>; /* 1.2v */ + rotation = <180>; + port { imx219_0: endpoint { remote-endpoint = <&csi1_ep>; @@ -110,4 +112,8 @@ cam0-pwdn = <&imx219_vana>,"gpio:4"; }; }; + + __overrides__ { + rotation = <&imx219>,"rotation:0"; + }; }; diff --git a/arch/arm/boot/dts/overlays/imx477-overlay.dts b/arch/arm/boot/dts/overlays/imx477-overlay.dts index 73d4f79d54e6f9..1a97eaaf4c8266 100644 --- a/arch/arm/boot/dts/overlays/imx477-overlay.dts +++ b/arch/arm/boot/dts/overlays/imx477-overlay.dts @@ -27,6 +27,8 @@ VDIG-supply = <&imx477_vdig>; /* 1.05v */ VDDL-supply = <&imx477_vddl>; /* 1.8v */ + rotation = <180>; + port { imx477_0: endpoint { remote-endpoint = <&csi1_ep>; @@ -110,4 +112,8 @@ cam0-pwdn = <&imx477_vana>,"gpio:4"; }; }; + + __overrides__ { + rotation = <&imx477>,"rotation:0"; + }; }; diff --git a/arch/arm/boot/dts/overlays/ov5647-overlay.dts b/arch/arm/boot/dts/overlays/ov5647-overlay.dts index 5eba3cb9fb91d5..fd1e7a457f697f 100644 --- a/arch/arm/boot/dts/overlays/ov5647-overlay.dts +++ b/arch/arm/boot/dts/overlays/ov5647-overlay.dts @@ -21,6 +21,8 @@ pwdn-gpios = <&gpio 41 1>, <&gpio 32 1>; clocks = <&ov5647_clk>; + rotation = <0>; + port { ov5647_0: endpoint { remote-endpoint = <&csi1_ep>; @@ -83,4 +85,8 @@ }; }; }; + + __overrides__ { + rotation = <&ov5647>,"rotation:0"; + }; }; diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c index b84fc19e9ff75e..812323107f36c5 100644 --- a/drivers/media/i2c/imx219.c +++ b/drivers/media/i2c/imx219.c @@ -1348,11 +1348,12 @@ static int imx219_init_controls(struct imx219 *imx219) struct i2c_client *client = v4l2_get_subdevdata(&imx219->sd); struct v4l2_ctrl_handler *ctrl_hdlr; unsigned int height = imx219->mode->height; + struct v4l2_fwnode_device_properties props; int exposure_max, exposure_def, hblank; int i, ret; ctrl_hdlr = &imx219->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 11); if (ret) return ret; @@ -1431,6 +1432,15 @@ static int imx219_init_controls(struct imx219 *imx219) goto error; } + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx219_ctrl_ops, + &props); + if (ret) + goto error; + imx219->sd.ctrl_handler = ctrl_hdlr; return 0; diff --git a/drivers/media/i2c/imx477.c b/drivers/media/i2c/imx477.c index e42a8633087d49..3fbb173fa07967 100644 --- a/drivers/media/i2c/imx477.c +++ b/drivers/media/i2c/imx477.c @@ -1957,11 +1957,12 @@ static int imx477_init_controls(struct imx477 *imx477) { struct v4l2_ctrl_handler *ctrl_hdlr; struct i2c_client *client = v4l2_get_subdevdata(&imx477->sd); + struct v4l2_fwnode_device_properties props; unsigned int i; int ret; ctrl_hdlr = &imx477->ctrl_handler; - ret = v4l2_ctrl_handler_init(ctrl_hdlr, 14); + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); if (ret) return ret; @@ -2045,6 +2046,15 @@ static int imx477_init_controls(struct imx477 *imx477) goto error; } + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx477_ctrl_ops, + &props); + if (ret) + goto error; + imx477->sd.ctrl_handler = ctrl_hdlr; /* Setup exposure and frame/line length limits. */ diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c index 6d84d2785f7409..86a821a172b3d1 100644 --- a/drivers/media/i2c/ov5647.c +++ b/drivers/media/i2c/ov5647.c @@ -1501,6 +1501,7 @@ static int ov5647_probe(struct i2c_client *client) struct device_node *np = client->dev.of_node; u32 xclk_freq; int hblank, exposure_max, exposure_def; + struct v4l2_fwnode_device_properties props; sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL); if (!sensor) @@ -1534,7 +1535,7 @@ static int ov5647_probe(struct i2c_client *client) mutex_init(&sensor->lock); /* Initialise controls. */ - v4l2_ctrl_handler_init(&sensor->ctrls, 7); + v4l2_ctrl_handler_init(&sensor->ctrls, 9); v4l2_ctrl_new_std(&sensor->ctrls, &ov5647_ctrl_ops, V4L2_CID_AUTOGAIN, 0, /* min */ @@ -1598,6 +1599,16 @@ static int ov5647_probe(struct i2c_client *client) __func__, ret); goto error; } + + ret = v4l2_fwnode_device_parse(&client->dev, &props); + if (ret) + goto error; + + ret = v4l2_ctrl_new_fwnode_properties(&sensor->ctrls, &ov5647_ctrl_ops, + &props); + if (ret) + goto error; + sensor->sd.ctrl_handler = &sensor->ctrls; /* Write out the register set over I2C on stream-on. */ diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c index 4f15335636550c..e0cac7f3d96085 100644 --- a/drivers/media/v4l2-core/v4l2-ctrls.c +++ b/drivers/media/v4l2-core/v4l2-ctrls.c @@ -17,6 +17,7 @@ #include #include #include +#include #define dprintk(vdev, fmt, arg...) do { \ if (!WARN_ON(!(vdev)) && ((vdev)->dev_debug & V4L2_DEV_DEBUG_CTRL)) \ @@ -577,6 +578,12 @@ const char * const *v4l2_ctrl_get_menu(u32 id) "Annex B Start Code", NULL, }; + static const char * const camera_orientation[] = { + "Front", + "Back", + "External", + NULL, + }; switch (id) { case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: @@ -702,6 +709,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id) return hevc_decode_mode; case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: return hevc_start_code; + case V4L2_CID_CAMERA_ORIENTATION: + return camera_orientation; default: return NULL; } @@ -1015,6 +1024,8 @@ const char *v4l2_ctrl_get_name(u32 id) case V4L2_CID_PAN_SPEED: return "Pan, Speed"; case V4L2_CID_TILT_SPEED: return "Tilt, Speed"; case V4L2_CID_UNIT_CELL_SIZE: return "Unit Cell Size"; + case V4L2_CID_CAMERA_ORIENTATION: return "Camera Orientation"; + case V4L2_CID_CAMERA_SENSOR_ROTATION: return "Camera Sensor Rotation"; /* FM Radio Modulator controls */ /* Keep the order of the 'case's the same as in v4l2-controls.h! */ @@ -1288,6 +1299,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_MPEG_VIDEO_HEVC_LOOP_FILTER_MODE: case V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE: case V4L2_CID_MPEG_VIDEO_HEVC_START_CODE: + case V4L2_CID_CAMERA_ORIENTATION: *type = V4L2_CTRL_TYPE_MENU; break; case V4L2_CID_LINK_FREQ: @@ -1480,6 +1492,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type, case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM: case V4L2_CID_RDS_RX_MUSIC_SPEECH: + case V4L2_CID_CAMERA_ORIENTATION: + case V4L2_CID_CAMERA_SENSOR_ROTATION: *flags |= V4L2_CTRL_FLAG_READ_ONLY; break; case V4L2_CID_RF_TUNER_PLL_LOCK: @@ -4564,3 +4578,42 @@ __poll_t v4l2_ctrl_poll(struct file *file, struct poll_table_struct *wait) return 0; } EXPORT_SYMBOL(v4l2_ctrl_poll); + +int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ctrl_ops, + const struct v4l2_fwnode_device_properties *p) +{ + if (p->orientation != V4L2_FWNODE_PROPERTY_UNSET) { + u32 orientation_ctrl; + + switch (p->orientation) { + case V4L2_FWNODE_ORIENTATION_FRONT: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_FRONT; + break; + case V4L2_FWNODE_ORIENTATION_BACK: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_BACK; + break; + case V4L2_FWNODE_ORIENTATION_EXTERNAL: + orientation_ctrl = V4L2_CAMERA_ORIENTATION_EXTERNAL; + break; + default: + return -EINVAL; + } + if (!v4l2_ctrl_new_std_menu(hdl, ctrl_ops, + V4L2_CID_CAMERA_ORIENTATION, + V4L2_CAMERA_ORIENTATION_EXTERNAL, 0, + orientation_ctrl)) + return hdl->error; + } + + if (p->rotation != V4L2_FWNODE_PROPERTY_UNSET) { + if (!v4l2_ctrl_new_std(hdl, ctrl_ops, + V4L2_CID_CAMERA_SENSOR_ROTATION, + p->rotation, p->rotation, 1, + p->rotation)) + return hdl->error; + } + + return hdl->error; +} +EXPORT_SYMBOL(v4l2_ctrl_new_fwnode_properties); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c index 3bd1888787eb3c..8560453563021c 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -595,6 +595,48 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link) } EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link); +int v4l2_fwnode_device_parse(struct device *dev, + struct v4l2_fwnode_device_properties *props) +{ + struct fwnode_handle *fwnode = dev_fwnode(dev); + u32 val; + int ret; + + memset(props, 0, sizeof(*props)); + + props->orientation = V4L2_FWNODE_PROPERTY_UNSET; + ret = fwnode_property_read_u32(fwnode, "orientation", &val); + if (!ret) { + switch (val) { + case V4L2_FWNODE_ORIENTATION_FRONT: + case V4L2_FWNODE_ORIENTATION_BACK: + case V4L2_FWNODE_ORIENTATION_EXTERNAL: + break; + default: + dev_warn(dev, "Unsupported device orientation: %u\n", val); + return -EINVAL; + } + + props->orientation = val; + dev_dbg(dev, "device orientation: %u\n", val); + } + + props->rotation = V4L2_FWNODE_PROPERTY_UNSET; + ret = fwnode_property_read_u32(fwnode, "rotation", &val); + if (!ret) { + if (val >= 360) { + dev_warn(dev, "Unsupported device rotation: %u\n", val); + return -EINVAL; + } + + props->rotation = val; + dev_dbg(dev, "device rotation: %u\n", val); + } + + return 0; +} +EXPORT_SYMBOL_GPL(v4l2_fwnode_device_parse); + static int v4l2_async_notifier_fwnode_parse_endpoint(struct device *dev, struct v4l2_async_notifier *notifier, diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h index 65575e9b5a2b12..162859aa213899 100644 --- a/include/media/v4l2-ctrls.h +++ b/include/media/v4l2-ctrls.h @@ -29,6 +29,7 @@ struct v4l2_ctrl_handler; struct v4l2_ctrl_helper; struct v4l2_ctrl; struct video_device; +struct v4l2_fwnode_device_properties; struct v4l2_subdev; struct v4l2_subscribed_event; struct v4l2_fh; @@ -1379,4 +1380,29 @@ int v4l2_ctrl_subdev_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, */ int v4l2_ctrl_subdev_log_status(struct v4l2_subdev *sd); +/** + * v4l2_ctrl_new_fwnode_properties() - Register controls for the device + * properties + * + * @hdl: pointer to &struct v4l2_ctrl_handler to register controls on + * @ctrl_ops: pointer to &struct v4l2_ctrl_ops to register controls with + * @p: pointer to &struct v4l2_fwnode_device_properties + * + * This function registers controls associated to device properties, using the + * property values contained in @p parameter, if the property has been set to + * a value. + * + * Currently the following v4l2 controls are parsed and registered: + * - V4L2_CID_CAMERA_ORIENTATION + * - V4L2_CID_CAMERA_SENSOR_ROTATION; + * + * Controls already registered by the caller with the @hdl control handler are + * not overwritten. Callers should register the controls they want to handle + * themselves before calling this function. + * + * Return: 0 on success, a negative error code on failure. + */ +int v4l2_ctrl_new_fwnode_properties(struct v4l2_ctrl_handler *hdl, + const struct v4l2_ctrl_ops *ctrl_ops, + const struct v4l2_fwnode_device_properties *p); #endif diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h index f6a7bcd1319779..7bb8da2092f69b 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -109,6 +109,36 @@ struct v4l2_fwnode_endpoint { unsigned int nr_of_link_frequencies; }; +/** + * V4L2_FWNODE_PROPERTY_UNSET - identify a non initialized property + * + * All properties in &struct v4l2_fwnode_device_properties are initialized + * to this value. + */ +#define V4L2_FWNODE_PROPERTY_UNSET (-1U) + +/** + * enum v4l2_fwnode_orientation - possible device orientation + * @V4L2_FWNODE_ORIENTATION_FRONT: device installed on the front side + * @V4L2_FWNODE_ORIENTATION_BACK: device installed on the back side + * @V4L2_FWNODE_ORIENTATION_EXTERNAL: device externally located + */ +enum v4l2_fwnode_orientation { + V4L2_FWNODE_ORIENTATION_FRONT, + V4L2_FWNODE_ORIENTATION_BACK, + V4L2_FWNODE_ORIENTATION_EXTERNAL +}; + +/** + * struct v4l2_fwnode_device_properties - fwnode device properties + * @orientation: device orientation. See &enum v4l2_fwnode_orientation + * @rotation: device rotation + */ +struct v4l2_fwnode_device_properties { + enum v4l2_fwnode_orientation orientation; + unsigned int rotation; +}; + /** * struct v4l2_fwnode_link - a link between two endpoints * @local_node: pointer to device_node of this endpoint @@ -233,6 +263,23 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode, */ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link); +/** + * v4l2_fwnode_device_parse() - parse fwnode device properties + * @dev: pointer to &struct device + * @props: pointer to &struct v4l2_fwnode_device_properties where to store the + * parsed properties values + * + * This function parses and validates the V4L2 fwnode device properties from the + * firmware interface, and fills the @struct v4l2_fwnode_device_properties + * provided by the caller. + * + * Return: + * % 0 on success + * %-EINVAL if a parsed property value is not valid + */ +int v4l2_fwnode_device_parse(struct device *dev, + struct v4l2_fwnode_device_properties *props); + /** * typedef parse_endpoint_func - Driver's callback function to be called on * each V4L2 fwnode endpoint. diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h index 660574b1b4e7ae..b6173d8c38f18d 100644 --- a/include/uapi/linux/v4l2-controls.h +++ b/include/uapi/linux/v4l2-controls.h @@ -917,6 +917,13 @@ enum v4l2_auto_focus_range { #define V4L2_CID_PAN_SPEED (V4L2_CID_CAMERA_CLASS_BASE+32) #define V4L2_CID_TILT_SPEED (V4L2_CID_CAMERA_CLASS_BASE+33) +#define V4L2_CID_CAMERA_ORIENTATION (V4L2_CID_CAMERA_CLASS_BASE+34) +#define V4L2_CAMERA_ORIENTATION_FRONT 0 +#define V4L2_CAMERA_ORIENTATION_BACK 1 +#define V4L2_CAMERA_ORIENTATION_EXTERNAL 2 + +#define V4L2_CID_CAMERA_SENSOR_ROTATION (V4L2_CID_CAMERA_CLASS_BASE+35) + /* FM Modulator class control IDs */ #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900)