1642bb5e8SMickael Guene // SPDX-License-Identifier: GPL-2.0 2642bb5e8SMickael Guene /* 3642bb5e8SMickael Guene * Driver for ST MIPID02 CSI-2 to PARALLEL bridge 4642bb5e8SMickael Guene * 5642bb5e8SMickael Guene * Copyright (C) STMicroelectronics SA 2019 6642bb5e8SMickael Guene * Authors: Mickael Guene <mickael.guene@st.com> 7642bb5e8SMickael Guene * for STMicroelectronics. 8642bb5e8SMickael Guene * 9642bb5e8SMickael Guene * 10642bb5e8SMickael Guene */ 11642bb5e8SMickael Guene 12642bb5e8SMickael Guene #include <linux/clk.h> 13642bb5e8SMickael Guene #include <linux/delay.h> 14642bb5e8SMickael Guene #include <linux/gpio/consumer.h> 15642bb5e8SMickael Guene #include <linux/i2c.h> 16642bb5e8SMickael Guene #include <linux/module.h> 17642bb5e8SMickael Guene #include <linux/of_graph.h> 18642bb5e8SMickael Guene #include <linux/regulator/consumer.h> 19642bb5e8SMickael Guene #include <media/v4l2-async.h> 20642bb5e8SMickael Guene #include <media/v4l2-ctrls.h> 21642bb5e8SMickael Guene #include <media/v4l2-device.h> 22642bb5e8SMickael Guene #include <media/v4l2-fwnode.h> 23642bb5e8SMickael Guene #include <media/v4l2-subdev.h> 24642bb5e8SMickael Guene 25642bb5e8SMickael Guene #define MIPID02_CLK_LANE_WR_REG1 0x01 26642bb5e8SMickael Guene #define MIPID02_CLK_LANE_REG1 0x02 27642bb5e8SMickael Guene #define MIPID02_CLK_LANE_REG3 0x04 28642bb5e8SMickael Guene #define MIPID02_DATA_LANE0_REG1 0x05 29642bb5e8SMickael Guene #define MIPID02_DATA_LANE0_REG2 0x06 30642bb5e8SMickael Guene #define MIPID02_DATA_LANE1_REG1 0x09 31642bb5e8SMickael Guene #define MIPID02_DATA_LANE1_REG2 0x0a 32642bb5e8SMickael Guene #define MIPID02_MODE_REG1 0x14 33642bb5e8SMickael Guene #define MIPID02_MODE_REG2 0x15 34642bb5e8SMickael Guene #define MIPID02_DATA_ID_RREG 0x17 35642bb5e8SMickael Guene #define MIPID02_DATA_SELECTION_CTRL 0x19 36642bb5e8SMickael Guene #define MIPID02_PIX_WIDTH_CTRL 0x1e 37642bb5e8SMickael Guene #define MIPID02_PIX_WIDTH_CTRL_EMB 0x1f 38642bb5e8SMickael Guene 39642bb5e8SMickael Guene /* Bits definition for MIPID02_CLK_LANE_REG1 */ 40642bb5e8SMickael Guene #define CLK_ENABLE BIT(0) 41642bb5e8SMickael Guene /* Bits definition for MIPID02_CLK_LANE_REG3 */ 42642bb5e8SMickael Guene #define CLK_MIPI_CSI BIT(1) 43642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_LANE0_REG1 */ 44642bb5e8SMickael Guene #define DATA_ENABLE BIT(0) 45642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_LANEx_REG2 */ 46642bb5e8SMickael Guene #define DATA_MIPI_CSI BIT(0) 47642bb5e8SMickael Guene /* Bits definition for MIPID02_MODE_REG1 */ 48642bb5e8SMickael Guene #define MODE_DATA_SWAP BIT(2) 49642bb5e8SMickael Guene #define MODE_NO_BYPASS BIT(6) 50642bb5e8SMickael Guene /* Bits definition for MIPID02_MODE_REG2 */ 51642bb5e8SMickael Guene #define MODE_HSYNC_ACTIVE_HIGH BIT(1) 52642bb5e8SMickael Guene #define MODE_VSYNC_ACTIVE_HIGH BIT(2) 5381bf9e2eSHugues Fruchet #define MODE_PCLK_SAMPLE_RISING BIT(3) 54642bb5e8SMickael Guene /* Bits definition for MIPID02_DATA_SELECTION_CTRL */ 55642bb5e8SMickael Guene #define SELECTION_MANUAL_DATA BIT(2) 56642bb5e8SMickael Guene #define SELECTION_MANUAL_WIDTH BIT(3) 57642bb5e8SMickael Guene 58642bb5e8SMickael Guene static const u32 mipid02_supported_fmt_codes[] = { 59642bb5e8SMickael Guene MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8, 60642bb5e8SMickael Guene MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8, 61642bb5e8SMickael Guene MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10, 62642bb5e8SMickael Guene MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10, 63642bb5e8SMickael Guene MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SGBRG12_1X12, 64642bb5e8SMickael Guene MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SRGGB12_1X12, 65d0034926SHugues Fruchet MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16, 66d0034926SHugues Fruchet MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16, 67d0034926SHugues Fruchet MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24, 68197adee6SHugues Fruchet MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE, 695109fc8dSAlain Volmat MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8, 705109fc8dSAlain Volmat MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8, 7103aedb1dSHugues Fruchet MEDIA_BUS_FMT_JPEG_1X8 72642bb5e8SMickael Guene }; 73642bb5e8SMickael Guene 74642bb5e8SMickael Guene /* regulator supplies */ 75642bb5e8SMickael Guene static const char * const mipid02_supply_name[] = { 76642bb5e8SMickael Guene "VDDE", /* 1.8V digital I/O supply */ 77642bb5e8SMickael Guene "VDDIN", /* 1V8 voltage regulator supply */ 78642bb5e8SMickael Guene }; 79642bb5e8SMickael Guene 80642bb5e8SMickael Guene #define MIPID02_NUM_SUPPLIES ARRAY_SIZE(mipid02_supply_name) 81642bb5e8SMickael Guene 82642bb5e8SMickael Guene #define MIPID02_SINK_0 0 83642bb5e8SMickael Guene #define MIPID02_SINK_1 1 84642bb5e8SMickael Guene #define MIPID02_SOURCE 2 85642bb5e8SMickael Guene #define MIPID02_PAD_NB 3 86642bb5e8SMickael Guene 87642bb5e8SMickael Guene struct mipid02_dev { 88642bb5e8SMickael Guene struct i2c_client *i2c_client; 89642bb5e8SMickael Guene struct regulator_bulk_data supplies[MIPID02_NUM_SUPPLIES]; 90642bb5e8SMickael Guene struct v4l2_subdev sd; 91642bb5e8SMickael Guene struct media_pad pad[MIPID02_PAD_NB]; 92642bb5e8SMickael Guene struct clk *xclk; 93642bb5e8SMickael Guene struct gpio_desc *reset_gpio; 94642bb5e8SMickael Guene /* endpoints info */ 95642bb5e8SMickael Guene struct v4l2_fwnode_endpoint rx; 96642bb5e8SMickael Guene u64 link_frequency; 97642bb5e8SMickael Guene struct v4l2_fwnode_endpoint tx; 98642bb5e8SMickael Guene /* remote source */ 99642bb5e8SMickael Guene struct v4l2_async_notifier notifier; 100642bb5e8SMickael Guene struct v4l2_subdev *s_subdev; 101642bb5e8SMickael Guene /* registers */ 102642bb5e8SMickael Guene struct { 103642bb5e8SMickael Guene u8 clk_lane_reg1; 104642bb5e8SMickael Guene u8 data_lane0_reg1; 105642bb5e8SMickael Guene u8 data_lane1_reg1; 106642bb5e8SMickael Guene u8 mode_reg1; 107642bb5e8SMickael Guene u8 mode_reg2; 10803aedb1dSHugues Fruchet u8 data_selection_ctrl; 109642bb5e8SMickael Guene u8 data_id_rreg; 110642bb5e8SMickael Guene u8 pix_width_ctrl; 111642bb5e8SMickael Guene u8 pix_width_ctrl_emb; 112642bb5e8SMickael Guene } r; 113642bb5e8SMickael Guene /* lock to protect all members below */ 114642bb5e8SMickael Guene struct mutex lock; 115642bb5e8SMickael Guene bool streaming; 116642bb5e8SMickael Guene struct v4l2_mbus_framefmt fmt; 117642bb5e8SMickael Guene }; 118642bb5e8SMickael Guene 119642bb5e8SMickael Guene static int bpp_from_code(__u32 code) 120642bb5e8SMickael Guene { 121642bb5e8SMickael Guene switch (code) { 122642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR8_1X8: 123642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG8_1X8: 124642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG8_1X8: 125642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB8_1X8: 126642bb5e8SMickael Guene return 8; 127642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR10_1X10: 128642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG10_1X10: 129642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG10_1X10: 130642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB10_1X10: 131642bb5e8SMickael Guene return 10; 132642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR12_1X12: 133642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG12_1X12: 134642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG12_1X12: 135642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB12_1X12: 136642bb5e8SMickael Guene return 12; 137d0034926SHugues Fruchet case MEDIA_BUS_FMT_YUYV8_1X16: 138d0034926SHugues Fruchet case MEDIA_BUS_FMT_YVYU8_1X16: 139642bb5e8SMickael Guene case MEDIA_BUS_FMT_UYVY8_1X16: 140d0034926SHugues Fruchet case MEDIA_BUS_FMT_VYUY8_1X16: 141d0034926SHugues Fruchet case MEDIA_BUS_FMT_RGB565_1X16: 142b9f343dfSHugues Fruchet case MEDIA_BUS_FMT_YUYV8_2X8: 1435109fc8dSAlain Volmat case MEDIA_BUS_FMT_YVYU8_2X8: 144b9f343dfSHugues Fruchet case MEDIA_BUS_FMT_UYVY8_2X8: 1455109fc8dSAlain Volmat case MEDIA_BUS_FMT_VYUY8_2X8: 146197adee6SHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_LE: 147197adee6SHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_BE: 148642bb5e8SMickael Guene return 16; 149642bb5e8SMickael Guene case MEDIA_BUS_FMT_BGR888_1X24: 150642bb5e8SMickael Guene return 24; 151642bb5e8SMickael Guene default: 152642bb5e8SMickael Guene return 0; 153642bb5e8SMickael Guene } 154642bb5e8SMickael Guene } 155642bb5e8SMickael Guene 156642bb5e8SMickael Guene static u8 data_type_from_code(__u32 code) 157642bb5e8SMickael Guene { 158642bb5e8SMickael Guene switch (code) { 159642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR8_1X8: 160642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG8_1X8: 161642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG8_1X8: 162642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB8_1X8: 163642bb5e8SMickael Guene return 0x2a; 164642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR10_1X10: 165642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG10_1X10: 166642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG10_1X10: 167642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB10_1X10: 168642bb5e8SMickael Guene return 0x2b; 169642bb5e8SMickael Guene case MEDIA_BUS_FMT_SBGGR12_1X12: 170642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGBRG12_1X12: 171642bb5e8SMickael Guene case MEDIA_BUS_FMT_SGRBG12_1X12: 172642bb5e8SMickael Guene case MEDIA_BUS_FMT_SRGGB12_1X12: 173642bb5e8SMickael Guene return 0x2c; 174d0034926SHugues Fruchet case MEDIA_BUS_FMT_YUYV8_1X16: 175d0034926SHugues Fruchet case MEDIA_BUS_FMT_YVYU8_1X16: 176642bb5e8SMickael Guene case MEDIA_BUS_FMT_UYVY8_1X16: 177d0034926SHugues Fruchet case MEDIA_BUS_FMT_VYUY8_1X16: 178b9f343dfSHugues Fruchet case MEDIA_BUS_FMT_YUYV8_2X8: 1795109fc8dSAlain Volmat case MEDIA_BUS_FMT_YVYU8_2X8: 180b9f343dfSHugues Fruchet case MEDIA_BUS_FMT_UYVY8_2X8: 1815109fc8dSAlain Volmat case MEDIA_BUS_FMT_VYUY8_2X8: 182642bb5e8SMickael Guene return 0x1e; 183642bb5e8SMickael Guene case MEDIA_BUS_FMT_BGR888_1X24: 184642bb5e8SMickael Guene return 0x24; 185d0034926SHugues Fruchet case MEDIA_BUS_FMT_RGB565_1X16: 186197adee6SHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_LE: 187197adee6SHugues Fruchet case MEDIA_BUS_FMT_RGB565_2X8_BE: 188197adee6SHugues Fruchet return 0x22; 189642bb5e8SMickael Guene default: 190642bb5e8SMickael Guene return 0; 191642bb5e8SMickael Guene } 192642bb5e8SMickael Guene } 193642bb5e8SMickael Guene 194642bb5e8SMickael Guene static void init_format(struct v4l2_mbus_framefmt *fmt) 195642bb5e8SMickael Guene { 196642bb5e8SMickael Guene fmt->code = MEDIA_BUS_FMT_SBGGR8_1X8; 197642bb5e8SMickael Guene fmt->field = V4L2_FIELD_NONE; 198642bb5e8SMickael Guene fmt->colorspace = V4L2_COLORSPACE_SRGB; 199642bb5e8SMickael Guene fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(V4L2_COLORSPACE_SRGB); 200642bb5e8SMickael Guene fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; 201642bb5e8SMickael Guene fmt->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(V4L2_COLORSPACE_SRGB); 202642bb5e8SMickael Guene fmt->width = 640; 203642bb5e8SMickael Guene fmt->height = 480; 204642bb5e8SMickael Guene } 205642bb5e8SMickael Guene 206642bb5e8SMickael Guene static __u32 get_fmt_code(__u32 code) 207642bb5e8SMickael Guene { 208642bb5e8SMickael Guene unsigned int i; 209642bb5e8SMickael Guene 210642bb5e8SMickael Guene for (i = 0; i < ARRAY_SIZE(mipid02_supported_fmt_codes); i++) { 211642bb5e8SMickael Guene if (code == mipid02_supported_fmt_codes[i]) 212642bb5e8SMickael Guene return code; 213642bb5e8SMickael Guene } 214642bb5e8SMickael Guene 215642bb5e8SMickael Guene return mipid02_supported_fmt_codes[0]; 216642bb5e8SMickael Guene } 217642bb5e8SMickael Guene 218642bb5e8SMickael Guene static __u32 serial_to_parallel_code(__u32 serial) 219642bb5e8SMickael Guene { 220d0034926SHugues Fruchet if (serial == MEDIA_BUS_FMT_RGB565_1X16) 221d0034926SHugues Fruchet return MEDIA_BUS_FMT_RGB565_2X8_LE; 222d0034926SHugues Fruchet if (serial == MEDIA_BUS_FMT_YUYV8_1X16) 223d0034926SHugues Fruchet return MEDIA_BUS_FMT_YUYV8_2X8; 224d0034926SHugues Fruchet if (serial == MEDIA_BUS_FMT_YVYU8_1X16) 225d0034926SHugues Fruchet return MEDIA_BUS_FMT_YVYU8_2X8; 226642bb5e8SMickael Guene if (serial == MEDIA_BUS_FMT_UYVY8_1X16) 227642bb5e8SMickael Guene return MEDIA_BUS_FMT_UYVY8_2X8; 228d0034926SHugues Fruchet if (serial == MEDIA_BUS_FMT_VYUY8_1X16) 229d0034926SHugues Fruchet return MEDIA_BUS_FMT_VYUY8_2X8; 230642bb5e8SMickael Guene if (serial == MEDIA_BUS_FMT_BGR888_1X24) 231642bb5e8SMickael Guene return MEDIA_BUS_FMT_BGR888_3X8; 232642bb5e8SMickael Guene 233642bb5e8SMickael Guene return serial; 234642bb5e8SMickael Guene } 235642bb5e8SMickael Guene 236642bb5e8SMickael Guene static inline struct mipid02_dev *to_mipid02_dev(struct v4l2_subdev *sd) 237642bb5e8SMickael Guene { 238642bb5e8SMickael Guene return container_of(sd, struct mipid02_dev, sd); 239642bb5e8SMickael Guene } 240642bb5e8SMickael Guene 241642bb5e8SMickael Guene static int mipid02_read_reg(struct mipid02_dev *bridge, u16 reg, u8 *val) 242642bb5e8SMickael Guene { 243642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 244642bb5e8SMickael Guene struct i2c_msg msg[2]; 245642bb5e8SMickael Guene u8 buf[2]; 246642bb5e8SMickael Guene int ret; 247642bb5e8SMickael Guene 248642bb5e8SMickael Guene buf[0] = reg >> 8; 249642bb5e8SMickael Guene buf[1] = reg & 0xff; 250642bb5e8SMickael Guene 251642bb5e8SMickael Guene msg[0].addr = client->addr; 252642bb5e8SMickael Guene msg[0].flags = client->flags; 253642bb5e8SMickael Guene msg[0].buf = buf; 254642bb5e8SMickael Guene msg[0].len = sizeof(buf); 255642bb5e8SMickael Guene 256642bb5e8SMickael Guene msg[1].addr = client->addr; 257642bb5e8SMickael Guene msg[1].flags = client->flags | I2C_M_RD; 258642bb5e8SMickael Guene msg[1].buf = val; 259642bb5e8SMickael Guene msg[1].len = 1; 260642bb5e8SMickael Guene 261642bb5e8SMickael Guene ret = i2c_transfer(client->adapter, msg, 2); 262642bb5e8SMickael Guene if (ret < 0) { 263642bb5e8SMickael Guene dev_dbg(&client->dev, "%s: %x i2c_transfer, reg: %x => %d\n", 264642bb5e8SMickael Guene __func__, client->addr, reg, ret); 265642bb5e8SMickael Guene return ret; 266642bb5e8SMickael Guene } 267642bb5e8SMickael Guene 268642bb5e8SMickael Guene return 0; 269642bb5e8SMickael Guene } 270642bb5e8SMickael Guene 271642bb5e8SMickael Guene static int mipid02_write_reg(struct mipid02_dev *bridge, u16 reg, u8 val) 272642bb5e8SMickael Guene { 273642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 274642bb5e8SMickael Guene struct i2c_msg msg; 275642bb5e8SMickael Guene u8 buf[3]; 276642bb5e8SMickael Guene int ret; 277642bb5e8SMickael Guene 278642bb5e8SMickael Guene buf[0] = reg >> 8; 279642bb5e8SMickael Guene buf[1] = reg & 0xff; 280642bb5e8SMickael Guene buf[2] = val; 281642bb5e8SMickael Guene 282642bb5e8SMickael Guene msg.addr = client->addr; 283642bb5e8SMickael Guene msg.flags = client->flags; 284642bb5e8SMickael Guene msg.buf = buf; 285642bb5e8SMickael Guene msg.len = sizeof(buf); 286642bb5e8SMickael Guene 287642bb5e8SMickael Guene ret = i2c_transfer(client->adapter, &msg, 1); 288642bb5e8SMickael Guene if (ret < 0) { 289642bb5e8SMickael Guene dev_dbg(&client->dev, "%s: i2c_transfer, reg: %x => %d\n", 290642bb5e8SMickael Guene __func__, reg, ret); 291642bb5e8SMickael Guene return ret; 292642bb5e8SMickael Guene } 293642bb5e8SMickael Guene 294642bb5e8SMickael Guene return 0; 295642bb5e8SMickael Guene } 296642bb5e8SMickael Guene 297642bb5e8SMickael Guene static int mipid02_get_regulators(struct mipid02_dev *bridge) 298642bb5e8SMickael Guene { 299642bb5e8SMickael Guene unsigned int i; 300642bb5e8SMickael Guene 301642bb5e8SMickael Guene for (i = 0; i < MIPID02_NUM_SUPPLIES; i++) 302642bb5e8SMickael Guene bridge->supplies[i].supply = mipid02_supply_name[i]; 303642bb5e8SMickael Guene 304642bb5e8SMickael Guene return devm_regulator_bulk_get(&bridge->i2c_client->dev, 305642bb5e8SMickael Guene MIPID02_NUM_SUPPLIES, 306642bb5e8SMickael Guene bridge->supplies); 307642bb5e8SMickael Guene } 308642bb5e8SMickael Guene 309642bb5e8SMickael Guene static void mipid02_apply_reset(struct mipid02_dev *bridge) 310642bb5e8SMickael Guene { 311642bb5e8SMickael Guene gpiod_set_value_cansleep(bridge->reset_gpio, 0); 312642bb5e8SMickael Guene usleep_range(5000, 10000); 313642bb5e8SMickael Guene gpiod_set_value_cansleep(bridge->reset_gpio, 1); 314642bb5e8SMickael Guene usleep_range(5000, 10000); 315642bb5e8SMickael Guene gpiod_set_value_cansleep(bridge->reset_gpio, 0); 316642bb5e8SMickael Guene usleep_range(5000, 10000); 317642bb5e8SMickael Guene } 318642bb5e8SMickael Guene 319642bb5e8SMickael Guene static int mipid02_set_power_on(struct mipid02_dev *bridge) 320642bb5e8SMickael Guene { 321642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 322642bb5e8SMickael Guene int ret; 323642bb5e8SMickael Guene 324642bb5e8SMickael Guene ret = clk_prepare_enable(bridge->xclk); 325642bb5e8SMickael Guene if (ret) { 326642bb5e8SMickael Guene dev_err(&client->dev, "%s: failed to enable clock\n", __func__); 327642bb5e8SMickael Guene return ret; 328642bb5e8SMickael Guene } 329642bb5e8SMickael Guene 330642bb5e8SMickael Guene ret = regulator_bulk_enable(MIPID02_NUM_SUPPLIES, 331642bb5e8SMickael Guene bridge->supplies); 332642bb5e8SMickael Guene if (ret) { 333642bb5e8SMickael Guene dev_err(&client->dev, "%s: failed to enable regulators\n", 334642bb5e8SMickael Guene __func__); 335642bb5e8SMickael Guene goto xclk_off; 336642bb5e8SMickael Guene } 337642bb5e8SMickael Guene 338642bb5e8SMickael Guene if (bridge->reset_gpio) { 339642bb5e8SMickael Guene dev_dbg(&client->dev, "apply reset"); 340642bb5e8SMickael Guene mipid02_apply_reset(bridge); 341642bb5e8SMickael Guene } else { 342642bb5e8SMickael Guene dev_dbg(&client->dev, "don't apply reset"); 343642bb5e8SMickael Guene usleep_range(5000, 10000); 344642bb5e8SMickael Guene } 345642bb5e8SMickael Guene 346642bb5e8SMickael Guene return 0; 347642bb5e8SMickael Guene 348642bb5e8SMickael Guene xclk_off: 349642bb5e8SMickael Guene clk_disable_unprepare(bridge->xclk); 350642bb5e8SMickael Guene return ret; 351642bb5e8SMickael Guene } 352642bb5e8SMickael Guene 353642bb5e8SMickael Guene static void mipid02_set_power_off(struct mipid02_dev *bridge) 354642bb5e8SMickael Guene { 355642bb5e8SMickael Guene regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies); 356642bb5e8SMickael Guene clk_disable_unprepare(bridge->xclk); 357642bb5e8SMickael Guene } 358642bb5e8SMickael Guene 359642bb5e8SMickael Guene static int mipid02_detect(struct mipid02_dev *bridge) 360642bb5e8SMickael Guene { 361642bb5e8SMickael Guene u8 reg; 362642bb5e8SMickael Guene 363642bb5e8SMickael Guene /* 364642bb5e8SMickael Guene * There is no version registers. Just try to read register 365642bb5e8SMickael Guene * MIPID02_CLK_LANE_WR_REG1. 366642bb5e8SMickael Guene */ 367642bb5e8SMickael Guene return mipid02_read_reg(bridge, MIPID02_CLK_LANE_WR_REG1, ®); 368642bb5e8SMickael Guene } 369642bb5e8SMickael Guene 3706a381d10SHugues Fruchet static u32 mipid02_get_link_freq_from_cid_link_freq(struct mipid02_dev *bridge, 3716a381d10SHugues Fruchet struct v4l2_subdev *subdev) 3726a381d10SHugues Fruchet { 3736a381d10SHugues Fruchet struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, }; 3746a381d10SHugues Fruchet struct v4l2_ctrl *ctrl; 3756a381d10SHugues Fruchet int ret; 3766a381d10SHugues Fruchet 3776a381d10SHugues Fruchet ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_LINK_FREQ); 3786a381d10SHugues Fruchet if (!ctrl) 3796a381d10SHugues Fruchet return 0; 3806a381d10SHugues Fruchet qm.index = v4l2_ctrl_g_ctrl(ctrl); 3816a381d10SHugues Fruchet 3826a381d10SHugues Fruchet ret = v4l2_querymenu(subdev->ctrl_handler, &qm); 3836a381d10SHugues Fruchet if (ret) 3846a381d10SHugues Fruchet return 0; 3856a381d10SHugues Fruchet 3866a381d10SHugues Fruchet return qm.value; 3876a381d10SHugues Fruchet } 3886a381d10SHugues Fruchet 389642bb5e8SMickael Guene static u32 mipid02_get_link_freq_from_cid_pixel_rate(struct mipid02_dev *bridge, 390642bb5e8SMickael Guene struct v4l2_subdev *subdev) 391642bb5e8SMickael Guene { 392642bb5e8SMickael Guene struct v4l2_fwnode_endpoint *ep = &bridge->rx; 393642bb5e8SMickael Guene struct v4l2_ctrl *ctrl; 394642bb5e8SMickael Guene u32 pixel_clock; 395642bb5e8SMickael Guene u32 bpp = bpp_from_code(bridge->fmt.code); 396642bb5e8SMickael Guene 397642bb5e8SMickael Guene ctrl = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_PIXEL_RATE); 398642bb5e8SMickael Guene if (!ctrl) 399642bb5e8SMickael Guene return 0; 400642bb5e8SMickael Guene pixel_clock = v4l2_ctrl_g_ctrl_int64(ctrl); 401642bb5e8SMickael Guene 402642bb5e8SMickael Guene return pixel_clock * bpp / (2 * ep->bus.mipi_csi2.num_data_lanes); 403642bb5e8SMickael Guene } 404642bb5e8SMickael Guene 405642bb5e8SMickael Guene /* 406642bb5e8SMickael Guene * We need to know link frequency to setup clk_lane_reg1 timings. Link frequency 407642bb5e8SMickael Guene * will be computed using connected device V4L2_CID_PIXEL_RATE, bit per pixel 408642bb5e8SMickael Guene * and number of lanes. 409642bb5e8SMickael Guene */ 410642bb5e8SMickael Guene static int mipid02_configure_from_rx_speed(struct mipid02_dev *bridge) 411642bb5e8SMickael Guene { 412642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 413642bb5e8SMickael Guene struct v4l2_subdev *subdev = bridge->s_subdev; 414642bb5e8SMickael Guene u32 link_freq; 415642bb5e8SMickael Guene 4166a381d10SHugues Fruchet link_freq = mipid02_get_link_freq_from_cid_link_freq(bridge, subdev); 417642bb5e8SMickael Guene if (!link_freq) { 4186a381d10SHugues Fruchet link_freq = mipid02_get_link_freq_from_cid_pixel_rate(bridge, 4196a381d10SHugues Fruchet subdev); 4206a381d10SHugues Fruchet if (!link_freq) { 4216a381d10SHugues Fruchet dev_err(&client->dev, "Failed to get link frequency"); 422642bb5e8SMickael Guene return -EINVAL; 423642bb5e8SMickael Guene } 4246a381d10SHugues Fruchet } 425642bb5e8SMickael Guene 426642bb5e8SMickael Guene dev_dbg(&client->dev, "detect link_freq = %d Hz", link_freq); 427642bb5e8SMickael Guene bridge->r.clk_lane_reg1 |= (2000000000 / link_freq) << 2; 428642bb5e8SMickael Guene 429642bb5e8SMickael Guene return 0; 430642bb5e8SMickael Guene } 431642bb5e8SMickael Guene 432642bb5e8SMickael Guene static int mipid02_configure_clk_lane(struct mipid02_dev *bridge) 433642bb5e8SMickael Guene { 434642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 435642bb5e8SMickael Guene struct v4l2_fwnode_endpoint *ep = &bridge->rx; 436642bb5e8SMickael Guene bool *polarities = ep->bus.mipi_csi2.lane_polarities; 437642bb5e8SMickael Guene 438642bb5e8SMickael Guene /* midid02 doesn't support clock lane remapping */ 439642bb5e8SMickael Guene if (ep->bus.mipi_csi2.clock_lane != 0) { 440642bb5e8SMickael Guene dev_err(&client->dev, "clk lane must be map to lane 0\n"); 441642bb5e8SMickael Guene return -EINVAL; 442642bb5e8SMickael Guene } 443642bb5e8SMickael Guene bridge->r.clk_lane_reg1 |= (polarities[0] << 1) | CLK_ENABLE; 444642bb5e8SMickael Guene 445642bb5e8SMickael Guene return 0; 446642bb5e8SMickael Guene } 447642bb5e8SMickael Guene 448642bb5e8SMickael Guene static int mipid02_configure_data0_lane(struct mipid02_dev *bridge, int nb, 449642bb5e8SMickael Guene bool are_lanes_swap, bool *polarities) 450642bb5e8SMickael Guene { 451642bb5e8SMickael Guene bool are_pin_swap = are_lanes_swap ? polarities[2] : polarities[1]; 452642bb5e8SMickael Guene 453642bb5e8SMickael Guene if (nb == 1 && are_lanes_swap) 454642bb5e8SMickael Guene return 0; 455642bb5e8SMickael Guene 456642bb5e8SMickael Guene /* 457642bb5e8SMickael Guene * data lane 0 as pin swap polarity reversed compared to clock and 458642bb5e8SMickael Guene * data lane 1 459642bb5e8SMickael Guene */ 460642bb5e8SMickael Guene if (!are_pin_swap) 461642bb5e8SMickael Guene bridge->r.data_lane0_reg1 = 1 << 1; 462642bb5e8SMickael Guene bridge->r.data_lane0_reg1 |= DATA_ENABLE; 463642bb5e8SMickael Guene 464642bb5e8SMickael Guene return 0; 465642bb5e8SMickael Guene } 466642bb5e8SMickael Guene 467642bb5e8SMickael Guene static int mipid02_configure_data1_lane(struct mipid02_dev *bridge, int nb, 468642bb5e8SMickael Guene bool are_lanes_swap, bool *polarities) 469642bb5e8SMickael Guene { 470642bb5e8SMickael Guene bool are_pin_swap = are_lanes_swap ? polarities[1] : polarities[2]; 471642bb5e8SMickael Guene 472642bb5e8SMickael Guene if (nb == 1 && !are_lanes_swap) 473642bb5e8SMickael Guene return 0; 474642bb5e8SMickael Guene 475642bb5e8SMickael Guene if (are_pin_swap) 476642bb5e8SMickael Guene bridge->r.data_lane1_reg1 = 1 << 1; 477642bb5e8SMickael Guene bridge->r.data_lane1_reg1 |= DATA_ENABLE; 478642bb5e8SMickael Guene 479642bb5e8SMickael Guene return 0; 480642bb5e8SMickael Guene } 481642bb5e8SMickael Guene 482642bb5e8SMickael Guene static int mipid02_configure_from_rx(struct mipid02_dev *bridge) 483642bb5e8SMickael Guene { 484642bb5e8SMickael Guene struct v4l2_fwnode_endpoint *ep = &bridge->rx; 485642bb5e8SMickael Guene bool are_lanes_swap = ep->bus.mipi_csi2.data_lanes[0] == 2; 486642bb5e8SMickael Guene bool *polarities = ep->bus.mipi_csi2.lane_polarities; 487642bb5e8SMickael Guene int nb = ep->bus.mipi_csi2.num_data_lanes; 488642bb5e8SMickael Guene int ret; 489642bb5e8SMickael Guene 490642bb5e8SMickael Guene ret = mipid02_configure_clk_lane(bridge); 491642bb5e8SMickael Guene if (ret) 492642bb5e8SMickael Guene return ret; 493642bb5e8SMickael Guene 494642bb5e8SMickael Guene ret = mipid02_configure_data0_lane(bridge, nb, are_lanes_swap, 495642bb5e8SMickael Guene polarities); 496642bb5e8SMickael Guene if (ret) 497642bb5e8SMickael Guene return ret; 498642bb5e8SMickael Guene 499642bb5e8SMickael Guene ret = mipid02_configure_data1_lane(bridge, nb, are_lanes_swap, 500642bb5e8SMickael Guene polarities); 501642bb5e8SMickael Guene if (ret) 502642bb5e8SMickael Guene return ret; 503642bb5e8SMickael Guene 504642bb5e8SMickael Guene bridge->r.mode_reg1 |= are_lanes_swap ? MODE_DATA_SWAP : 0; 505642bb5e8SMickael Guene bridge->r.mode_reg1 |= (nb - 1) << 1; 506642bb5e8SMickael Guene 507642bb5e8SMickael Guene return mipid02_configure_from_rx_speed(bridge); 508642bb5e8SMickael Guene } 509642bb5e8SMickael Guene 510642bb5e8SMickael Guene static int mipid02_configure_from_tx(struct mipid02_dev *bridge) 511642bb5e8SMickael Guene { 512642bb5e8SMickael Guene struct v4l2_fwnode_endpoint *ep = &bridge->tx; 513642bb5e8SMickael Guene 51403aedb1dSHugues Fruchet bridge->r.data_selection_ctrl = SELECTION_MANUAL_WIDTH; 515642bb5e8SMickael Guene bridge->r.pix_width_ctrl = ep->bus.parallel.bus_width; 516642bb5e8SMickael Guene bridge->r.pix_width_ctrl_emb = ep->bus.parallel.bus_width; 517642bb5e8SMickael Guene if (ep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) 518642bb5e8SMickael Guene bridge->r.mode_reg2 |= MODE_HSYNC_ACTIVE_HIGH; 519642bb5e8SMickael Guene if (ep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) 520642bb5e8SMickael Guene bridge->r.mode_reg2 |= MODE_VSYNC_ACTIVE_HIGH; 52181bf9e2eSHugues Fruchet if (ep->bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) 52281bf9e2eSHugues Fruchet bridge->r.mode_reg2 |= MODE_PCLK_SAMPLE_RISING; 523642bb5e8SMickael Guene 524642bb5e8SMickael Guene return 0; 525642bb5e8SMickael Guene } 526642bb5e8SMickael Guene 527642bb5e8SMickael Guene static int mipid02_configure_from_code(struct mipid02_dev *bridge) 528642bb5e8SMickael Guene { 529642bb5e8SMickael Guene u8 data_type; 530642bb5e8SMickael Guene 531642bb5e8SMickael Guene bridge->r.data_id_rreg = 0; 53203aedb1dSHugues Fruchet 53303aedb1dSHugues Fruchet if (bridge->fmt.code != MEDIA_BUS_FMT_JPEG_1X8) { 53403aedb1dSHugues Fruchet bridge->r.data_selection_ctrl |= SELECTION_MANUAL_DATA; 53503aedb1dSHugues Fruchet 536642bb5e8SMickael Guene data_type = data_type_from_code(bridge->fmt.code); 537642bb5e8SMickael Guene if (!data_type) 538642bb5e8SMickael Guene return -EINVAL; 539642bb5e8SMickael Guene bridge->r.data_id_rreg = data_type; 54003aedb1dSHugues Fruchet } 541642bb5e8SMickael Guene 542642bb5e8SMickael Guene return 0; 543642bb5e8SMickael Guene } 544642bb5e8SMickael Guene 545642bb5e8SMickael Guene static int mipid02_stream_disable(struct mipid02_dev *bridge) 546642bb5e8SMickael Guene { 547642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 548642bb5e8SMickael Guene int ret; 549642bb5e8SMickael Guene 550642bb5e8SMickael Guene /* Disable all lanes */ 551642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 0); 552642bb5e8SMickael Guene if (ret) 553642bb5e8SMickael Guene goto error; 554642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 0); 555642bb5e8SMickael Guene if (ret) 556642bb5e8SMickael Guene goto error; 557642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 0); 558642bb5e8SMickael Guene if (ret) 559642bb5e8SMickael Guene goto error; 560642bb5e8SMickael Guene error: 561642bb5e8SMickael Guene if (ret) 562642bb5e8SMickael Guene dev_err(&client->dev, "failed to stream off %d", ret); 563642bb5e8SMickael Guene 564642bb5e8SMickael Guene return ret; 565642bb5e8SMickael Guene } 566642bb5e8SMickael Guene 567642bb5e8SMickael Guene static int mipid02_stream_enable(struct mipid02_dev *bridge) 568642bb5e8SMickael Guene { 569642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 570642bb5e8SMickael Guene int ret = -EINVAL; 571642bb5e8SMickael Guene 572642bb5e8SMickael Guene if (!bridge->s_subdev) 573642bb5e8SMickael Guene goto error; 574642bb5e8SMickael Guene 575642bb5e8SMickael Guene memset(&bridge->r, 0, sizeof(bridge->r)); 576642bb5e8SMickael Guene /* build registers content */ 577642bb5e8SMickael Guene ret = mipid02_configure_from_rx(bridge); 578642bb5e8SMickael Guene if (ret) 579642bb5e8SMickael Guene goto error; 580642bb5e8SMickael Guene ret = mipid02_configure_from_tx(bridge); 581642bb5e8SMickael Guene if (ret) 582642bb5e8SMickael Guene goto error; 583642bb5e8SMickael Guene ret = mipid02_configure_from_code(bridge); 584642bb5e8SMickael Guene if (ret) 585642bb5e8SMickael Guene goto error; 586642bb5e8SMickael Guene 587642bb5e8SMickael Guene /* write mipi registers */ 588642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG1, 589642bb5e8SMickael Guene bridge->r.clk_lane_reg1); 590642bb5e8SMickael Guene if (ret) 591642bb5e8SMickael Guene goto error; 592642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_CLK_LANE_REG3, CLK_MIPI_CSI); 593642bb5e8SMickael Guene if (ret) 594642bb5e8SMickael Guene goto error; 595642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG1, 596642bb5e8SMickael Guene bridge->r.data_lane0_reg1); 597642bb5e8SMickael Guene if (ret) 598642bb5e8SMickael Guene goto error; 599642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE0_REG2, 600642bb5e8SMickael Guene DATA_MIPI_CSI); 601642bb5e8SMickael Guene if (ret) 602642bb5e8SMickael Guene goto error; 603642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG1, 604642bb5e8SMickael Guene bridge->r.data_lane1_reg1); 605642bb5e8SMickael Guene if (ret) 606642bb5e8SMickael Guene goto error; 607642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_LANE1_REG2, 608642bb5e8SMickael Guene DATA_MIPI_CSI); 609642bb5e8SMickael Guene if (ret) 610642bb5e8SMickael Guene goto error; 611642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_MODE_REG1, 612642bb5e8SMickael Guene MODE_NO_BYPASS | bridge->r.mode_reg1); 613642bb5e8SMickael Guene if (ret) 614642bb5e8SMickael Guene goto error; 615642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_MODE_REG2, 616642bb5e8SMickael Guene bridge->r.mode_reg2); 617642bb5e8SMickael Guene if (ret) 618642bb5e8SMickael Guene goto error; 619642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_ID_RREG, 620642bb5e8SMickael Guene bridge->r.data_id_rreg); 621642bb5e8SMickael Guene if (ret) 622642bb5e8SMickael Guene goto error; 623642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_DATA_SELECTION_CTRL, 62403aedb1dSHugues Fruchet bridge->r.data_selection_ctrl); 625642bb5e8SMickael Guene if (ret) 626642bb5e8SMickael Guene goto error; 627642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL, 628642bb5e8SMickael Guene bridge->r.pix_width_ctrl); 629642bb5e8SMickael Guene if (ret) 630642bb5e8SMickael Guene goto error; 631642bb5e8SMickael Guene ret = mipid02_write_reg(bridge, MIPID02_PIX_WIDTH_CTRL_EMB, 632642bb5e8SMickael Guene bridge->r.pix_width_ctrl_emb); 633642bb5e8SMickael Guene if (ret) 634642bb5e8SMickael Guene goto error; 635642bb5e8SMickael Guene 636642bb5e8SMickael Guene return 0; 637642bb5e8SMickael Guene 638642bb5e8SMickael Guene error: 639642bb5e8SMickael Guene dev_err(&client->dev, "failed to stream on %d", ret); 640642bb5e8SMickael Guene mipid02_stream_disable(bridge); 641642bb5e8SMickael Guene 642642bb5e8SMickael Guene return ret; 643642bb5e8SMickael Guene } 644642bb5e8SMickael Guene 645642bb5e8SMickael Guene static int mipid02_s_stream(struct v4l2_subdev *sd, int enable) 646642bb5e8SMickael Guene { 647642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 648642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 649642bb5e8SMickael Guene int ret = 0; 650642bb5e8SMickael Guene 651642bb5e8SMickael Guene dev_dbg(&client->dev, "%s : requested %d / current = %d", __func__, 652642bb5e8SMickael Guene enable, bridge->streaming); 653642bb5e8SMickael Guene mutex_lock(&bridge->lock); 654642bb5e8SMickael Guene 655642bb5e8SMickael Guene if (bridge->streaming == enable) 656642bb5e8SMickael Guene goto out; 657642bb5e8SMickael Guene 658642bb5e8SMickael Guene ret = enable ? mipid02_stream_enable(bridge) : 659642bb5e8SMickael Guene mipid02_stream_disable(bridge); 660642bb5e8SMickael Guene if (!ret) 661642bb5e8SMickael Guene bridge->streaming = enable; 662642bb5e8SMickael Guene 663642bb5e8SMickael Guene out: 664642bb5e8SMickael Guene dev_dbg(&client->dev, "%s current now = %d / %d", __func__, 665642bb5e8SMickael Guene bridge->streaming, ret); 666642bb5e8SMickael Guene mutex_unlock(&bridge->lock); 667642bb5e8SMickael Guene 668642bb5e8SMickael Guene return ret; 669642bb5e8SMickael Guene } 670642bb5e8SMickael Guene 671642bb5e8SMickael Guene static int mipid02_enum_mbus_code(struct v4l2_subdev *sd, 6720d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 673642bb5e8SMickael Guene struct v4l2_subdev_mbus_code_enum *code) 674642bb5e8SMickael Guene { 675642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 676642bb5e8SMickael Guene int ret = 0; 677642bb5e8SMickael Guene 678642bb5e8SMickael Guene switch (code->pad) { 679642bb5e8SMickael Guene case MIPID02_SINK_0: 680642bb5e8SMickael Guene if (code->index >= ARRAY_SIZE(mipid02_supported_fmt_codes)) 681642bb5e8SMickael Guene ret = -EINVAL; 682642bb5e8SMickael Guene else 683642bb5e8SMickael Guene code->code = mipid02_supported_fmt_codes[code->index]; 684642bb5e8SMickael Guene break; 685642bb5e8SMickael Guene case MIPID02_SOURCE: 686642bb5e8SMickael Guene if (code->index == 0) 687642bb5e8SMickael Guene code->code = serial_to_parallel_code(bridge->fmt.code); 688642bb5e8SMickael Guene else 689642bb5e8SMickael Guene ret = -EINVAL; 690642bb5e8SMickael Guene break; 691642bb5e8SMickael Guene default: 692642bb5e8SMickael Guene ret = -EINVAL; 693642bb5e8SMickael Guene } 694642bb5e8SMickael Guene 695642bb5e8SMickael Guene return ret; 696642bb5e8SMickael Guene } 697642bb5e8SMickael Guene 698642bb5e8SMickael Guene static int mipid02_get_fmt(struct v4l2_subdev *sd, 6990d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 700642bb5e8SMickael Guene struct v4l2_subdev_format *format) 701642bb5e8SMickael Guene { 702642bb5e8SMickael Guene struct v4l2_mbus_framefmt *mbus_fmt = &format->format; 703642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 704642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 705642bb5e8SMickael Guene struct v4l2_mbus_framefmt *fmt; 706642bb5e8SMickael Guene 707642bb5e8SMickael Guene dev_dbg(&client->dev, "%s probe %d", __func__, format->pad); 708642bb5e8SMickael Guene 709642bb5e8SMickael Guene if (format->pad >= MIPID02_PAD_NB) 710642bb5e8SMickael Guene return -EINVAL; 711642bb5e8SMickael Guene /* second CSI-2 pad not yet supported */ 712642bb5e8SMickael Guene if (format->pad == MIPID02_SINK_1) 713642bb5e8SMickael Guene return -EINVAL; 714642bb5e8SMickael Guene 715642bb5e8SMickael Guene if (format->which == V4L2_SUBDEV_FORMAT_TRY) 7160d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(&bridge->sd, sd_state, 7170d346d2aSTomi Valkeinen format->pad); 718642bb5e8SMickael Guene else 719642bb5e8SMickael Guene fmt = &bridge->fmt; 720642bb5e8SMickael Guene 721642bb5e8SMickael Guene mutex_lock(&bridge->lock); 722642bb5e8SMickael Guene 723642bb5e8SMickael Guene *mbus_fmt = *fmt; 724642bb5e8SMickael Guene /* code may need to be converted for source */ 725642bb5e8SMickael Guene if (format->pad == MIPID02_SOURCE) 726642bb5e8SMickael Guene mbus_fmt->code = serial_to_parallel_code(mbus_fmt->code); 727642bb5e8SMickael Guene 728642bb5e8SMickael Guene mutex_unlock(&bridge->lock); 729642bb5e8SMickael Guene 730642bb5e8SMickael Guene return 0; 731642bb5e8SMickael Guene } 732642bb5e8SMickael Guene 733642bb5e8SMickael Guene static void mipid02_set_fmt_source(struct v4l2_subdev *sd, 7340d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 735642bb5e8SMickael Guene struct v4l2_subdev_format *format) 736642bb5e8SMickael Guene { 737642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 738642bb5e8SMickael Guene 739306c3190SDaniel Scally /* source pad mirror sink pad */ 740306c3190SDaniel Scally if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) 741642bb5e8SMickael Guene format->format = bridge->fmt; 742306c3190SDaniel Scally else 743306c3190SDaniel Scally format->format = *v4l2_subdev_get_try_format(sd, sd_state, 744306c3190SDaniel Scally MIPID02_SINK_0); 745306c3190SDaniel Scally 746642bb5e8SMickael Guene /* but code may need to be converted */ 747642bb5e8SMickael Guene format->format.code = serial_to_parallel_code(format->format.code); 748642bb5e8SMickael Guene 749642bb5e8SMickael Guene /* only apply format for V4L2_SUBDEV_FORMAT_TRY case */ 750642bb5e8SMickael Guene if (format->which != V4L2_SUBDEV_FORMAT_TRY) 751642bb5e8SMickael Guene return; 752642bb5e8SMickael Guene 7536c01e6f3SDaniel Scally *v4l2_subdev_get_try_format(sd, sd_state, MIPID02_SOURCE) = 7546c01e6f3SDaniel Scally format->format; 755642bb5e8SMickael Guene } 756642bb5e8SMickael Guene 757642bb5e8SMickael Guene static void mipid02_set_fmt_sink(struct v4l2_subdev *sd, 7580d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 759642bb5e8SMickael Guene struct v4l2_subdev_format *format) 760642bb5e8SMickael Guene { 761642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 762642bb5e8SMickael Guene struct v4l2_mbus_framefmt *fmt; 763642bb5e8SMickael Guene 764642bb5e8SMickael Guene format->format.code = get_fmt_code(format->format.code); 765642bb5e8SMickael Guene 766642bb5e8SMickael Guene if (format->which == V4L2_SUBDEV_FORMAT_TRY) 7670d346d2aSTomi Valkeinen fmt = v4l2_subdev_get_try_format(sd, sd_state, format->pad); 768642bb5e8SMickael Guene else 769642bb5e8SMickael Guene fmt = &bridge->fmt; 770642bb5e8SMickael Guene 771642bb5e8SMickael Guene *fmt = format->format; 7726c01e6f3SDaniel Scally 7736c01e6f3SDaniel Scally /* Propagate the format change to the source pad */ 7746c01e6f3SDaniel Scally mipid02_set_fmt_source(sd, sd_state, format); 775642bb5e8SMickael Guene } 776642bb5e8SMickael Guene 777642bb5e8SMickael Guene static int mipid02_set_fmt(struct v4l2_subdev *sd, 7780d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 779642bb5e8SMickael Guene struct v4l2_subdev_format *format) 780642bb5e8SMickael Guene { 781642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 782642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 783642bb5e8SMickael Guene int ret = 0; 784642bb5e8SMickael Guene 785642bb5e8SMickael Guene dev_dbg(&client->dev, "%s for %d", __func__, format->pad); 786642bb5e8SMickael Guene 787642bb5e8SMickael Guene if (format->pad >= MIPID02_PAD_NB) 788642bb5e8SMickael Guene return -EINVAL; 789642bb5e8SMickael Guene /* second CSI-2 pad not yet supported */ 790642bb5e8SMickael Guene if (format->pad == MIPID02_SINK_1) 791642bb5e8SMickael Guene return -EINVAL; 792642bb5e8SMickael Guene 793642bb5e8SMickael Guene mutex_lock(&bridge->lock); 794642bb5e8SMickael Guene 795642bb5e8SMickael Guene if (bridge->streaming) { 796642bb5e8SMickael Guene ret = -EBUSY; 797642bb5e8SMickael Guene goto error; 798642bb5e8SMickael Guene } 799642bb5e8SMickael Guene 800642bb5e8SMickael Guene if (format->pad == MIPID02_SOURCE) 8010d346d2aSTomi Valkeinen mipid02_set_fmt_source(sd, sd_state, format); 802642bb5e8SMickael Guene else 8030d346d2aSTomi Valkeinen mipid02_set_fmt_sink(sd, sd_state, format); 804642bb5e8SMickael Guene 805642bb5e8SMickael Guene error: 806642bb5e8SMickael Guene mutex_unlock(&bridge->lock); 807642bb5e8SMickael Guene 808642bb5e8SMickael Guene return ret; 809642bb5e8SMickael Guene } 810642bb5e8SMickael Guene 811642bb5e8SMickael Guene static const struct v4l2_subdev_video_ops mipid02_video_ops = { 812642bb5e8SMickael Guene .s_stream = mipid02_s_stream, 813642bb5e8SMickael Guene }; 814642bb5e8SMickael Guene 815642bb5e8SMickael Guene static const struct v4l2_subdev_pad_ops mipid02_pad_ops = { 816642bb5e8SMickael Guene .enum_mbus_code = mipid02_enum_mbus_code, 817642bb5e8SMickael Guene .get_fmt = mipid02_get_fmt, 818642bb5e8SMickael Guene .set_fmt = mipid02_set_fmt, 819642bb5e8SMickael Guene }; 820642bb5e8SMickael Guene 821642bb5e8SMickael Guene static const struct v4l2_subdev_ops mipid02_subdev_ops = { 822642bb5e8SMickael Guene .video = &mipid02_video_ops, 823642bb5e8SMickael Guene .pad = &mipid02_pad_ops, 824642bb5e8SMickael Guene }; 825642bb5e8SMickael Guene 826642bb5e8SMickael Guene static const struct media_entity_operations mipid02_subdev_entity_ops = { 827642bb5e8SMickael Guene .link_validate = v4l2_subdev_link_validate, 828642bb5e8SMickael Guene }; 829642bb5e8SMickael Guene 830642bb5e8SMickael Guene static int mipid02_async_bound(struct v4l2_async_notifier *notifier, 831642bb5e8SMickael Guene struct v4l2_subdev *s_subdev, 832adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 833642bb5e8SMickael Guene { 834642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); 835642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 836642bb5e8SMickael Guene int source_pad; 837642bb5e8SMickael Guene int ret; 838642bb5e8SMickael Guene 839642bb5e8SMickael Guene dev_dbg(&client->dev, "sensor_async_bound call %p", s_subdev); 840642bb5e8SMickael Guene 841642bb5e8SMickael Guene source_pad = media_entity_get_fwnode_pad(&s_subdev->entity, 842642bb5e8SMickael Guene s_subdev->fwnode, 843642bb5e8SMickael Guene MEDIA_PAD_FL_SOURCE); 844642bb5e8SMickael Guene if (source_pad < 0) { 845642bb5e8SMickael Guene dev_err(&client->dev, "Couldn't find output pad for subdev %s\n", 846642bb5e8SMickael Guene s_subdev->name); 847642bb5e8SMickael Guene return source_pad; 848642bb5e8SMickael Guene } 849642bb5e8SMickael Guene 850642bb5e8SMickael Guene ret = media_create_pad_link(&s_subdev->entity, source_pad, 851642bb5e8SMickael Guene &bridge->sd.entity, 0, 852642bb5e8SMickael Guene MEDIA_LNK_FL_ENABLED | 853642bb5e8SMickael Guene MEDIA_LNK_FL_IMMUTABLE); 854642bb5e8SMickael Guene if (ret) { 855642bb5e8SMickael Guene dev_err(&client->dev, "Couldn't create media link %d", ret); 856642bb5e8SMickael Guene return ret; 857642bb5e8SMickael Guene } 858642bb5e8SMickael Guene 859642bb5e8SMickael Guene bridge->s_subdev = s_subdev; 860642bb5e8SMickael Guene 861642bb5e8SMickael Guene return 0; 862642bb5e8SMickael Guene } 863642bb5e8SMickael Guene 864642bb5e8SMickael Guene static void mipid02_async_unbind(struct v4l2_async_notifier *notifier, 865642bb5e8SMickael Guene struct v4l2_subdev *s_subdev, 866adb2dcd5SSakari Ailus struct v4l2_async_connection *asd) 867642bb5e8SMickael Guene { 868642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(notifier->sd); 869642bb5e8SMickael Guene 870642bb5e8SMickael Guene bridge->s_subdev = NULL; 871642bb5e8SMickael Guene } 872642bb5e8SMickael Guene 873642bb5e8SMickael Guene static const struct v4l2_async_notifier_operations mipid02_notifier_ops = { 874642bb5e8SMickael Guene .bound = mipid02_async_bound, 875642bb5e8SMickael Guene .unbind = mipid02_async_unbind, 876642bb5e8SMickael Guene }; 877642bb5e8SMickael Guene 878642bb5e8SMickael Guene static int mipid02_parse_rx_ep(struct mipid02_dev *bridge) 879642bb5e8SMickael Guene { 880642bb5e8SMickael Guene struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY }; 881642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 882adb2dcd5SSakari Ailus struct v4l2_async_connection *asd; 883642bb5e8SMickael Guene struct device_node *ep_node; 884642bb5e8SMickael Guene int ret; 885642bb5e8SMickael Guene 886642bb5e8SMickael Guene /* parse rx (endpoint 0) */ 887642bb5e8SMickael Guene ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, 888642bb5e8SMickael Guene 0, 0); 889642bb5e8SMickael Guene if (!ep_node) { 890642bb5e8SMickael Guene dev_err(&client->dev, "unable to find port0 ep"); 891642bb5e8SMickael Guene ret = -EINVAL; 892642bb5e8SMickael Guene goto error; 893642bb5e8SMickael Guene } 894642bb5e8SMickael Guene 895642bb5e8SMickael Guene ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); 896642bb5e8SMickael Guene if (ret) { 897642bb5e8SMickael Guene dev_err(&client->dev, "Could not parse v4l2 endpoint %d\n", 898642bb5e8SMickael Guene ret); 899642bb5e8SMickael Guene goto error_of_node_put; 900642bb5e8SMickael Guene } 901642bb5e8SMickael Guene 902642bb5e8SMickael Guene /* do some sanity checks */ 903642bb5e8SMickael Guene if (ep.bus.mipi_csi2.num_data_lanes > 2) { 904642bb5e8SMickael Guene dev_err(&client->dev, "max supported data lanes is 2 / got %d", 905642bb5e8SMickael Guene ep.bus.mipi_csi2.num_data_lanes); 906642bb5e8SMickael Guene ret = -EINVAL; 907642bb5e8SMickael Guene goto error_of_node_put; 908642bb5e8SMickael Guene } 909642bb5e8SMickael Guene 910642bb5e8SMickael Guene /* register it for later use */ 911642bb5e8SMickael Guene bridge->rx = ep; 912642bb5e8SMickael Guene 913642bb5e8SMickael Guene /* register async notifier so we get noticed when sensor is connected */ 914*b8ec754aSSakari Ailus v4l2_async_subdev_nf_init(&bridge->notifier, &bridge->sd); 9153c8c1539SSakari Ailus asd = v4l2_async_nf_add_fwnode_remote(&bridge->notifier, 9165bbefdefSEzequiel Garcia of_fwnode_handle(ep_node), 917adb2dcd5SSakari Ailus struct v4l2_async_connection); 918642bb5e8SMickael Guene of_node_put(ep_node); 919642bb5e8SMickael Guene 9205bbefdefSEzequiel Garcia if (IS_ERR(asd)) { 9215bbefdefSEzequiel Garcia dev_err(&client->dev, "fail to register asd to notifier %ld", 9225bbefdefSEzequiel Garcia PTR_ERR(asd)); 9235bbefdefSEzequiel Garcia return PTR_ERR(asd); 924642bb5e8SMickael Guene } 925642bb5e8SMickael Guene bridge->notifier.ops = &mipid02_notifier_ops; 926642bb5e8SMickael Guene 927*b8ec754aSSakari Ailus ret = v4l2_async_nf_register(&bridge->notifier); 928642bb5e8SMickael Guene if (ret) 9293c8c1539SSakari Ailus v4l2_async_nf_cleanup(&bridge->notifier); 930642bb5e8SMickael Guene 931642bb5e8SMickael Guene return ret; 932642bb5e8SMickael Guene 933642bb5e8SMickael Guene error_of_node_put: 934642bb5e8SMickael Guene of_node_put(ep_node); 935642bb5e8SMickael Guene error: 936642bb5e8SMickael Guene 937642bb5e8SMickael Guene return ret; 938642bb5e8SMickael Guene } 939642bb5e8SMickael Guene 940642bb5e8SMickael Guene static int mipid02_parse_tx_ep(struct mipid02_dev *bridge) 941642bb5e8SMickael Guene { 942642bb5e8SMickael Guene struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_PARALLEL }; 943642bb5e8SMickael Guene struct i2c_client *client = bridge->i2c_client; 944642bb5e8SMickael Guene struct device_node *ep_node; 945642bb5e8SMickael Guene int ret; 946642bb5e8SMickael Guene 947642bb5e8SMickael Guene /* parse tx (endpoint 2) */ 948642bb5e8SMickael Guene ep_node = of_graph_get_endpoint_by_regs(bridge->i2c_client->dev.of_node, 949642bb5e8SMickael Guene 2, 0); 950642bb5e8SMickael Guene if (!ep_node) { 951642bb5e8SMickael Guene dev_err(&client->dev, "unable to find port1 ep"); 952642bb5e8SMickael Guene ret = -EINVAL; 953642bb5e8SMickael Guene goto error; 954642bb5e8SMickael Guene } 955642bb5e8SMickael Guene 956642bb5e8SMickael Guene ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep_node), &ep); 957642bb5e8SMickael Guene if (ret) { 958642bb5e8SMickael Guene dev_err(&client->dev, "Could not parse v4l2 endpoint\n"); 959642bb5e8SMickael Guene goto error_of_node_put; 960642bb5e8SMickael Guene } 961642bb5e8SMickael Guene 962642bb5e8SMickael Guene of_node_put(ep_node); 963642bb5e8SMickael Guene bridge->tx = ep; 964642bb5e8SMickael Guene 965642bb5e8SMickael Guene return 0; 966642bb5e8SMickael Guene 967642bb5e8SMickael Guene error_of_node_put: 968642bb5e8SMickael Guene of_node_put(ep_node); 969642bb5e8SMickael Guene error: 970642bb5e8SMickael Guene 971642bb5e8SMickael Guene return -EINVAL; 972642bb5e8SMickael Guene } 973642bb5e8SMickael Guene 974642bb5e8SMickael Guene static int mipid02_probe(struct i2c_client *client) 975642bb5e8SMickael Guene { 976642bb5e8SMickael Guene struct device *dev = &client->dev; 977642bb5e8SMickael Guene struct mipid02_dev *bridge; 978642bb5e8SMickael Guene u32 clk_freq; 979642bb5e8SMickael Guene int ret; 980642bb5e8SMickael Guene 981642bb5e8SMickael Guene bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL); 982642bb5e8SMickael Guene if (!bridge) 983642bb5e8SMickael Guene return -ENOMEM; 984642bb5e8SMickael Guene 985642bb5e8SMickael Guene init_format(&bridge->fmt); 986642bb5e8SMickael Guene 987642bb5e8SMickael Guene bridge->i2c_client = client; 988642bb5e8SMickael Guene v4l2_i2c_subdev_init(&bridge->sd, client, &mipid02_subdev_ops); 989642bb5e8SMickael Guene 990642bb5e8SMickael Guene /* got and check clock */ 991642bb5e8SMickael Guene bridge->xclk = devm_clk_get(dev, "xclk"); 992642bb5e8SMickael Guene if (IS_ERR(bridge->xclk)) { 993642bb5e8SMickael Guene dev_err(dev, "failed to get xclk\n"); 994642bb5e8SMickael Guene return PTR_ERR(bridge->xclk); 995642bb5e8SMickael Guene } 996642bb5e8SMickael Guene 997642bb5e8SMickael Guene clk_freq = clk_get_rate(bridge->xclk); 998642bb5e8SMickael Guene if (clk_freq < 6000000 || clk_freq > 27000000) { 999642bb5e8SMickael Guene dev_err(dev, "xclk freq must be in 6-27 Mhz range. got %d Hz\n", 1000642bb5e8SMickael Guene clk_freq); 1001642bb5e8SMickael Guene return -EINVAL; 1002642bb5e8SMickael Guene } 1003642bb5e8SMickael Guene 1004642bb5e8SMickael Guene bridge->reset_gpio = devm_gpiod_get_optional(dev, "reset", 1005642bb5e8SMickael Guene GPIOD_OUT_HIGH); 1006642bb5e8SMickael Guene 100761c03b63SChuhong Yuan if (IS_ERR(bridge->reset_gpio)) { 100861c03b63SChuhong Yuan dev_err(dev, "failed to get reset GPIO\n"); 100961c03b63SChuhong Yuan return PTR_ERR(bridge->reset_gpio); 101061c03b63SChuhong Yuan } 101161c03b63SChuhong Yuan 1012642bb5e8SMickael Guene ret = mipid02_get_regulators(bridge); 1013642bb5e8SMickael Guene if (ret) { 1014642bb5e8SMickael Guene dev_err(dev, "failed to get regulators %d", ret); 1015642bb5e8SMickael Guene return ret; 1016642bb5e8SMickael Guene } 1017642bb5e8SMickael Guene 1018642bb5e8SMickael Guene mutex_init(&bridge->lock); 1019642bb5e8SMickael Guene bridge->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 1020642bb5e8SMickael Guene bridge->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 1021642bb5e8SMickael Guene bridge->sd.entity.ops = &mipid02_subdev_entity_ops; 1022642bb5e8SMickael Guene bridge->pad[0].flags = MEDIA_PAD_FL_SINK; 1023642bb5e8SMickael Guene bridge->pad[1].flags = MEDIA_PAD_FL_SINK; 1024642bb5e8SMickael Guene bridge->pad[2].flags = MEDIA_PAD_FL_SOURCE; 1025642bb5e8SMickael Guene ret = media_entity_pads_init(&bridge->sd.entity, MIPID02_PAD_NB, 1026642bb5e8SMickael Guene bridge->pad); 1027642bb5e8SMickael Guene if (ret) { 1028642bb5e8SMickael Guene dev_err(&client->dev, "pads init failed %d", ret); 1029642bb5e8SMickael Guene goto mutex_cleanup; 1030642bb5e8SMickael Guene } 1031642bb5e8SMickael Guene 1032642bb5e8SMickael Guene /* enable clock, power and reset device if available */ 1033642bb5e8SMickael Guene ret = mipid02_set_power_on(bridge); 1034642bb5e8SMickael Guene if (ret) 1035642bb5e8SMickael Guene goto entity_cleanup; 1036642bb5e8SMickael Guene 1037642bb5e8SMickael Guene ret = mipid02_detect(bridge); 1038642bb5e8SMickael Guene if (ret) { 1039642bb5e8SMickael Guene dev_err(&client->dev, "failed to detect mipid02 %d", ret); 1040642bb5e8SMickael Guene goto power_off; 1041642bb5e8SMickael Guene } 1042642bb5e8SMickael Guene 1043642bb5e8SMickael Guene ret = mipid02_parse_tx_ep(bridge); 1044642bb5e8SMickael Guene if (ret) { 1045642bb5e8SMickael Guene dev_err(&client->dev, "failed to parse tx %d", ret); 1046642bb5e8SMickael Guene goto power_off; 1047642bb5e8SMickael Guene } 1048642bb5e8SMickael Guene 1049642bb5e8SMickael Guene ret = mipid02_parse_rx_ep(bridge); 1050642bb5e8SMickael Guene if (ret) { 1051642bb5e8SMickael Guene dev_err(&client->dev, "failed to parse rx %d", ret); 1052642bb5e8SMickael Guene goto power_off; 1053642bb5e8SMickael Guene } 1054642bb5e8SMickael Guene 1055642bb5e8SMickael Guene ret = v4l2_async_register_subdev(&bridge->sd); 1056642bb5e8SMickael Guene if (ret < 0) { 1057642bb5e8SMickael Guene dev_err(&client->dev, "v4l2_async_register_subdev failed %d", 1058642bb5e8SMickael Guene ret); 1059642bb5e8SMickael Guene goto unregister_notifier; 1060642bb5e8SMickael Guene } 1061642bb5e8SMickael Guene 1062642bb5e8SMickael Guene dev_info(&client->dev, "mipid02 device probe successfully"); 1063642bb5e8SMickael Guene 1064642bb5e8SMickael Guene return 0; 1065642bb5e8SMickael Guene 1066642bb5e8SMickael Guene unregister_notifier: 10673c8c1539SSakari Ailus v4l2_async_nf_unregister(&bridge->notifier); 10683c8c1539SSakari Ailus v4l2_async_nf_cleanup(&bridge->notifier); 1069642bb5e8SMickael Guene power_off: 1070642bb5e8SMickael Guene mipid02_set_power_off(bridge); 1071642bb5e8SMickael Guene entity_cleanup: 1072642bb5e8SMickael Guene media_entity_cleanup(&bridge->sd.entity); 1073642bb5e8SMickael Guene mutex_cleanup: 1074642bb5e8SMickael Guene mutex_destroy(&bridge->lock); 1075642bb5e8SMickael Guene 1076642bb5e8SMickael Guene return ret; 1077642bb5e8SMickael Guene } 1078642bb5e8SMickael Guene 1079ed5c2f5fSUwe Kleine-König static void mipid02_remove(struct i2c_client *client) 1080642bb5e8SMickael Guene { 1081642bb5e8SMickael Guene struct v4l2_subdev *sd = i2c_get_clientdata(client); 1082642bb5e8SMickael Guene struct mipid02_dev *bridge = to_mipid02_dev(sd); 1083642bb5e8SMickael Guene 10843c8c1539SSakari Ailus v4l2_async_nf_unregister(&bridge->notifier); 10853c8c1539SSakari Ailus v4l2_async_nf_cleanup(&bridge->notifier); 1086642bb5e8SMickael Guene v4l2_async_unregister_subdev(&bridge->sd); 1087642bb5e8SMickael Guene mipid02_set_power_off(bridge); 1088642bb5e8SMickael Guene media_entity_cleanup(&bridge->sd.entity); 1089642bb5e8SMickael Guene mutex_destroy(&bridge->lock); 1090642bb5e8SMickael Guene } 1091642bb5e8SMickael Guene 1092642bb5e8SMickael Guene static const struct of_device_id mipid02_dt_ids[] = { 1093642bb5e8SMickael Guene { .compatible = "st,st-mipid02" }, 1094642bb5e8SMickael Guene { /* sentinel */ } 1095642bb5e8SMickael Guene }; 1096642bb5e8SMickael Guene MODULE_DEVICE_TABLE(of, mipid02_dt_ids); 1097642bb5e8SMickael Guene 1098642bb5e8SMickael Guene static struct i2c_driver mipid02_i2c_driver = { 1099642bb5e8SMickael Guene .driver = { 1100642bb5e8SMickael Guene .name = "st-mipid02", 1101642bb5e8SMickael Guene .of_match_table = mipid02_dt_ids, 1102642bb5e8SMickael Guene }, 1103aaeb31c0SUwe Kleine-König .probe = mipid02_probe, 1104642bb5e8SMickael Guene .remove = mipid02_remove, 1105642bb5e8SMickael Guene }; 1106642bb5e8SMickael Guene 1107642bb5e8SMickael Guene module_i2c_driver(mipid02_i2c_driver); 1108642bb5e8SMickael Guene 1109642bb5e8SMickael Guene MODULE_AUTHOR("Mickael Guene <mickael.guene@st.com>"); 1110642bb5e8SMickael Guene MODULE_DESCRIPTION("STMicroelectronics MIPID02 CSI-2 bridge driver"); 1111642bb5e8SMickael Guene MODULE_LICENSE("GPL v2"); 1112