143619059SRicardo Ribalda Delgado // SPDX-License-Identifier: GPL-2.0 243619059SRicardo Ribalda Delgado /* 343619059SRicardo Ribalda Delgado * imx214.c - imx214 sensor driver 443619059SRicardo Ribalda Delgado * 543619059SRicardo Ribalda Delgado * Copyright 2018 Qtechnology A/S 643619059SRicardo Ribalda Delgado * 743619059SRicardo Ribalda Delgado * Ricardo Ribalda <ricardo.ribalda@gmail.com> 843619059SRicardo Ribalda Delgado */ 943619059SRicardo Ribalda Delgado #include <linux/clk.h> 1043619059SRicardo Ribalda Delgado #include <linux/delay.h> 1143619059SRicardo Ribalda Delgado #include <linux/gpio/consumer.h> 1243619059SRicardo Ribalda Delgado #include <linux/i2c.h> 1343619059SRicardo Ribalda Delgado #include <linux/module.h> 1443619059SRicardo Ribalda Delgado #include <linux/pm_runtime.h> 1543619059SRicardo Ribalda Delgado #include <linux/regmap.h> 1643619059SRicardo Ribalda Delgado #include <linux/regulator/consumer.h> 1743619059SRicardo Ribalda Delgado #include <media/media-entity.h> 1843619059SRicardo Ribalda Delgado #include <media/v4l2-ctrls.h> 1943619059SRicardo Ribalda Delgado #include <media/v4l2-fwnode.h> 2043619059SRicardo Ribalda Delgado #include <media/v4l2-subdev.h> 2143619059SRicardo Ribalda Delgado 2243619059SRicardo Ribalda Delgado #define IMX214_DEFAULT_CLK_FREQ 24000000 2343619059SRicardo Ribalda Delgado #define IMX214_DEFAULT_LINK_FREQ 480000000 2443619059SRicardo Ribalda Delgado #define IMX214_DEFAULT_PIXEL_RATE ((IMX214_DEFAULT_LINK_FREQ * 8LL) / 10) 2543619059SRicardo Ribalda Delgado #define IMX214_FPS 30 2643619059SRicardo Ribalda Delgado #define IMX214_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10 2743619059SRicardo Ribalda Delgado 2843619059SRicardo Ribalda Delgado static const char * const imx214_supply_name[] = { 2943619059SRicardo Ribalda Delgado "vdda", 3043619059SRicardo Ribalda Delgado "vddd", 3143619059SRicardo Ribalda Delgado "vdddo", 3243619059SRicardo Ribalda Delgado }; 3343619059SRicardo Ribalda Delgado 3443619059SRicardo Ribalda Delgado #define IMX214_NUM_SUPPLIES ARRAY_SIZE(imx214_supply_name) 3543619059SRicardo Ribalda Delgado 3643619059SRicardo Ribalda Delgado struct imx214 { 3743619059SRicardo Ribalda Delgado struct device *dev; 3843619059SRicardo Ribalda Delgado struct clk *xclk; 3943619059SRicardo Ribalda Delgado struct regmap *regmap; 4043619059SRicardo Ribalda Delgado 4143619059SRicardo Ribalda Delgado struct v4l2_subdev sd; 4243619059SRicardo Ribalda Delgado struct media_pad pad; 4343619059SRicardo Ribalda Delgado struct v4l2_mbus_framefmt fmt; 4443619059SRicardo Ribalda Delgado struct v4l2_rect crop; 4543619059SRicardo Ribalda Delgado 4643619059SRicardo Ribalda Delgado struct v4l2_ctrl_handler ctrls; 4743619059SRicardo Ribalda Delgado struct v4l2_ctrl *pixel_rate; 4843619059SRicardo Ribalda Delgado struct v4l2_ctrl *link_freq; 4943619059SRicardo Ribalda Delgado struct v4l2_ctrl *exposure; 5043619059SRicardo Ribalda Delgado 5143619059SRicardo Ribalda Delgado struct regulator_bulk_data supplies[IMX214_NUM_SUPPLIES]; 5243619059SRicardo Ribalda Delgado 5343619059SRicardo Ribalda Delgado struct gpio_desc *enable_gpio; 5443619059SRicardo Ribalda Delgado 5543619059SRicardo Ribalda Delgado /* 5643619059SRicardo Ribalda Delgado * Serialize control access, get/set format, get selection 5743619059SRicardo Ribalda Delgado * and start streaming. 5843619059SRicardo Ribalda Delgado */ 5943619059SRicardo Ribalda Delgado struct mutex mutex; 6043619059SRicardo Ribalda Delgado 6143619059SRicardo Ribalda Delgado bool streaming; 6243619059SRicardo Ribalda Delgado }; 6343619059SRicardo Ribalda Delgado 6443619059SRicardo Ribalda Delgado struct reg_8 { 6543619059SRicardo Ribalda Delgado u16 addr; 6643619059SRicardo Ribalda Delgado u8 val; 6743619059SRicardo Ribalda Delgado }; 6843619059SRicardo Ribalda Delgado 6943619059SRicardo Ribalda Delgado enum { 7043619059SRicardo Ribalda Delgado IMX214_TABLE_WAIT_MS = 0, 7143619059SRicardo Ribalda Delgado IMX214_TABLE_END, 7243619059SRicardo Ribalda Delgado IMX214_MAX_RETRIES, 7343619059SRicardo Ribalda Delgado IMX214_WAIT_MS 7443619059SRicardo Ribalda Delgado }; 7543619059SRicardo Ribalda Delgado 7643619059SRicardo Ribalda Delgado /*From imx214_mode_tbls.h*/ 7743619059SRicardo Ribalda Delgado static const struct reg_8 mode_4096x2304[] = { 7843619059SRicardo Ribalda Delgado {0x0114, 0x03}, 7943619059SRicardo Ribalda Delgado {0x0220, 0x00}, 8043619059SRicardo Ribalda Delgado {0x0221, 0x11}, 8143619059SRicardo Ribalda Delgado {0x0222, 0x01}, 8243619059SRicardo Ribalda Delgado {0x0340, 0x0C}, 8343619059SRicardo Ribalda Delgado {0x0341, 0x7A}, 8443619059SRicardo Ribalda Delgado {0x0342, 0x13}, 8543619059SRicardo Ribalda Delgado {0x0343, 0x90}, 8643619059SRicardo Ribalda Delgado {0x0344, 0x00}, 8743619059SRicardo Ribalda Delgado {0x0345, 0x38}, 8843619059SRicardo Ribalda Delgado {0x0346, 0x01}, 8943619059SRicardo Ribalda Delgado {0x0347, 0x98}, 9043619059SRicardo Ribalda Delgado {0x0348, 0x10}, 9143619059SRicardo Ribalda Delgado {0x0349, 0x37}, 9243619059SRicardo Ribalda Delgado {0x034A, 0x0A}, 9343619059SRicardo Ribalda Delgado {0x034B, 0x97}, 9443619059SRicardo Ribalda Delgado {0x0381, 0x01}, 9543619059SRicardo Ribalda Delgado {0x0383, 0x01}, 9643619059SRicardo Ribalda Delgado {0x0385, 0x01}, 9743619059SRicardo Ribalda Delgado {0x0387, 0x01}, 9843619059SRicardo Ribalda Delgado {0x0900, 0x00}, 9943619059SRicardo Ribalda Delgado {0x0901, 0x00}, 10043619059SRicardo Ribalda Delgado {0x0902, 0x00}, 10143619059SRicardo Ribalda Delgado {0x3000, 0x35}, 10243619059SRicardo Ribalda Delgado {0x3054, 0x01}, 10343619059SRicardo Ribalda Delgado {0x305C, 0x11}, 10443619059SRicardo Ribalda Delgado 10543619059SRicardo Ribalda Delgado {0x0112, 0x0A}, 10643619059SRicardo Ribalda Delgado {0x0113, 0x0A}, 10743619059SRicardo Ribalda Delgado {0x034C, 0x10}, 10843619059SRicardo Ribalda Delgado {0x034D, 0x00}, 10943619059SRicardo Ribalda Delgado {0x034E, 0x09}, 11043619059SRicardo Ribalda Delgado {0x034F, 0x00}, 11143619059SRicardo Ribalda Delgado {0x0401, 0x00}, 11243619059SRicardo Ribalda Delgado {0x0404, 0x00}, 11343619059SRicardo Ribalda Delgado {0x0405, 0x10}, 11443619059SRicardo Ribalda Delgado {0x0408, 0x00}, 11543619059SRicardo Ribalda Delgado {0x0409, 0x00}, 11643619059SRicardo Ribalda Delgado {0x040A, 0x00}, 11743619059SRicardo Ribalda Delgado {0x040B, 0x00}, 11843619059SRicardo Ribalda Delgado {0x040C, 0x10}, 11943619059SRicardo Ribalda Delgado {0x040D, 0x00}, 12043619059SRicardo Ribalda Delgado {0x040E, 0x09}, 12143619059SRicardo Ribalda Delgado {0x040F, 0x00}, 12243619059SRicardo Ribalda Delgado 12343619059SRicardo Ribalda Delgado {0x0301, 0x05}, 12443619059SRicardo Ribalda Delgado {0x0303, 0x02}, 12543619059SRicardo Ribalda Delgado {0x0305, 0x03}, 12643619059SRicardo Ribalda Delgado {0x0306, 0x00}, 12743619059SRicardo Ribalda Delgado {0x0307, 0x96}, 12843619059SRicardo Ribalda Delgado {0x0309, 0x0A}, 12943619059SRicardo Ribalda Delgado {0x030B, 0x01}, 13043619059SRicardo Ribalda Delgado {0x0310, 0x00}, 13143619059SRicardo Ribalda Delgado 13243619059SRicardo Ribalda Delgado {0x0820, 0x12}, 13343619059SRicardo Ribalda Delgado {0x0821, 0xC0}, 13443619059SRicardo Ribalda Delgado {0x0822, 0x00}, 13543619059SRicardo Ribalda Delgado {0x0823, 0x00}, 13643619059SRicardo Ribalda Delgado 13743619059SRicardo Ribalda Delgado {0x3A03, 0x09}, 13843619059SRicardo Ribalda Delgado {0x3A04, 0x50}, 13943619059SRicardo Ribalda Delgado {0x3A05, 0x01}, 14043619059SRicardo Ribalda Delgado 14143619059SRicardo Ribalda Delgado {0x0B06, 0x01}, 14243619059SRicardo Ribalda Delgado {0x30A2, 0x00}, 14343619059SRicardo Ribalda Delgado 14443619059SRicardo Ribalda Delgado {0x30B4, 0x00}, 14543619059SRicardo Ribalda Delgado 14643619059SRicardo Ribalda Delgado {0x3A02, 0xFF}, 14743619059SRicardo Ribalda Delgado 14843619059SRicardo Ribalda Delgado {0x3011, 0x00}, 14943619059SRicardo Ribalda Delgado {0x3013, 0x01}, 15043619059SRicardo Ribalda Delgado 15143619059SRicardo Ribalda Delgado {0x0202, 0x0C}, 15243619059SRicardo Ribalda Delgado {0x0203, 0x70}, 15343619059SRicardo Ribalda Delgado {0x0224, 0x01}, 15443619059SRicardo Ribalda Delgado {0x0225, 0xF4}, 15543619059SRicardo Ribalda Delgado 15643619059SRicardo Ribalda Delgado {0x0204, 0x00}, 15743619059SRicardo Ribalda Delgado {0x0205, 0x00}, 15843619059SRicardo Ribalda Delgado {0x020E, 0x01}, 15943619059SRicardo Ribalda Delgado {0x020F, 0x00}, 16043619059SRicardo Ribalda Delgado {0x0210, 0x01}, 16143619059SRicardo Ribalda Delgado {0x0211, 0x00}, 16243619059SRicardo Ribalda Delgado {0x0212, 0x01}, 16343619059SRicardo Ribalda Delgado {0x0213, 0x00}, 16443619059SRicardo Ribalda Delgado {0x0214, 0x01}, 16543619059SRicardo Ribalda Delgado {0x0215, 0x00}, 16643619059SRicardo Ribalda Delgado {0x0216, 0x00}, 16743619059SRicardo Ribalda Delgado {0x0217, 0x00}, 16843619059SRicardo Ribalda Delgado 16943619059SRicardo Ribalda Delgado {0x4170, 0x00}, 17043619059SRicardo Ribalda Delgado {0x4171, 0x10}, 17143619059SRicardo Ribalda Delgado {0x4176, 0x00}, 17243619059SRicardo Ribalda Delgado {0x4177, 0x3C}, 17343619059SRicardo Ribalda Delgado {0xAE20, 0x04}, 17443619059SRicardo Ribalda Delgado {0xAE21, 0x5C}, 17543619059SRicardo Ribalda Delgado 17643619059SRicardo Ribalda Delgado {IMX214_TABLE_WAIT_MS, 10}, 17743619059SRicardo Ribalda Delgado {0x0138, 0x01}, 17843619059SRicardo Ribalda Delgado {IMX214_TABLE_END, 0x00} 17943619059SRicardo Ribalda Delgado }; 18043619059SRicardo Ribalda Delgado 18143619059SRicardo Ribalda Delgado static const struct reg_8 mode_1920x1080[] = { 18243619059SRicardo Ribalda Delgado {0x0114, 0x03}, 18343619059SRicardo Ribalda Delgado {0x0220, 0x00}, 18443619059SRicardo Ribalda Delgado {0x0221, 0x11}, 18543619059SRicardo Ribalda Delgado {0x0222, 0x01}, 18643619059SRicardo Ribalda Delgado {0x0340, 0x0C}, 18743619059SRicardo Ribalda Delgado {0x0341, 0x7A}, 18843619059SRicardo Ribalda Delgado {0x0342, 0x13}, 18943619059SRicardo Ribalda Delgado {0x0343, 0x90}, 19043619059SRicardo Ribalda Delgado {0x0344, 0x04}, 19143619059SRicardo Ribalda Delgado {0x0345, 0x78}, 19243619059SRicardo Ribalda Delgado {0x0346, 0x03}, 19343619059SRicardo Ribalda Delgado {0x0347, 0xFC}, 19443619059SRicardo Ribalda Delgado {0x0348, 0x0B}, 19543619059SRicardo Ribalda Delgado {0x0349, 0xF7}, 19643619059SRicardo Ribalda Delgado {0x034A, 0x08}, 19743619059SRicardo Ribalda Delgado {0x034B, 0x33}, 19843619059SRicardo Ribalda Delgado {0x0381, 0x01}, 19943619059SRicardo Ribalda Delgado {0x0383, 0x01}, 20043619059SRicardo Ribalda Delgado {0x0385, 0x01}, 20143619059SRicardo Ribalda Delgado {0x0387, 0x01}, 20243619059SRicardo Ribalda Delgado {0x0900, 0x00}, 20343619059SRicardo Ribalda Delgado {0x0901, 0x00}, 20443619059SRicardo Ribalda Delgado {0x0902, 0x00}, 20543619059SRicardo Ribalda Delgado {0x3000, 0x35}, 20643619059SRicardo Ribalda Delgado {0x3054, 0x01}, 20743619059SRicardo Ribalda Delgado {0x305C, 0x11}, 20843619059SRicardo Ribalda Delgado 20943619059SRicardo Ribalda Delgado {0x0112, 0x0A}, 21043619059SRicardo Ribalda Delgado {0x0113, 0x0A}, 21143619059SRicardo Ribalda Delgado {0x034C, 0x07}, 21243619059SRicardo Ribalda Delgado {0x034D, 0x80}, 21343619059SRicardo Ribalda Delgado {0x034E, 0x04}, 21443619059SRicardo Ribalda Delgado {0x034F, 0x38}, 21543619059SRicardo Ribalda Delgado {0x0401, 0x00}, 21643619059SRicardo Ribalda Delgado {0x0404, 0x00}, 21743619059SRicardo Ribalda Delgado {0x0405, 0x10}, 21843619059SRicardo Ribalda Delgado {0x0408, 0x00}, 21943619059SRicardo Ribalda Delgado {0x0409, 0x00}, 22043619059SRicardo Ribalda Delgado {0x040A, 0x00}, 22143619059SRicardo Ribalda Delgado {0x040B, 0x00}, 22243619059SRicardo Ribalda Delgado {0x040C, 0x07}, 22343619059SRicardo Ribalda Delgado {0x040D, 0x80}, 22443619059SRicardo Ribalda Delgado {0x040E, 0x04}, 22543619059SRicardo Ribalda Delgado {0x040F, 0x38}, 22643619059SRicardo Ribalda Delgado 22743619059SRicardo Ribalda Delgado {0x0301, 0x05}, 22843619059SRicardo Ribalda Delgado {0x0303, 0x02}, 22943619059SRicardo Ribalda Delgado {0x0305, 0x03}, 23043619059SRicardo Ribalda Delgado {0x0306, 0x00}, 23143619059SRicardo Ribalda Delgado {0x0307, 0x96}, 23243619059SRicardo Ribalda Delgado {0x0309, 0x0A}, 23343619059SRicardo Ribalda Delgado {0x030B, 0x01}, 23443619059SRicardo Ribalda Delgado {0x0310, 0x00}, 23543619059SRicardo Ribalda Delgado 23643619059SRicardo Ribalda Delgado {0x0820, 0x12}, 23743619059SRicardo Ribalda Delgado {0x0821, 0xC0}, 23843619059SRicardo Ribalda Delgado {0x0822, 0x00}, 23943619059SRicardo Ribalda Delgado {0x0823, 0x00}, 24043619059SRicardo Ribalda Delgado 24143619059SRicardo Ribalda Delgado {0x3A03, 0x04}, 24243619059SRicardo Ribalda Delgado {0x3A04, 0xF8}, 24343619059SRicardo Ribalda Delgado {0x3A05, 0x02}, 24443619059SRicardo Ribalda Delgado 24543619059SRicardo Ribalda Delgado {0x0B06, 0x01}, 24643619059SRicardo Ribalda Delgado {0x30A2, 0x00}, 24743619059SRicardo Ribalda Delgado 24843619059SRicardo Ribalda Delgado {0x30B4, 0x00}, 24943619059SRicardo Ribalda Delgado 25043619059SRicardo Ribalda Delgado {0x3A02, 0xFF}, 25143619059SRicardo Ribalda Delgado 25243619059SRicardo Ribalda Delgado {0x3011, 0x00}, 25343619059SRicardo Ribalda Delgado {0x3013, 0x01}, 25443619059SRicardo Ribalda Delgado 25543619059SRicardo Ribalda Delgado {0x0202, 0x0C}, 25643619059SRicardo Ribalda Delgado {0x0203, 0x70}, 25743619059SRicardo Ribalda Delgado {0x0224, 0x01}, 25843619059SRicardo Ribalda Delgado {0x0225, 0xF4}, 25943619059SRicardo Ribalda Delgado 26043619059SRicardo Ribalda Delgado {0x0204, 0x00}, 26143619059SRicardo Ribalda Delgado {0x0205, 0x00}, 26243619059SRicardo Ribalda Delgado {0x020E, 0x01}, 26343619059SRicardo Ribalda Delgado {0x020F, 0x00}, 26443619059SRicardo Ribalda Delgado {0x0210, 0x01}, 26543619059SRicardo Ribalda Delgado {0x0211, 0x00}, 26643619059SRicardo Ribalda Delgado {0x0212, 0x01}, 26743619059SRicardo Ribalda Delgado {0x0213, 0x00}, 26843619059SRicardo Ribalda Delgado {0x0214, 0x01}, 26943619059SRicardo Ribalda Delgado {0x0215, 0x00}, 27043619059SRicardo Ribalda Delgado {0x0216, 0x00}, 27143619059SRicardo Ribalda Delgado {0x0217, 0x00}, 27243619059SRicardo Ribalda Delgado 27343619059SRicardo Ribalda Delgado {0x4170, 0x00}, 27443619059SRicardo Ribalda Delgado {0x4171, 0x10}, 27543619059SRicardo Ribalda Delgado {0x4176, 0x00}, 27643619059SRicardo Ribalda Delgado {0x4177, 0x3C}, 27743619059SRicardo Ribalda Delgado {0xAE20, 0x04}, 27843619059SRicardo Ribalda Delgado {0xAE21, 0x5C}, 27943619059SRicardo Ribalda Delgado 28043619059SRicardo Ribalda Delgado {IMX214_TABLE_WAIT_MS, 10}, 28143619059SRicardo Ribalda Delgado {0x0138, 0x01}, 28243619059SRicardo Ribalda Delgado {IMX214_TABLE_END, 0x00} 28343619059SRicardo Ribalda Delgado }; 28443619059SRicardo Ribalda Delgado 28543619059SRicardo Ribalda Delgado static const struct reg_8 mode_table_common[] = { 28643619059SRicardo Ribalda Delgado /* software reset */ 28743619059SRicardo Ribalda Delgado 28843619059SRicardo Ribalda Delgado /* software standby settings */ 28943619059SRicardo Ribalda Delgado {0x0100, 0x00}, 29043619059SRicardo Ribalda Delgado 29143619059SRicardo Ribalda Delgado /* ATR setting */ 29243619059SRicardo Ribalda Delgado {0x9300, 0x02}, 29343619059SRicardo Ribalda Delgado 29443619059SRicardo Ribalda Delgado /* external clock setting */ 29543619059SRicardo Ribalda Delgado {0x0136, 0x18}, 29643619059SRicardo Ribalda Delgado {0x0137, 0x00}, 29743619059SRicardo Ribalda Delgado 29843619059SRicardo Ribalda Delgado /* global setting */ 29943619059SRicardo Ribalda Delgado /* basic config */ 30043619059SRicardo Ribalda Delgado {0x0101, 0x00}, 30143619059SRicardo Ribalda Delgado {0x0105, 0x01}, 30243619059SRicardo Ribalda Delgado {0x0106, 0x01}, 30343619059SRicardo Ribalda Delgado {0x4550, 0x02}, 30443619059SRicardo Ribalda Delgado {0x4601, 0x00}, 30543619059SRicardo Ribalda Delgado {0x4642, 0x05}, 30643619059SRicardo Ribalda Delgado {0x6227, 0x11}, 30743619059SRicardo Ribalda Delgado {0x6276, 0x00}, 30843619059SRicardo Ribalda Delgado {0x900E, 0x06}, 30943619059SRicardo Ribalda Delgado {0xA802, 0x90}, 31043619059SRicardo Ribalda Delgado {0xA803, 0x11}, 31143619059SRicardo Ribalda Delgado {0xA804, 0x62}, 31243619059SRicardo Ribalda Delgado {0xA805, 0x77}, 31343619059SRicardo Ribalda Delgado {0xA806, 0xAE}, 31443619059SRicardo Ribalda Delgado {0xA807, 0x34}, 31543619059SRicardo Ribalda Delgado {0xA808, 0xAE}, 31643619059SRicardo Ribalda Delgado {0xA809, 0x35}, 31743619059SRicardo Ribalda Delgado {0xA80A, 0x62}, 31843619059SRicardo Ribalda Delgado {0xA80B, 0x83}, 31943619059SRicardo Ribalda Delgado {0xAE33, 0x00}, 32043619059SRicardo Ribalda Delgado 32143619059SRicardo Ribalda Delgado /* analog setting */ 32243619059SRicardo Ribalda Delgado {0x4174, 0x00}, 32343619059SRicardo Ribalda Delgado {0x4175, 0x11}, 32443619059SRicardo Ribalda Delgado {0x4612, 0x29}, 32543619059SRicardo Ribalda Delgado {0x461B, 0x12}, 32643619059SRicardo Ribalda Delgado {0x461F, 0x06}, 32743619059SRicardo Ribalda Delgado {0x4635, 0x07}, 32843619059SRicardo Ribalda Delgado {0x4637, 0x30}, 32943619059SRicardo Ribalda Delgado {0x463F, 0x18}, 33043619059SRicardo Ribalda Delgado {0x4641, 0x0D}, 33143619059SRicardo Ribalda Delgado {0x465B, 0x12}, 33243619059SRicardo Ribalda Delgado {0x465F, 0x11}, 33343619059SRicardo Ribalda Delgado {0x4663, 0x11}, 33443619059SRicardo Ribalda Delgado {0x4667, 0x0F}, 33543619059SRicardo Ribalda Delgado {0x466F, 0x0F}, 33643619059SRicardo Ribalda Delgado {0x470E, 0x09}, 33743619059SRicardo Ribalda Delgado {0x4909, 0xAB}, 33843619059SRicardo Ribalda Delgado {0x490B, 0x95}, 33943619059SRicardo Ribalda Delgado {0x4915, 0x5D}, 34043619059SRicardo Ribalda Delgado {0x4A5F, 0xFF}, 34143619059SRicardo Ribalda Delgado {0x4A61, 0xFF}, 34243619059SRicardo Ribalda Delgado {0x4A73, 0x62}, 34343619059SRicardo Ribalda Delgado {0x4A85, 0x00}, 34443619059SRicardo Ribalda Delgado {0x4A87, 0xFF}, 34543619059SRicardo Ribalda Delgado 34643619059SRicardo Ribalda Delgado /* embedded data */ 34743619059SRicardo Ribalda Delgado {0x5041, 0x04}, 34843619059SRicardo Ribalda Delgado {0x583C, 0x04}, 34943619059SRicardo Ribalda Delgado {0x620E, 0x04}, 35043619059SRicardo Ribalda Delgado {0x6EB2, 0x01}, 35143619059SRicardo Ribalda Delgado {0x6EB3, 0x00}, 35243619059SRicardo Ribalda Delgado {0x9300, 0x02}, 35343619059SRicardo Ribalda Delgado 35443619059SRicardo Ribalda Delgado /* imagequality */ 35543619059SRicardo Ribalda Delgado /* HDR setting */ 35643619059SRicardo Ribalda Delgado {0x3001, 0x07}, 35743619059SRicardo Ribalda Delgado {0x6D12, 0x3F}, 35843619059SRicardo Ribalda Delgado {0x6D13, 0xFF}, 35943619059SRicardo Ribalda Delgado {0x9344, 0x03}, 36043619059SRicardo Ribalda Delgado {0x9706, 0x10}, 36143619059SRicardo Ribalda Delgado {0x9707, 0x03}, 36243619059SRicardo Ribalda Delgado {0x9708, 0x03}, 36343619059SRicardo Ribalda Delgado {0x9E04, 0x01}, 36443619059SRicardo Ribalda Delgado {0x9E05, 0x00}, 36543619059SRicardo Ribalda Delgado {0x9E0C, 0x01}, 36643619059SRicardo Ribalda Delgado {0x9E0D, 0x02}, 36743619059SRicardo Ribalda Delgado {0x9E24, 0x00}, 36843619059SRicardo Ribalda Delgado {0x9E25, 0x8C}, 36943619059SRicardo Ribalda Delgado {0x9E26, 0x00}, 37043619059SRicardo Ribalda Delgado {0x9E27, 0x94}, 37143619059SRicardo Ribalda Delgado {0x9E28, 0x00}, 37243619059SRicardo Ribalda Delgado {0x9E29, 0x96}, 37343619059SRicardo Ribalda Delgado 37443619059SRicardo Ribalda Delgado /* CNR parameter setting */ 37543619059SRicardo Ribalda Delgado {0x69DB, 0x01}, 37643619059SRicardo Ribalda Delgado 37743619059SRicardo Ribalda Delgado /* Moire reduction */ 37843619059SRicardo Ribalda Delgado {0x6957, 0x01}, 37943619059SRicardo Ribalda Delgado 38043619059SRicardo Ribalda Delgado /* image enhancment */ 38143619059SRicardo Ribalda Delgado {0x6987, 0x17}, 38243619059SRicardo Ribalda Delgado {0x698A, 0x03}, 38343619059SRicardo Ribalda Delgado {0x698B, 0x03}, 38443619059SRicardo Ribalda Delgado 38543619059SRicardo Ribalda Delgado /* white balanace */ 38643619059SRicardo Ribalda Delgado {0x0B8E, 0x01}, 38743619059SRicardo Ribalda Delgado {0x0B8F, 0x00}, 38843619059SRicardo Ribalda Delgado {0x0B90, 0x01}, 38943619059SRicardo Ribalda Delgado {0x0B91, 0x00}, 39043619059SRicardo Ribalda Delgado {0x0B92, 0x01}, 39143619059SRicardo Ribalda Delgado {0x0B93, 0x00}, 39243619059SRicardo Ribalda Delgado {0x0B94, 0x01}, 39343619059SRicardo Ribalda Delgado {0x0B95, 0x00}, 39443619059SRicardo Ribalda Delgado 39543619059SRicardo Ribalda Delgado /* ATR setting */ 39643619059SRicardo Ribalda Delgado {0x6E50, 0x00}, 39743619059SRicardo Ribalda Delgado {0x6E51, 0x32}, 39843619059SRicardo Ribalda Delgado {0x9340, 0x00}, 39943619059SRicardo Ribalda Delgado {0x9341, 0x3C}, 40043619059SRicardo Ribalda Delgado {0x9342, 0x03}, 40143619059SRicardo Ribalda Delgado {0x9343, 0xFF}, 40243619059SRicardo Ribalda Delgado {IMX214_TABLE_END, 0x00} 40343619059SRicardo Ribalda Delgado }; 40443619059SRicardo Ribalda Delgado 40543619059SRicardo Ribalda Delgado /* 40643619059SRicardo Ribalda Delgado * Declare modes in order, from biggest 40743619059SRicardo Ribalda Delgado * to smallest height. 40843619059SRicardo Ribalda Delgado */ 40943619059SRicardo Ribalda Delgado static const struct imx214_mode { 41043619059SRicardo Ribalda Delgado u32 width; 41143619059SRicardo Ribalda Delgado u32 height; 41243619059SRicardo Ribalda Delgado const struct reg_8 *reg_table; 41343619059SRicardo Ribalda Delgado } imx214_modes[] = { 41443619059SRicardo Ribalda Delgado { 41543619059SRicardo Ribalda Delgado .width = 4096, 41643619059SRicardo Ribalda Delgado .height = 2304, 41743619059SRicardo Ribalda Delgado .reg_table = mode_4096x2304, 41843619059SRicardo Ribalda Delgado }, 41943619059SRicardo Ribalda Delgado { 42043619059SRicardo Ribalda Delgado .width = 1920, 42143619059SRicardo Ribalda Delgado .height = 1080, 42243619059SRicardo Ribalda Delgado .reg_table = mode_1920x1080, 42343619059SRicardo Ribalda Delgado }, 42443619059SRicardo Ribalda Delgado }; 42543619059SRicardo Ribalda Delgado 42643619059SRicardo Ribalda Delgado static inline struct imx214 *to_imx214(struct v4l2_subdev *sd) 42743619059SRicardo Ribalda Delgado { 42843619059SRicardo Ribalda Delgado return container_of(sd, struct imx214, sd); 42943619059SRicardo Ribalda Delgado } 43043619059SRicardo Ribalda Delgado 43143619059SRicardo Ribalda Delgado static int __maybe_unused imx214_power_on(struct device *dev) 43243619059SRicardo Ribalda Delgado { 43343619059SRicardo Ribalda Delgado struct i2c_client *client = to_i2c_client(dev); 43443619059SRicardo Ribalda Delgado struct v4l2_subdev *sd = i2c_get_clientdata(client); 43543619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 43643619059SRicardo Ribalda Delgado int ret; 43743619059SRicardo Ribalda Delgado 43843619059SRicardo Ribalda Delgado ret = regulator_bulk_enable(IMX214_NUM_SUPPLIES, imx214->supplies); 43943619059SRicardo Ribalda Delgado if (ret < 0) { 44043619059SRicardo Ribalda Delgado dev_err(imx214->dev, "failed to enable regulators: %d\n", ret); 44143619059SRicardo Ribalda Delgado return ret; 44243619059SRicardo Ribalda Delgado } 44343619059SRicardo Ribalda Delgado 44443619059SRicardo Ribalda Delgado usleep_range(2000, 3000); 44543619059SRicardo Ribalda Delgado 44643619059SRicardo Ribalda Delgado ret = clk_prepare_enable(imx214->xclk); 44743619059SRicardo Ribalda Delgado if (ret < 0) { 44843619059SRicardo Ribalda Delgado regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies); 44943619059SRicardo Ribalda Delgado dev_err(imx214->dev, "clk prepare enable failed\n"); 45043619059SRicardo Ribalda Delgado return ret; 45143619059SRicardo Ribalda Delgado } 45243619059SRicardo Ribalda Delgado 45343619059SRicardo Ribalda Delgado gpiod_set_value_cansleep(imx214->enable_gpio, 1); 45443619059SRicardo Ribalda Delgado usleep_range(12000, 15000); 45543619059SRicardo Ribalda Delgado 45643619059SRicardo Ribalda Delgado return 0; 45743619059SRicardo Ribalda Delgado } 45843619059SRicardo Ribalda Delgado 45943619059SRicardo Ribalda Delgado static int __maybe_unused imx214_power_off(struct device *dev) 46043619059SRicardo Ribalda Delgado { 46143619059SRicardo Ribalda Delgado struct i2c_client *client = to_i2c_client(dev); 46243619059SRicardo Ribalda Delgado struct v4l2_subdev *sd = i2c_get_clientdata(client); 46343619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 46443619059SRicardo Ribalda Delgado 46543619059SRicardo Ribalda Delgado gpiod_set_value_cansleep(imx214->enable_gpio, 0); 46643619059SRicardo Ribalda Delgado 46743619059SRicardo Ribalda Delgado clk_disable_unprepare(imx214->xclk); 46843619059SRicardo Ribalda Delgado 46943619059SRicardo Ribalda Delgado regulator_bulk_disable(IMX214_NUM_SUPPLIES, imx214->supplies); 47043619059SRicardo Ribalda Delgado usleep_range(10, 20); 47143619059SRicardo Ribalda Delgado 47243619059SRicardo Ribalda Delgado return 0; 47343619059SRicardo Ribalda Delgado } 47443619059SRicardo Ribalda Delgado 47543619059SRicardo Ribalda Delgado static int imx214_enum_mbus_code(struct v4l2_subdev *sd, 47643619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 47743619059SRicardo Ribalda Delgado struct v4l2_subdev_mbus_code_enum *code) 47843619059SRicardo Ribalda Delgado { 47943619059SRicardo Ribalda Delgado if (code->index > 0) 48043619059SRicardo Ribalda Delgado return -EINVAL; 48143619059SRicardo Ribalda Delgado 48243619059SRicardo Ribalda Delgado code->code = IMX214_MBUS_CODE; 48343619059SRicardo Ribalda Delgado 48443619059SRicardo Ribalda Delgado return 0; 48543619059SRicardo Ribalda Delgado } 48643619059SRicardo Ribalda Delgado 48743619059SRicardo Ribalda Delgado static int imx214_enum_frame_size(struct v4l2_subdev *subdev, 48843619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 48943619059SRicardo Ribalda Delgado struct v4l2_subdev_frame_size_enum *fse) 49043619059SRicardo Ribalda Delgado { 49143619059SRicardo Ribalda Delgado if (fse->code != IMX214_MBUS_CODE) 49243619059SRicardo Ribalda Delgado return -EINVAL; 49343619059SRicardo Ribalda Delgado 49443619059SRicardo Ribalda Delgado if (fse->index >= ARRAY_SIZE(imx214_modes)) 49543619059SRicardo Ribalda Delgado return -EINVAL; 49643619059SRicardo Ribalda Delgado 49743619059SRicardo Ribalda Delgado fse->min_width = fse->max_width = imx214_modes[fse->index].width; 49843619059SRicardo Ribalda Delgado fse->min_height = fse->max_height = imx214_modes[fse->index].height; 49943619059SRicardo Ribalda Delgado 50043619059SRicardo Ribalda Delgado return 0; 50143619059SRicardo Ribalda Delgado } 50243619059SRicardo Ribalda Delgado 50343619059SRicardo Ribalda Delgado #ifdef CONFIG_VIDEO_ADV_DEBUG 50443619059SRicardo Ribalda Delgado static int imx214_s_register(struct v4l2_subdev *subdev, 50543619059SRicardo Ribalda Delgado const struct v4l2_dbg_register *reg) 50643619059SRicardo Ribalda Delgado { 50743619059SRicardo Ribalda Delgado struct imx214 *imx214 = container_of(subdev, struct imx214, sd); 50843619059SRicardo Ribalda Delgado 50943619059SRicardo Ribalda Delgado return regmap_write(imx214->regmap, reg->reg, reg->val); 51043619059SRicardo Ribalda Delgado } 51143619059SRicardo Ribalda Delgado 51243619059SRicardo Ribalda Delgado static int imx214_g_register(struct v4l2_subdev *subdev, 51343619059SRicardo Ribalda Delgado struct v4l2_dbg_register *reg) 51443619059SRicardo Ribalda Delgado { 51543619059SRicardo Ribalda Delgado struct imx214 *imx214 = container_of(subdev, struct imx214, sd); 51643619059SRicardo Ribalda Delgado unsigned int aux; 51743619059SRicardo Ribalda Delgado int ret; 51843619059SRicardo Ribalda Delgado 51943619059SRicardo Ribalda Delgado reg->size = 1; 52043619059SRicardo Ribalda Delgado ret = regmap_read(imx214->regmap, reg->reg, &aux); 52143619059SRicardo Ribalda Delgado reg->val = aux; 52243619059SRicardo Ribalda Delgado 52343619059SRicardo Ribalda Delgado return ret; 52443619059SRicardo Ribalda Delgado } 52543619059SRicardo Ribalda Delgado #endif 52643619059SRicardo Ribalda Delgado 52743619059SRicardo Ribalda Delgado static const struct v4l2_subdev_core_ops imx214_core_ops = { 52843619059SRicardo Ribalda Delgado #ifdef CONFIG_VIDEO_ADV_DEBUG 52943619059SRicardo Ribalda Delgado .g_register = imx214_g_register, 53043619059SRicardo Ribalda Delgado .s_register = imx214_s_register, 53143619059SRicardo Ribalda Delgado #endif 53243619059SRicardo Ribalda Delgado }; 53343619059SRicardo Ribalda Delgado 53443619059SRicardo Ribalda Delgado static struct v4l2_mbus_framefmt * 53543619059SRicardo Ribalda Delgado __imx214_get_pad_format(struct imx214 *imx214, 53643619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 53743619059SRicardo Ribalda Delgado unsigned int pad, 53843619059SRicardo Ribalda Delgado enum v4l2_subdev_format_whence which) 53943619059SRicardo Ribalda Delgado { 54043619059SRicardo Ribalda Delgado switch (which) { 54143619059SRicardo Ribalda Delgado case V4L2_SUBDEV_FORMAT_TRY: 54243619059SRicardo Ribalda Delgado return v4l2_subdev_get_try_format(&imx214->sd, cfg, pad); 54343619059SRicardo Ribalda Delgado case V4L2_SUBDEV_FORMAT_ACTIVE: 54443619059SRicardo Ribalda Delgado return &imx214->fmt; 54543619059SRicardo Ribalda Delgado default: 54643619059SRicardo Ribalda Delgado return NULL; 54743619059SRicardo Ribalda Delgado } 54843619059SRicardo Ribalda Delgado } 54943619059SRicardo Ribalda Delgado 55043619059SRicardo Ribalda Delgado static int imx214_get_format(struct v4l2_subdev *sd, 55143619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 55243619059SRicardo Ribalda Delgado struct v4l2_subdev_format *format) 55343619059SRicardo Ribalda Delgado { 55443619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 55543619059SRicardo Ribalda Delgado 55643619059SRicardo Ribalda Delgado mutex_lock(&imx214->mutex); 55743619059SRicardo Ribalda Delgado format->format = *__imx214_get_pad_format(imx214, cfg, format->pad, 55843619059SRicardo Ribalda Delgado format->which); 55943619059SRicardo Ribalda Delgado mutex_unlock(&imx214->mutex); 56043619059SRicardo Ribalda Delgado 56143619059SRicardo Ribalda Delgado return 0; 56243619059SRicardo Ribalda Delgado } 56343619059SRicardo Ribalda Delgado 56443619059SRicardo Ribalda Delgado static struct v4l2_rect * 56543619059SRicardo Ribalda Delgado __imx214_get_pad_crop(struct imx214 *imx214, struct v4l2_subdev_pad_config *cfg, 56643619059SRicardo Ribalda Delgado unsigned int pad, enum v4l2_subdev_format_whence which) 56743619059SRicardo Ribalda Delgado { 56843619059SRicardo Ribalda Delgado switch (which) { 56943619059SRicardo Ribalda Delgado case V4L2_SUBDEV_FORMAT_TRY: 57043619059SRicardo Ribalda Delgado return v4l2_subdev_get_try_crop(&imx214->sd, cfg, pad); 57143619059SRicardo Ribalda Delgado case V4L2_SUBDEV_FORMAT_ACTIVE: 57243619059SRicardo Ribalda Delgado return &imx214->crop; 57343619059SRicardo Ribalda Delgado default: 57443619059SRicardo Ribalda Delgado return NULL; 57543619059SRicardo Ribalda Delgado } 57643619059SRicardo Ribalda Delgado } 57743619059SRicardo Ribalda Delgado 57843619059SRicardo Ribalda Delgado static int imx214_set_format(struct v4l2_subdev *sd, 57943619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 58043619059SRicardo Ribalda Delgado struct v4l2_subdev_format *format) 58143619059SRicardo Ribalda Delgado { 58243619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 58343619059SRicardo Ribalda Delgado struct v4l2_mbus_framefmt *__format; 58443619059SRicardo Ribalda Delgado struct v4l2_rect *__crop; 58543619059SRicardo Ribalda Delgado const struct imx214_mode *mode; 58643619059SRicardo Ribalda Delgado 58743619059SRicardo Ribalda Delgado mutex_lock(&imx214->mutex); 58843619059SRicardo Ribalda Delgado 58943619059SRicardo Ribalda Delgado __crop = __imx214_get_pad_crop(imx214, cfg, format->pad, format->which); 59043619059SRicardo Ribalda Delgado 59143619059SRicardo Ribalda Delgado if (format) 59243619059SRicardo Ribalda Delgado mode = v4l2_find_nearest_size(imx214_modes, 59343619059SRicardo Ribalda Delgado ARRAY_SIZE(imx214_modes), width, height, 59443619059SRicardo Ribalda Delgado format->format.width, format->format.height); 59543619059SRicardo Ribalda Delgado else 59643619059SRicardo Ribalda Delgado mode = &imx214_modes[0]; 59743619059SRicardo Ribalda Delgado 59843619059SRicardo Ribalda Delgado __crop->width = mode->width; 59943619059SRicardo Ribalda Delgado __crop->height = mode->height; 60043619059SRicardo Ribalda Delgado 60143619059SRicardo Ribalda Delgado __format = __imx214_get_pad_format(imx214, cfg, format->pad, 60243619059SRicardo Ribalda Delgado format->which); 60343619059SRicardo Ribalda Delgado __format->width = __crop->width; 60443619059SRicardo Ribalda Delgado __format->height = __crop->height; 60543619059SRicardo Ribalda Delgado __format->code = IMX214_MBUS_CODE; 60643619059SRicardo Ribalda Delgado __format->field = V4L2_FIELD_NONE; 60743619059SRicardo Ribalda Delgado __format->colorspace = V4L2_COLORSPACE_SRGB; 60843619059SRicardo Ribalda Delgado __format->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(__format->colorspace); 60943619059SRicardo Ribalda Delgado __format->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(true, 61043619059SRicardo Ribalda Delgado __format->colorspace, __format->ycbcr_enc); 61143619059SRicardo Ribalda Delgado __format->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(__format->colorspace); 61243619059SRicardo Ribalda Delgado 61343619059SRicardo Ribalda Delgado format->format = *__format; 61443619059SRicardo Ribalda Delgado 61543619059SRicardo Ribalda Delgado mutex_unlock(&imx214->mutex); 61643619059SRicardo Ribalda Delgado 61743619059SRicardo Ribalda Delgado return 0; 61843619059SRicardo Ribalda Delgado } 61943619059SRicardo Ribalda Delgado 62043619059SRicardo Ribalda Delgado static int imx214_get_selection(struct v4l2_subdev *sd, 62143619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 62243619059SRicardo Ribalda Delgado struct v4l2_subdev_selection *sel) 62343619059SRicardo Ribalda Delgado { 62443619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 62543619059SRicardo Ribalda Delgado 62643619059SRicardo Ribalda Delgado if (sel->target != V4L2_SEL_TGT_CROP) 62743619059SRicardo Ribalda Delgado return -EINVAL; 62843619059SRicardo Ribalda Delgado 62943619059SRicardo Ribalda Delgado mutex_lock(&imx214->mutex); 63043619059SRicardo Ribalda Delgado sel->r = *__imx214_get_pad_crop(imx214, cfg, sel->pad, 63143619059SRicardo Ribalda Delgado sel->which); 63243619059SRicardo Ribalda Delgado mutex_unlock(&imx214->mutex); 63343619059SRicardo Ribalda Delgado return 0; 63443619059SRicardo Ribalda Delgado } 63543619059SRicardo Ribalda Delgado 63643619059SRicardo Ribalda Delgado static int imx214_entity_init_cfg(struct v4l2_subdev *subdev, 63743619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg) 63843619059SRicardo Ribalda Delgado { 63943619059SRicardo Ribalda Delgado struct v4l2_subdev_format fmt = { }; 64043619059SRicardo Ribalda Delgado 64143619059SRicardo Ribalda Delgado fmt.which = cfg ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE; 64243619059SRicardo Ribalda Delgado fmt.format.width = imx214_modes[0].width; 64343619059SRicardo Ribalda Delgado fmt.format.height = imx214_modes[0].height; 64443619059SRicardo Ribalda Delgado 64543619059SRicardo Ribalda Delgado imx214_set_format(subdev, cfg, &fmt); 64643619059SRicardo Ribalda Delgado 64743619059SRicardo Ribalda Delgado return 0; 64843619059SRicardo Ribalda Delgado } 64943619059SRicardo Ribalda Delgado 65043619059SRicardo Ribalda Delgado static int imx214_set_ctrl(struct v4l2_ctrl *ctrl) 65143619059SRicardo Ribalda Delgado { 65243619059SRicardo Ribalda Delgado struct imx214 *imx214 = container_of(ctrl->handler, 65343619059SRicardo Ribalda Delgado struct imx214, ctrls); 65443619059SRicardo Ribalda Delgado u8 vals[2]; 65543619059SRicardo Ribalda Delgado int ret; 65643619059SRicardo Ribalda Delgado 65743619059SRicardo Ribalda Delgado /* 65843619059SRicardo Ribalda Delgado * Applying V4L2 control value only happens 65943619059SRicardo Ribalda Delgado * when power is up for streaming 66043619059SRicardo Ribalda Delgado */ 66143619059SRicardo Ribalda Delgado if (!pm_runtime_get_if_in_use(imx214->dev)) 66243619059SRicardo Ribalda Delgado return 0; 66343619059SRicardo Ribalda Delgado 66443619059SRicardo Ribalda Delgado switch (ctrl->id) { 66543619059SRicardo Ribalda Delgado case V4L2_CID_EXPOSURE: 66643619059SRicardo Ribalda Delgado vals[1] = ctrl->val; 66743619059SRicardo Ribalda Delgado vals[0] = ctrl->val >> 8; 66843619059SRicardo Ribalda Delgado ret = regmap_bulk_write(imx214->regmap, 0x202, vals, 2); 66943619059SRicardo Ribalda Delgado if (ret < 0) 67043619059SRicardo Ribalda Delgado dev_err(imx214->dev, "Error %d\n", ret); 67143619059SRicardo Ribalda Delgado ret = 0; 67243619059SRicardo Ribalda Delgado break; 67343619059SRicardo Ribalda Delgado 67443619059SRicardo Ribalda Delgado default: 67543619059SRicardo Ribalda Delgado ret = -EINVAL; 67643619059SRicardo Ribalda Delgado } 67743619059SRicardo Ribalda Delgado 67843619059SRicardo Ribalda Delgado pm_runtime_put(imx214->dev); 67943619059SRicardo Ribalda Delgado 68043619059SRicardo Ribalda Delgado return ret; 68143619059SRicardo Ribalda Delgado } 68243619059SRicardo Ribalda Delgado 68343619059SRicardo Ribalda Delgado static const struct v4l2_ctrl_ops imx214_ctrl_ops = { 68443619059SRicardo Ribalda Delgado .s_ctrl = imx214_set_ctrl, 68543619059SRicardo Ribalda Delgado }; 68643619059SRicardo Ribalda Delgado 68743619059SRicardo Ribalda Delgado #define MAX_CMD 4 68843619059SRicardo Ribalda Delgado static int imx214_write_table(struct imx214 *imx214, 68943619059SRicardo Ribalda Delgado const struct reg_8 table[]) 69043619059SRicardo Ribalda Delgado { 69143619059SRicardo Ribalda Delgado u8 vals[MAX_CMD]; 69243619059SRicardo Ribalda Delgado int i; 69343619059SRicardo Ribalda Delgado int ret; 69443619059SRicardo Ribalda Delgado 69543619059SRicardo Ribalda Delgado for (table = table; table->addr != IMX214_TABLE_END ; table++) { 69643619059SRicardo Ribalda Delgado if (table->addr == IMX214_TABLE_WAIT_MS) { 69743619059SRicardo Ribalda Delgado usleep_range(table->val * 1000, 69843619059SRicardo Ribalda Delgado table->val * 1000 + 500); 69943619059SRicardo Ribalda Delgado continue; 70043619059SRicardo Ribalda Delgado } 70143619059SRicardo Ribalda Delgado 70243619059SRicardo Ribalda Delgado for (i = 0; i < MAX_CMD; i++) { 70343619059SRicardo Ribalda Delgado if (table[i].addr != (table[0].addr + i)) 70443619059SRicardo Ribalda Delgado break; 70543619059SRicardo Ribalda Delgado vals[i] = table[i].val; 70643619059SRicardo Ribalda Delgado } 70743619059SRicardo Ribalda Delgado 70843619059SRicardo Ribalda Delgado ret = regmap_bulk_write(imx214->regmap, table->addr, vals, i); 70943619059SRicardo Ribalda Delgado 71043619059SRicardo Ribalda Delgado if (ret) { 71143619059SRicardo Ribalda Delgado dev_err(imx214->dev, "write_table error: %d\n", ret); 71243619059SRicardo Ribalda Delgado return ret; 71343619059SRicardo Ribalda Delgado } 71443619059SRicardo Ribalda Delgado 71543619059SRicardo Ribalda Delgado table += i - 1; 71643619059SRicardo Ribalda Delgado } 71743619059SRicardo Ribalda Delgado 71843619059SRicardo Ribalda Delgado return 0; 71943619059SRicardo Ribalda Delgado } 72043619059SRicardo Ribalda Delgado 72143619059SRicardo Ribalda Delgado static int imx214_start_streaming(struct imx214 *imx214) 72243619059SRicardo Ribalda Delgado { 72343619059SRicardo Ribalda Delgado const struct imx214_mode *mode; 72443619059SRicardo Ribalda Delgado int ret; 72543619059SRicardo Ribalda Delgado 72643619059SRicardo Ribalda Delgado mutex_lock(&imx214->mutex); 72743619059SRicardo Ribalda Delgado ret = imx214_write_table(imx214, mode_table_common); 72843619059SRicardo Ribalda Delgado if (ret < 0) { 72943619059SRicardo Ribalda Delgado dev_err(imx214->dev, "could not sent common table %d\n", ret); 73043619059SRicardo Ribalda Delgado goto error; 73143619059SRicardo Ribalda Delgado } 73243619059SRicardo Ribalda Delgado 73343619059SRicardo Ribalda Delgado mode = v4l2_find_nearest_size(imx214_modes, 73443619059SRicardo Ribalda Delgado ARRAY_SIZE(imx214_modes), width, height, 73543619059SRicardo Ribalda Delgado imx214->fmt.width, imx214->fmt.height); 73643619059SRicardo Ribalda Delgado ret = imx214_write_table(imx214, mode->reg_table); 73743619059SRicardo Ribalda Delgado if (ret < 0) { 73843619059SRicardo Ribalda Delgado dev_err(imx214->dev, "could not sent mode table %d\n", ret); 73943619059SRicardo Ribalda Delgado goto error; 74043619059SRicardo Ribalda Delgado } 74143619059SRicardo Ribalda Delgado ret = __v4l2_ctrl_handler_setup(&imx214->ctrls); 74243619059SRicardo Ribalda Delgado if (ret < 0) { 74343619059SRicardo Ribalda Delgado dev_err(imx214->dev, "could not sync v4l2 controls\n"); 74443619059SRicardo Ribalda Delgado goto error; 74543619059SRicardo Ribalda Delgado } 74643619059SRicardo Ribalda Delgado ret = regmap_write(imx214->regmap, 0x100, 1); 74743619059SRicardo Ribalda Delgado if (ret < 0) { 74843619059SRicardo Ribalda Delgado dev_err(imx214->dev, "could not sent start table %d\n", ret); 74943619059SRicardo Ribalda Delgado goto error; 75043619059SRicardo Ribalda Delgado } 75143619059SRicardo Ribalda Delgado 75243619059SRicardo Ribalda Delgado mutex_unlock(&imx214->mutex); 75343619059SRicardo Ribalda Delgado return 0; 75443619059SRicardo Ribalda Delgado 75543619059SRicardo Ribalda Delgado error: 75643619059SRicardo Ribalda Delgado mutex_unlock(&imx214->mutex); 75743619059SRicardo Ribalda Delgado return ret; 75843619059SRicardo Ribalda Delgado } 75943619059SRicardo Ribalda Delgado 76043619059SRicardo Ribalda Delgado static int imx214_stop_streaming(struct imx214 *imx214) 76143619059SRicardo Ribalda Delgado { 76243619059SRicardo Ribalda Delgado int ret; 76343619059SRicardo Ribalda Delgado 76443619059SRicardo Ribalda Delgado ret = regmap_write(imx214->regmap, 0x100, 0); 76543619059SRicardo Ribalda Delgado if (ret < 0) 76643619059SRicardo Ribalda Delgado dev_err(imx214->dev, "could not sent stop table %d\n", ret); 76743619059SRicardo Ribalda Delgado 76843619059SRicardo Ribalda Delgado return ret; 76943619059SRicardo Ribalda Delgado } 77043619059SRicardo Ribalda Delgado 77143619059SRicardo Ribalda Delgado static int imx214_s_stream(struct v4l2_subdev *subdev, int enable) 77243619059SRicardo Ribalda Delgado { 77343619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(subdev); 77443619059SRicardo Ribalda Delgado int ret; 77543619059SRicardo Ribalda Delgado 77643619059SRicardo Ribalda Delgado if (imx214->streaming == enable) 77743619059SRicardo Ribalda Delgado return 0; 77843619059SRicardo Ribalda Delgado 77943619059SRicardo Ribalda Delgado if (enable) { 78043619059SRicardo Ribalda Delgado ret = pm_runtime_get_sync(imx214->dev); 78143619059SRicardo Ribalda Delgado if (ret < 0) { 78243619059SRicardo Ribalda Delgado pm_runtime_put_noidle(imx214->dev); 78343619059SRicardo Ribalda Delgado return ret; 78443619059SRicardo Ribalda Delgado } 78543619059SRicardo Ribalda Delgado 78643619059SRicardo Ribalda Delgado ret = imx214_start_streaming(imx214); 78743619059SRicardo Ribalda Delgado if (ret < 0) 78843619059SRicardo Ribalda Delgado goto err_rpm_put; 78943619059SRicardo Ribalda Delgado } else { 79043619059SRicardo Ribalda Delgado ret = imx214_start_streaming(imx214); 79143619059SRicardo Ribalda Delgado if (ret < 0) 79243619059SRicardo Ribalda Delgado goto err_rpm_put; 79343619059SRicardo Ribalda Delgado pm_runtime_put(imx214->dev); 79443619059SRicardo Ribalda Delgado } 79543619059SRicardo Ribalda Delgado 79643619059SRicardo Ribalda Delgado imx214->streaming = enable; 79743619059SRicardo Ribalda Delgado return 0; 79843619059SRicardo Ribalda Delgado 79943619059SRicardo Ribalda Delgado err_rpm_put: 80043619059SRicardo Ribalda Delgado pm_runtime_put(imx214->dev); 80143619059SRicardo Ribalda Delgado return ret; 80243619059SRicardo Ribalda Delgado } 80343619059SRicardo Ribalda Delgado 80443619059SRicardo Ribalda Delgado static int imx214_g_frame_interval(struct v4l2_subdev *subdev, 80543619059SRicardo Ribalda Delgado struct v4l2_subdev_frame_interval *fival) 80643619059SRicardo Ribalda Delgado { 80743619059SRicardo Ribalda Delgado fival->pad = 0; 80843619059SRicardo Ribalda Delgado fival->interval.numerator = 1; 80943619059SRicardo Ribalda Delgado fival->interval.denominator = IMX214_FPS; 81043619059SRicardo Ribalda Delgado 81143619059SRicardo Ribalda Delgado return 0; 81243619059SRicardo Ribalda Delgado } 81343619059SRicardo Ribalda Delgado 81443619059SRicardo Ribalda Delgado static int imx214_enum_frame_interval(struct v4l2_subdev *subdev, 81543619059SRicardo Ribalda Delgado struct v4l2_subdev_pad_config *cfg, 81643619059SRicardo Ribalda Delgado struct v4l2_subdev_frame_interval_enum *fie) 81743619059SRicardo Ribalda Delgado { 81843619059SRicardo Ribalda Delgado const struct imx214_mode *mode; 81943619059SRicardo Ribalda Delgado 82043619059SRicardo Ribalda Delgado if (fie->index != 0) 82143619059SRicardo Ribalda Delgado return -EINVAL; 82243619059SRicardo Ribalda Delgado 82343619059SRicardo Ribalda Delgado mode = v4l2_find_nearest_size(imx214_modes, 82443619059SRicardo Ribalda Delgado ARRAY_SIZE(imx214_modes), width, height, 82543619059SRicardo Ribalda Delgado fie->width, fie->height); 82643619059SRicardo Ribalda Delgado 82743619059SRicardo Ribalda Delgado fie->code = IMX214_MBUS_CODE; 82843619059SRicardo Ribalda Delgado fie->width = mode->width; 82943619059SRicardo Ribalda Delgado fie->height = mode->height; 83043619059SRicardo Ribalda Delgado fie->interval.numerator = 1; 83143619059SRicardo Ribalda Delgado fie->interval.denominator = IMX214_FPS; 83243619059SRicardo Ribalda Delgado 83343619059SRicardo Ribalda Delgado return 0; 83443619059SRicardo Ribalda Delgado } 83543619059SRicardo Ribalda Delgado 83643619059SRicardo Ribalda Delgado static const struct v4l2_subdev_video_ops imx214_video_ops = { 83743619059SRicardo Ribalda Delgado .s_stream = imx214_s_stream, 83843619059SRicardo Ribalda Delgado .g_frame_interval = imx214_g_frame_interval, 83943619059SRicardo Ribalda Delgado .s_frame_interval = imx214_g_frame_interval, 84043619059SRicardo Ribalda Delgado }; 84143619059SRicardo Ribalda Delgado 84243619059SRicardo Ribalda Delgado static const struct v4l2_subdev_pad_ops imx214_subdev_pad_ops = { 84343619059SRicardo Ribalda Delgado .enum_mbus_code = imx214_enum_mbus_code, 84443619059SRicardo Ribalda Delgado .enum_frame_size = imx214_enum_frame_size, 84543619059SRicardo Ribalda Delgado .enum_frame_interval = imx214_enum_frame_interval, 84643619059SRicardo Ribalda Delgado .get_fmt = imx214_get_format, 84743619059SRicardo Ribalda Delgado .set_fmt = imx214_set_format, 84843619059SRicardo Ribalda Delgado .get_selection = imx214_get_selection, 84943619059SRicardo Ribalda Delgado .init_cfg = imx214_entity_init_cfg, 85043619059SRicardo Ribalda Delgado }; 85143619059SRicardo Ribalda Delgado 85243619059SRicardo Ribalda Delgado static const struct v4l2_subdev_ops imx214_subdev_ops = { 85343619059SRicardo Ribalda Delgado .core = &imx214_core_ops, 85443619059SRicardo Ribalda Delgado .video = &imx214_video_ops, 85543619059SRicardo Ribalda Delgado .pad = &imx214_subdev_pad_ops, 85643619059SRicardo Ribalda Delgado }; 85743619059SRicardo Ribalda Delgado 85843619059SRicardo Ribalda Delgado static const struct regmap_config sensor_regmap_config = { 85943619059SRicardo Ribalda Delgado .reg_bits = 16, 86043619059SRicardo Ribalda Delgado .val_bits = 8, 86143619059SRicardo Ribalda Delgado .cache_type = REGCACHE_RBTREE, 86243619059SRicardo Ribalda Delgado }; 86343619059SRicardo Ribalda Delgado 86443619059SRicardo Ribalda Delgado static int imx214_get_regulators(struct device *dev, struct imx214 *imx214) 86543619059SRicardo Ribalda Delgado { 86643619059SRicardo Ribalda Delgado unsigned int i; 86743619059SRicardo Ribalda Delgado 86843619059SRicardo Ribalda Delgado for (i = 0; i < IMX214_NUM_SUPPLIES; i++) 86943619059SRicardo Ribalda Delgado imx214->supplies[i].supply = imx214_supply_name[i]; 87043619059SRicardo Ribalda Delgado 87143619059SRicardo Ribalda Delgado return devm_regulator_bulk_get(dev, IMX214_NUM_SUPPLIES, 87243619059SRicardo Ribalda Delgado imx214->supplies); 87343619059SRicardo Ribalda Delgado } 87443619059SRicardo Ribalda Delgado 87543619059SRicardo Ribalda Delgado static int imx214_parse_fwnode(struct device *dev) 87643619059SRicardo Ribalda Delgado { 87743619059SRicardo Ribalda Delgado struct fwnode_handle *endpoint; 87843619059SRicardo Ribalda Delgado struct v4l2_fwnode_endpoint bus_cfg = { 87943619059SRicardo Ribalda Delgado .bus_type = V4L2_MBUS_CSI2_DPHY, 88043619059SRicardo Ribalda Delgado }; 88143619059SRicardo Ribalda Delgado unsigned int i; 88243619059SRicardo Ribalda Delgado int ret; 88343619059SRicardo Ribalda Delgado 88443619059SRicardo Ribalda Delgado endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL); 88543619059SRicardo Ribalda Delgado if (!endpoint) { 88643619059SRicardo Ribalda Delgado dev_err(dev, "endpoint node not found\n"); 88743619059SRicardo Ribalda Delgado return -EINVAL; 88843619059SRicardo Ribalda Delgado } 88943619059SRicardo Ribalda Delgado 89043619059SRicardo Ribalda Delgado ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); 89143619059SRicardo Ribalda Delgado if (ret) { 89243619059SRicardo Ribalda Delgado dev_err(dev, "parsing endpoint node failed\n"); 89343619059SRicardo Ribalda Delgado goto done; 89443619059SRicardo Ribalda Delgado } 89543619059SRicardo Ribalda Delgado 89643619059SRicardo Ribalda Delgado for (i = 0; i < bus_cfg.nr_of_link_frequencies; i++) 89743619059SRicardo Ribalda Delgado if (bus_cfg.link_frequencies[i] == IMX214_DEFAULT_LINK_FREQ) 89843619059SRicardo Ribalda Delgado break; 89943619059SRicardo Ribalda Delgado 90043619059SRicardo Ribalda Delgado if (i == bus_cfg.nr_of_link_frequencies) { 90143619059SRicardo Ribalda Delgado dev_err(dev, "link-frequencies %d not supported, Please review your DT\n", 90243619059SRicardo Ribalda Delgado IMX214_DEFAULT_LINK_FREQ); 90343619059SRicardo Ribalda Delgado ret = -EINVAL; 90443619059SRicardo Ribalda Delgado goto done; 90543619059SRicardo Ribalda Delgado } 90643619059SRicardo Ribalda Delgado 90743619059SRicardo Ribalda Delgado done: 90843619059SRicardo Ribalda Delgado v4l2_fwnode_endpoint_free(&bus_cfg); 90943619059SRicardo Ribalda Delgado fwnode_handle_put(endpoint); 91043619059SRicardo Ribalda Delgado return ret; 91143619059SRicardo Ribalda Delgado } 91243619059SRicardo Ribalda Delgado 91343619059SRicardo Ribalda Delgado static int __maybe_unused imx214_suspend(struct device *dev) 91443619059SRicardo Ribalda Delgado { 91543619059SRicardo Ribalda Delgado struct i2c_client *client = to_i2c_client(dev); 91643619059SRicardo Ribalda Delgado struct v4l2_subdev *sd = i2c_get_clientdata(client); 91743619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 91843619059SRicardo Ribalda Delgado 91943619059SRicardo Ribalda Delgado if (imx214->streaming) 92043619059SRicardo Ribalda Delgado imx214_stop_streaming(imx214); 92143619059SRicardo Ribalda Delgado 92243619059SRicardo Ribalda Delgado return 0; 92343619059SRicardo Ribalda Delgado } 92443619059SRicardo Ribalda Delgado 92543619059SRicardo Ribalda Delgado static int __maybe_unused imx214_resume(struct device *dev) 92643619059SRicardo Ribalda Delgado { 92743619059SRicardo Ribalda Delgado struct i2c_client *client = to_i2c_client(dev); 92843619059SRicardo Ribalda Delgado struct v4l2_subdev *sd = i2c_get_clientdata(client); 92943619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 93043619059SRicardo Ribalda Delgado int ret; 93143619059SRicardo Ribalda Delgado 93243619059SRicardo Ribalda Delgado if (imx214->streaming) { 93343619059SRicardo Ribalda Delgado ret = imx214_start_streaming(imx214); 93443619059SRicardo Ribalda Delgado if (ret) 93543619059SRicardo Ribalda Delgado goto error; 93643619059SRicardo Ribalda Delgado } 93743619059SRicardo Ribalda Delgado 93843619059SRicardo Ribalda Delgado return 0; 93943619059SRicardo Ribalda Delgado 94043619059SRicardo Ribalda Delgado error: 94143619059SRicardo Ribalda Delgado imx214_stop_streaming(imx214); 94243619059SRicardo Ribalda Delgado imx214->streaming = 0; 94343619059SRicardo Ribalda Delgado return ret; 94443619059SRicardo Ribalda Delgado } 94543619059SRicardo Ribalda Delgado 94643619059SRicardo Ribalda Delgado static int imx214_probe(struct i2c_client *client) 94743619059SRicardo Ribalda Delgado { 94843619059SRicardo Ribalda Delgado struct device *dev = &client->dev; 94943619059SRicardo Ribalda Delgado struct imx214 *imx214; 95043619059SRicardo Ribalda Delgado static const s64 link_freq[] = { 95143619059SRicardo Ribalda Delgado IMX214_DEFAULT_LINK_FREQ, 95243619059SRicardo Ribalda Delgado }; 95343619059SRicardo Ribalda Delgado int ret; 95443619059SRicardo Ribalda Delgado 95543619059SRicardo Ribalda Delgado ret = imx214_parse_fwnode(dev); 95643619059SRicardo Ribalda Delgado if (ret) 95743619059SRicardo Ribalda Delgado return ret; 95843619059SRicardo Ribalda Delgado 95943619059SRicardo Ribalda Delgado imx214 = devm_kzalloc(dev, sizeof(*imx214), GFP_KERNEL); 96043619059SRicardo Ribalda Delgado if (!imx214) 96143619059SRicardo Ribalda Delgado return -ENOMEM; 96243619059SRicardo Ribalda Delgado 96343619059SRicardo Ribalda Delgado imx214->dev = dev; 96443619059SRicardo Ribalda Delgado 96543619059SRicardo Ribalda Delgado imx214->xclk = devm_clk_get(dev, NULL); 96643619059SRicardo Ribalda Delgado if (IS_ERR(imx214->xclk)) { 96743619059SRicardo Ribalda Delgado dev_err(dev, "could not get xclk"); 96843619059SRicardo Ribalda Delgado return PTR_ERR(imx214->xclk); 96943619059SRicardo Ribalda Delgado } 97043619059SRicardo Ribalda Delgado 97143619059SRicardo Ribalda Delgado ret = clk_set_rate(imx214->xclk, IMX214_DEFAULT_CLK_FREQ); 97243619059SRicardo Ribalda Delgado if (ret) { 97343619059SRicardo Ribalda Delgado dev_err(dev, "could not set xclk frequency\n"); 97443619059SRicardo Ribalda Delgado return ret; 97543619059SRicardo Ribalda Delgado } 97643619059SRicardo Ribalda Delgado 97743619059SRicardo Ribalda Delgado ret = imx214_get_regulators(dev, imx214); 97843619059SRicardo Ribalda Delgado if (ret < 0) { 97943619059SRicardo Ribalda Delgado dev_err(dev, "cannot get regulators\n"); 98043619059SRicardo Ribalda Delgado return ret; 98143619059SRicardo Ribalda Delgado } 98243619059SRicardo Ribalda Delgado 98343619059SRicardo Ribalda Delgado imx214->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 98443619059SRicardo Ribalda Delgado if (IS_ERR(imx214->enable_gpio)) { 98543619059SRicardo Ribalda Delgado dev_err(dev, "cannot get enable gpio\n"); 98643619059SRicardo Ribalda Delgado return PTR_ERR(imx214->enable_gpio); 98743619059SRicardo Ribalda Delgado } 98843619059SRicardo Ribalda Delgado 98943619059SRicardo Ribalda Delgado imx214->regmap = devm_regmap_init_i2c(client, &sensor_regmap_config); 99043619059SRicardo Ribalda Delgado if (IS_ERR(imx214->regmap)) { 99143619059SRicardo Ribalda Delgado dev_err(dev, "regmap init failed\n"); 99243619059SRicardo Ribalda Delgado return PTR_ERR(imx214->regmap); 99343619059SRicardo Ribalda Delgado } 99443619059SRicardo Ribalda Delgado 99543619059SRicardo Ribalda Delgado v4l2_i2c_subdev_init(&imx214->sd, client, &imx214_subdev_ops); 99643619059SRicardo Ribalda Delgado 99743619059SRicardo Ribalda Delgado /* 99843619059SRicardo Ribalda Delgado * Enable power initially, to avoid warnings 99943619059SRicardo Ribalda Delgado * from clk_disable on power_off 100043619059SRicardo Ribalda Delgado */ 100143619059SRicardo Ribalda Delgado imx214_power_on(imx214->dev); 100243619059SRicardo Ribalda Delgado 100343619059SRicardo Ribalda Delgado pm_runtime_set_active(imx214->dev); 100443619059SRicardo Ribalda Delgado pm_runtime_enable(imx214->dev); 100543619059SRicardo Ribalda Delgado pm_runtime_idle(imx214->dev); 100643619059SRicardo Ribalda Delgado 100743619059SRicardo Ribalda Delgado v4l2_ctrl_handler_init(&imx214->ctrls, 3); 100843619059SRicardo Ribalda Delgado 100943619059SRicardo Ribalda Delgado imx214->pixel_rate = v4l2_ctrl_new_std(&imx214->ctrls, NULL, 101043619059SRicardo Ribalda Delgado V4L2_CID_PIXEL_RATE, 0, 101143619059SRicardo Ribalda Delgado IMX214_DEFAULT_PIXEL_RATE, 1, 101243619059SRicardo Ribalda Delgado IMX214_DEFAULT_PIXEL_RATE); 101343619059SRicardo Ribalda Delgado imx214->link_freq = v4l2_ctrl_new_int_menu(&imx214->ctrls, NULL, 101443619059SRicardo Ribalda Delgado V4L2_CID_LINK_FREQ, 101543619059SRicardo Ribalda Delgado ARRAY_SIZE(link_freq) - 1, 101643619059SRicardo Ribalda Delgado 0, link_freq); 101743619059SRicardo Ribalda Delgado if (imx214->link_freq) 101843619059SRicardo Ribalda Delgado imx214->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; 101943619059SRicardo Ribalda Delgado 102043619059SRicardo Ribalda Delgado /* 102143619059SRicardo Ribalda Delgado * WARNING! 102243619059SRicardo Ribalda Delgado * Values obtained reverse engineering blobs and/or devices. 102343619059SRicardo Ribalda Delgado * Ranges and functionality might be wrong. 102443619059SRicardo Ribalda Delgado * 102543619059SRicardo Ribalda Delgado * Sony, please release some register set documentation for the 102643619059SRicardo Ribalda Delgado * device. 102743619059SRicardo Ribalda Delgado * 102843619059SRicardo Ribalda Delgado * Yours sincerely, Ricardo. 102943619059SRicardo Ribalda Delgado */ 103043619059SRicardo Ribalda Delgado imx214->exposure = v4l2_ctrl_new_std(&imx214->ctrls, &imx214_ctrl_ops, 103143619059SRicardo Ribalda Delgado V4L2_CID_EXPOSURE, 103243619059SRicardo Ribalda Delgado 0, 3184, 1, 0x0c70); 103343619059SRicardo Ribalda Delgado 103443619059SRicardo Ribalda Delgado ret = imx214->ctrls.error; 103543619059SRicardo Ribalda Delgado if (ret) { 103643619059SRicardo Ribalda Delgado dev_err(&client->dev, "%s control init failed (%d)\n", 103743619059SRicardo Ribalda Delgado __func__, ret); 103843619059SRicardo Ribalda Delgado goto free_ctrl; 103943619059SRicardo Ribalda Delgado } 104043619059SRicardo Ribalda Delgado 104143619059SRicardo Ribalda Delgado imx214->sd.ctrl_handler = &imx214->ctrls; 104243619059SRicardo Ribalda Delgado mutex_init(&imx214->mutex); 104343619059SRicardo Ribalda Delgado imx214->ctrls.lock = &imx214->mutex; 104443619059SRicardo Ribalda Delgado 104543619059SRicardo Ribalda Delgado imx214->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 104643619059SRicardo Ribalda Delgado imx214->pad.flags = MEDIA_PAD_FL_SOURCE; 104743619059SRicardo Ribalda Delgado imx214->sd.dev = &client->dev; 104843619059SRicardo Ribalda Delgado imx214->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; 104943619059SRicardo Ribalda Delgado 105043619059SRicardo Ribalda Delgado ret = media_entity_pads_init(&imx214->sd.entity, 1, &imx214->pad); 105143619059SRicardo Ribalda Delgado if (ret < 0) { 105243619059SRicardo Ribalda Delgado dev_err(dev, "could not register media entity\n"); 105343619059SRicardo Ribalda Delgado goto free_ctrl; 105443619059SRicardo Ribalda Delgado } 105543619059SRicardo Ribalda Delgado 105643619059SRicardo Ribalda Delgado imx214_entity_init_cfg(&imx214->sd, NULL); 105743619059SRicardo Ribalda Delgado 105843619059SRicardo Ribalda Delgado ret = v4l2_async_register_subdev_sensor_common(&imx214->sd); 105943619059SRicardo Ribalda Delgado if (ret < 0) { 106043619059SRicardo Ribalda Delgado dev_err(dev, "could not register v4l2 device\n"); 106143619059SRicardo Ribalda Delgado goto free_entity; 106243619059SRicardo Ribalda Delgado } 106343619059SRicardo Ribalda Delgado 106443619059SRicardo Ribalda Delgado return 0; 106543619059SRicardo Ribalda Delgado 106643619059SRicardo Ribalda Delgado free_entity: 106743619059SRicardo Ribalda Delgado media_entity_cleanup(&imx214->sd.entity); 106843619059SRicardo Ribalda Delgado free_ctrl: 106943619059SRicardo Ribalda Delgado mutex_destroy(&imx214->mutex); 107043619059SRicardo Ribalda Delgado v4l2_ctrl_handler_free(&imx214->ctrls); 107143619059SRicardo Ribalda Delgado pm_runtime_disable(imx214->dev); 107243619059SRicardo Ribalda Delgado 107343619059SRicardo Ribalda Delgado return ret; 107443619059SRicardo Ribalda Delgado } 107543619059SRicardo Ribalda Delgado 107643619059SRicardo Ribalda Delgado static int imx214_remove(struct i2c_client *client) 107743619059SRicardo Ribalda Delgado { 107843619059SRicardo Ribalda Delgado struct v4l2_subdev *sd = i2c_get_clientdata(client); 107943619059SRicardo Ribalda Delgado struct imx214 *imx214 = to_imx214(sd); 108043619059SRicardo Ribalda Delgado 108143619059SRicardo Ribalda Delgado v4l2_async_unregister_subdev(&imx214->sd); 108243619059SRicardo Ribalda Delgado media_entity_cleanup(&imx214->sd.entity); 108343619059SRicardo Ribalda Delgado v4l2_ctrl_handler_free(&imx214->ctrls); 108443619059SRicardo Ribalda Delgado 108543619059SRicardo Ribalda Delgado pm_runtime_disable(&client->dev); 108643619059SRicardo Ribalda Delgado pm_runtime_set_suspended(&client->dev); 108743619059SRicardo Ribalda Delgado 108843619059SRicardo Ribalda Delgado mutex_destroy(&imx214->mutex); 108943619059SRicardo Ribalda Delgado 109043619059SRicardo Ribalda Delgado return 0; 109143619059SRicardo Ribalda Delgado } 109243619059SRicardo Ribalda Delgado 109343619059SRicardo Ribalda Delgado static const struct of_device_id imx214_of_match[] = { 109443619059SRicardo Ribalda Delgado { .compatible = "sony,imx214" }, 109543619059SRicardo Ribalda Delgado { } 109643619059SRicardo Ribalda Delgado }; 109743619059SRicardo Ribalda Delgado MODULE_DEVICE_TABLE(of, imx214_of_match); 109843619059SRicardo Ribalda Delgado 109943619059SRicardo Ribalda Delgado static const struct dev_pm_ops imx214_pm_ops = { 110043619059SRicardo Ribalda Delgado SET_SYSTEM_SLEEP_PM_OPS(imx214_suspend, imx214_resume) 110143619059SRicardo Ribalda Delgado SET_RUNTIME_PM_OPS(imx214_power_off, imx214_power_on, NULL) 110243619059SRicardo Ribalda Delgado }; 110343619059SRicardo Ribalda Delgado 110443619059SRicardo Ribalda Delgado static struct i2c_driver imx214_i2c_driver = { 110543619059SRicardo Ribalda Delgado .driver = { 110643619059SRicardo Ribalda Delgado .of_match_table = imx214_of_match, 110743619059SRicardo Ribalda Delgado .pm = &imx214_pm_ops, 110843619059SRicardo Ribalda Delgado .name = "imx214", 110943619059SRicardo Ribalda Delgado }, 111043619059SRicardo Ribalda Delgado .probe_new = imx214_probe, 111143619059SRicardo Ribalda Delgado .remove = imx214_remove, 111243619059SRicardo Ribalda Delgado }; 111343619059SRicardo Ribalda Delgado 111443619059SRicardo Ribalda Delgado module_i2c_driver(imx214_i2c_driver); 111543619059SRicardo Ribalda Delgado 111643619059SRicardo Ribalda Delgado MODULE_DESCRIPTION("Sony IMX214 Camera drier"); 111743619059SRicardo Ribalda Delgado MODULE_AUTHOR("Ricardo Ribalda <ricardo.ribalda@gmail.com>"); 111843619059SRicardo Ribalda Delgado MODULE_LICENSE("GPL v2"); 1119