166d8c9d2SKieran Bingham // SPDX-License-Identifier: GPL-2.0+ 266d8c9d2SKieran Bingham /* 366d8c9d2SKieran Bingham * Maxim MAX9286 GMSL Deserializer Driver 466d8c9d2SKieran Bingham * 566d8c9d2SKieran Bingham * Copyright (C) 2017-2019 Jacopo Mondi 666d8c9d2SKieran Bingham * Copyright (C) 2017-2019 Kieran Bingham 766d8c9d2SKieran Bingham * Copyright (C) 2017-2019 Laurent Pinchart 866d8c9d2SKieran Bingham * Copyright (C) 2017-2019 Niklas Söderlund 966d8c9d2SKieran Bingham * Copyright (C) 2016 Renesas Electronics Corporation 1066d8c9d2SKieran Bingham * Copyright (C) 2015 Cogent Embedded, Inc. 1166d8c9d2SKieran Bingham */ 1266d8c9d2SKieran Bingham 1366d8c9d2SKieran Bingham #include <linux/delay.h> 1466d8c9d2SKieran Bingham #include <linux/device.h> 1566d8c9d2SKieran Bingham #include <linux/fwnode.h> 1666d8c9d2SKieran Bingham #include <linux/gpio/consumer.h> 1766d8c9d2SKieran Bingham #include <linux/gpio/driver.h> 18c9352df7SJacopo Mondi #include <linux/gpio/machine.h> 1966d8c9d2SKieran Bingham #include <linux/i2c.h> 2066d8c9d2SKieran Bingham #include <linux/i2c-mux.h> 2166d8c9d2SKieran Bingham #include <linux/module.h> 2266d8c9d2SKieran Bingham #include <linux/mutex.h> 2366d8c9d2SKieran Bingham #include <linux/of_graph.h> 2466d8c9d2SKieran Bingham #include <linux/regulator/consumer.h> 2566d8c9d2SKieran Bingham #include <linux/slab.h> 2666d8c9d2SKieran Bingham 2766d8c9d2SKieran Bingham #include <media/v4l2-async.h> 2866d8c9d2SKieran Bingham #include <media/v4l2-ctrls.h> 2966d8c9d2SKieran Bingham #include <media/v4l2-device.h> 3066d8c9d2SKieran Bingham #include <media/v4l2-fwnode.h> 3166d8c9d2SKieran Bingham #include <media/v4l2-subdev.h> 3266d8c9d2SKieran Bingham 3366d8c9d2SKieran Bingham /* Register 0x00 */ 3466d8c9d2SKieran Bingham #define MAX9286_MSTLINKSEL_AUTO (7 << 5) 3566d8c9d2SKieran Bingham #define MAX9286_MSTLINKSEL(n) ((n) << 5) 3666d8c9d2SKieran Bingham #define MAX9286_EN_VS_GEN BIT(4) 3766d8c9d2SKieran Bingham #define MAX9286_LINKEN(n) (1 << (n)) 3866d8c9d2SKieran Bingham /* Register 0x01 */ 3966d8c9d2SKieran Bingham #define MAX9286_FSYNCMODE_ECU (3 << 6) 4066d8c9d2SKieran Bingham #define MAX9286_FSYNCMODE_EXT (2 << 6) 4166d8c9d2SKieran Bingham #define MAX9286_FSYNCMODE_INT_OUT (1 << 6) 4266d8c9d2SKieran Bingham #define MAX9286_FSYNCMODE_INT_HIZ (0 << 6) 4366d8c9d2SKieran Bingham #define MAX9286_GPIEN BIT(5) 4466d8c9d2SKieran Bingham #define MAX9286_ENLMO_RSTFSYNC BIT(2) 4566d8c9d2SKieran Bingham #define MAX9286_FSYNCMETH_AUTO (2 << 0) 4666d8c9d2SKieran Bingham #define MAX9286_FSYNCMETH_SEMI_AUTO (1 << 0) 4766d8c9d2SKieran Bingham #define MAX9286_FSYNCMETH_MANUAL (0 << 0) 4866d8c9d2SKieran Bingham #define MAX9286_REG_FSYNC_PERIOD_L 0x06 4966d8c9d2SKieran Bingham #define MAX9286_REG_FSYNC_PERIOD_M 0x07 5066d8c9d2SKieran Bingham #define MAX9286_REG_FSYNC_PERIOD_H 0x08 5166d8c9d2SKieran Bingham /* Register 0x0a */ 5266d8c9d2SKieran Bingham #define MAX9286_FWDCCEN(n) (1 << ((n) + 4)) 5366d8c9d2SKieran Bingham #define MAX9286_REVCCEN(n) (1 << (n)) 5466d8c9d2SKieran Bingham /* Register 0x0c */ 5566d8c9d2SKieran Bingham #define MAX9286_HVEN BIT(7) 5666d8c9d2SKieran Bingham #define MAX9286_EDC_6BIT_HAMMING (2 << 5) 5766d8c9d2SKieran Bingham #define MAX9286_EDC_6BIT_CRC (1 << 5) 5866d8c9d2SKieran Bingham #define MAX9286_EDC_1BIT_PARITY (0 << 5) 5966d8c9d2SKieran Bingham #define MAX9286_DESEL BIT(4) 6066d8c9d2SKieran Bingham #define MAX9286_INVVS BIT(3) 6166d8c9d2SKieran Bingham #define MAX9286_INVHS BIT(2) 6266d8c9d2SKieran Bingham #define MAX9286_HVSRC_D0 (2 << 0) 6366d8c9d2SKieran Bingham #define MAX9286_HVSRC_D14 (1 << 0) 6466d8c9d2SKieran Bingham #define MAX9286_HVSRC_D18 (0 << 0) 6566d8c9d2SKieran Bingham /* Register 0x0f */ 6666d8c9d2SKieran Bingham #define MAX9286_0X0F_RESERVED BIT(3) 6766d8c9d2SKieran Bingham /* Register 0x12 */ 6866d8c9d2SKieran Bingham #define MAX9286_CSILANECNT(n) (((n) - 1) << 6) 6966d8c9d2SKieran Bingham #define MAX9286_CSIDBL BIT(5) 7066d8c9d2SKieran Bingham #define MAX9286_DBL BIT(4) 7166d8c9d2SKieran Bingham #define MAX9286_DATATYPE_USER_8BIT (11 << 0) 7266d8c9d2SKieran Bingham #define MAX9286_DATATYPE_USER_YUV_12BIT (10 << 0) 7366d8c9d2SKieran Bingham #define MAX9286_DATATYPE_USER_24BIT (9 << 0) 7466d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RAW14 (8 << 0) 75b904512bSLaurent Pinchart #define MAX9286_DATATYPE_RAW12 (7 << 0) 7666d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RAW10 (6 << 0) 7766d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RAW8 (5 << 0) 7866d8c9d2SKieran Bingham #define MAX9286_DATATYPE_YUV422_10BIT (4 << 0) 7966d8c9d2SKieran Bingham #define MAX9286_DATATYPE_YUV422_8BIT (3 << 0) 8066d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RGB555 (2 << 0) 8166d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RGB565 (1 << 0) 8266d8c9d2SKieran Bingham #define MAX9286_DATATYPE_RGB888 (0 << 0) 8366d8c9d2SKieran Bingham /* Register 0x15 */ 84cdcb186eSLaurent Pinchart #define MAX9286_CSI_IMAGE_TYP BIT(7) 8566d8c9d2SKieran Bingham #define MAX9286_VC(n) ((n) << 5) 8666d8c9d2SKieran Bingham #define MAX9286_VCTYPE BIT(4) 8766d8c9d2SKieran Bingham #define MAX9286_CSIOUTEN BIT(3) 88cdcb186eSLaurent Pinchart #define MAX9286_SWP_ENDIAN BIT(2) 89cdcb186eSLaurent Pinchart #define MAX9286_EN_CCBSYB_CLK_STR BIT(1) 90cdcb186eSLaurent Pinchart #define MAX9286_EN_GPI_CCBSYB BIT(0) 9166d8c9d2SKieran Bingham /* Register 0x1b */ 9266d8c9d2SKieran Bingham #define MAX9286_SWITCHIN(n) (1 << ((n) + 4)) 9366d8c9d2SKieran Bingham #define MAX9286_ENEQ(n) (1 << (n)) 943697f108SLaurent Pinchart /* Register 0x1c */ 953697f108SLaurent Pinchart #define MAX9286_HIGHIMM(n) BIT((n) + 4) 963697f108SLaurent Pinchart #define MAX9286_I2CSEL BIT(2) 973697f108SLaurent Pinchart #define MAX9286_HIBW BIT(1) 983697f108SLaurent Pinchart #define MAX9286_BWS BIT(0) 9966d8c9d2SKieran Bingham /* Register 0x27 */ 10066d8c9d2SKieran Bingham #define MAX9286_LOCKED BIT(7) 10166d8c9d2SKieran Bingham /* Register 0x31 */ 10266d8c9d2SKieran Bingham #define MAX9286_FSYNC_LOCKED BIT(6) 10366d8c9d2SKieran Bingham /* Register 0x34 */ 10466d8c9d2SKieran Bingham #define MAX9286_I2CLOCACK BIT(7) 10566d8c9d2SKieran Bingham #define MAX9286_I2CSLVSH_1046NS_469NS (3 << 5) 10666d8c9d2SKieran Bingham #define MAX9286_I2CSLVSH_938NS_352NS (2 << 5) 10766d8c9d2SKieran Bingham #define MAX9286_I2CSLVSH_469NS_234NS (1 << 5) 10866d8c9d2SKieran Bingham #define MAX9286_I2CSLVSH_352NS_117NS (0 << 5) 10966d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_837KBPS (7 << 2) 11066d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_533KBPS (6 << 2) 11166d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_339KBPS (5 << 2) 11266d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_173KBPS (4 << 2) 11366d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_105KBPS (3 << 2) 11466d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_84KBPS (2 << 2) 11566d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_28KBPS (1 << 2) 11666d8c9d2SKieran Bingham #define MAX9286_I2CMSTBT_8KBPS (0 << 2) 11766d8c9d2SKieran Bingham #define MAX9286_I2CSLVTO_NONE (3 << 0) 11866d8c9d2SKieran Bingham #define MAX9286_I2CSLVTO_1024US (2 << 0) 11966d8c9d2SKieran Bingham #define MAX9286_I2CSLVTO_256US (1 << 0) 12066d8c9d2SKieran Bingham #define MAX9286_I2CSLVTO_64US (0 << 0) 12166d8c9d2SKieran Bingham /* Register 0x3b */ 12266d8c9d2SKieran Bingham #define MAX9286_REV_TRF(n) ((n) << 4) 12366d8c9d2SKieran Bingham #define MAX9286_REV_AMP(n) ((((n) - 30) / 10) << 1) /* in mV */ 12466d8c9d2SKieran Bingham #define MAX9286_REV_AMP_X BIT(0) 125731c24ffSJacopo Mondi #define MAX9286_REV_AMP_HIGH 170 12666d8c9d2SKieran Bingham /* Register 0x3f */ 12766d8c9d2SKieran Bingham #define MAX9286_EN_REV_CFG BIT(6) 12866d8c9d2SKieran Bingham #define MAX9286_REV_FLEN(n) ((n) - 20) 12966d8c9d2SKieran Bingham /* Register 0x49 */ 13066d8c9d2SKieran Bingham #define MAX9286_VIDEO_DETECT_MASK 0x0f 13166d8c9d2SKieran Bingham /* Register 0x69 */ 13266d8c9d2SKieran Bingham #define MAX9286_LFLTBMONMASKED BIT(7) 13366d8c9d2SKieran Bingham #define MAX9286_LOCKMONMASKED BIT(6) 13466d8c9d2SKieran Bingham #define MAX9286_AUTOCOMBACKEN BIT(5) 13566d8c9d2SKieran Bingham #define MAX9286_AUTOMASKEN BIT(4) 13666d8c9d2SKieran Bingham #define MAX9286_MASKLINK(n) ((n) << 0) 13766d8c9d2SKieran Bingham 13866d8c9d2SKieran Bingham /* 13966d8c9d2SKieran Bingham * The sink and source pads are created to match the OF graph port numbers so 14066d8c9d2SKieran Bingham * that their indexes can be used interchangeably. 14166d8c9d2SKieran Bingham */ 14266d8c9d2SKieran Bingham #define MAX9286_NUM_GMSL 4 14366d8c9d2SKieran Bingham #define MAX9286_N_SINKS 4 14466d8c9d2SKieran Bingham #define MAX9286_N_PADS 5 14566d8c9d2SKieran Bingham #define MAX9286_SRC_PAD 4 14666d8c9d2SKieran Bingham 147f1403802SLaurent Pinchart struct max9286_format_info { 148f1403802SLaurent Pinchart u32 code; 149f1403802SLaurent Pinchart u8 datatype; 150f1403802SLaurent Pinchart }; 151f1403802SLaurent Pinchart 152e332061bSLaurent Pinchart struct max9286_i2c_speed { 153e332061bSLaurent Pinchart u32 rate; 154e332061bSLaurent Pinchart u8 mstbt; 155e332061bSLaurent Pinchart }; 156e332061bSLaurent Pinchart 15766d8c9d2SKieran Bingham struct max9286_source { 15866d8c9d2SKieran Bingham struct v4l2_subdev *sd; 15966d8c9d2SKieran Bingham struct fwnode_handle *fwnode; 160817660f4SThomas Nizan struct regulator *regulator; 16166d8c9d2SKieran Bingham }; 16266d8c9d2SKieran Bingham 16386d37bf3SLaurent Pinchart struct max9286_asd { 16486d37bf3SLaurent Pinchart struct v4l2_async_subdev base; 16586d37bf3SLaurent Pinchart struct max9286_source *source; 16686d37bf3SLaurent Pinchart }; 16786d37bf3SLaurent Pinchart 16886d37bf3SLaurent Pinchart static inline struct max9286_asd *to_max9286_asd(struct v4l2_async_subdev *asd) 16986d37bf3SLaurent Pinchart { 17086d37bf3SLaurent Pinchart return container_of(asd, struct max9286_asd, base); 17186d37bf3SLaurent Pinchart } 17266d8c9d2SKieran Bingham 17366d8c9d2SKieran Bingham struct max9286_priv { 17466d8c9d2SKieran Bingham struct i2c_client *client; 17566d8c9d2SKieran Bingham struct gpio_desc *gpiod_pwdn; 17666d8c9d2SKieran Bingham struct v4l2_subdev sd; 17766d8c9d2SKieran Bingham struct media_pad pads[MAX9286_N_PADS]; 17866d8c9d2SKieran Bingham struct regulator *regulator; 17966d8c9d2SKieran Bingham 18066d8c9d2SKieran Bingham struct gpio_chip gpio; 18166d8c9d2SKieran Bingham u8 gpio_state; 18266d8c9d2SKieran Bingham 18366d8c9d2SKieran Bingham struct i2c_mux_core *mux; 18466d8c9d2SKieran Bingham unsigned int mux_channel; 18566d8c9d2SKieran Bingham bool mux_open; 18666d8c9d2SKieran Bingham 187f78723ebSJacopo Mondi /* The initial reverse control channel amplitude. */ 188f78723ebSJacopo Mondi u32 init_rev_chan_mv; 189902edc2aSJacopo Mondi u32 rev_chan_mv; 190e332061bSLaurent Pinchart u8 i2c_mstbt; 1913697f108SLaurent Pinchart u32 bus_width; 19285cb767cSJacopo Mondi 193817660f4SThomas Nizan bool use_gpio_poc; 194c9352df7SJacopo Mondi u32 gpio_poc[2]; 195c9352df7SJacopo Mondi 19666d8c9d2SKieran Bingham struct v4l2_ctrl_handler ctrls; 197cffc9fb1SLaurent Pinchart struct v4l2_ctrl *pixelrate_ctrl; 198cffc9fb1SLaurent Pinchart unsigned int pixelrate; 19966d8c9d2SKieran Bingham 20066d8c9d2SKieran Bingham struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS]; 201cffc9fb1SLaurent Pinchart struct v4l2_fract interval; 20266d8c9d2SKieran Bingham 20366d8c9d2SKieran Bingham /* Protects controls and fmt structures */ 20466d8c9d2SKieran Bingham struct mutex mutex; 20566d8c9d2SKieran Bingham 20666d8c9d2SKieran Bingham unsigned int nsources; 20766d8c9d2SKieran Bingham unsigned int source_mask; 20866d8c9d2SKieran Bingham unsigned int route_mask; 20966d8c9d2SKieran Bingham unsigned int bound_sources; 21066d8c9d2SKieran Bingham unsigned int csi2_data_lanes; 21166d8c9d2SKieran Bingham struct max9286_source sources[MAX9286_NUM_GMSL]; 21266d8c9d2SKieran Bingham struct v4l2_async_notifier notifier; 21366d8c9d2SKieran Bingham }; 21466d8c9d2SKieran Bingham 21566d8c9d2SKieran Bingham static struct max9286_source *next_source(struct max9286_priv *priv, 21666d8c9d2SKieran Bingham struct max9286_source *source) 21766d8c9d2SKieran Bingham { 21866d8c9d2SKieran Bingham if (!source) 21966d8c9d2SKieran Bingham source = &priv->sources[0]; 22066d8c9d2SKieran Bingham else 22166d8c9d2SKieran Bingham source++; 22266d8c9d2SKieran Bingham 22366d8c9d2SKieran Bingham for (; source < &priv->sources[MAX9286_NUM_GMSL]; source++) { 22466d8c9d2SKieran Bingham if (source->fwnode) 22566d8c9d2SKieran Bingham return source; 22666d8c9d2SKieran Bingham } 22766d8c9d2SKieran Bingham 22866d8c9d2SKieran Bingham return NULL; 22966d8c9d2SKieran Bingham } 23066d8c9d2SKieran Bingham 23166d8c9d2SKieran Bingham #define for_each_source(priv, source) \ 23266d8c9d2SKieran Bingham for ((source) = NULL; ((source) = next_source((priv), (source))); ) 23366d8c9d2SKieran Bingham 23466d8c9d2SKieran Bingham #define to_index(priv, source) ((source) - &(priv)->sources[0]) 23566d8c9d2SKieran Bingham 23666d8c9d2SKieran Bingham static inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd) 23766d8c9d2SKieran Bingham { 23866d8c9d2SKieran Bingham return container_of(sd, struct max9286_priv, sd); 23966d8c9d2SKieran Bingham } 24066d8c9d2SKieran Bingham 241f1403802SLaurent Pinchart static const struct max9286_format_info max9286_formats[] = { 242f1403802SLaurent Pinchart { 243f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_UYVY8_1X16, 244f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_YUV422_8BIT, 245f1403802SLaurent Pinchart }, { 246f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_VYUY8_1X16, 247f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_YUV422_8BIT, 248f1403802SLaurent Pinchart }, { 249f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_YUYV8_1X16, 250f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_YUV422_8BIT, 251f1403802SLaurent Pinchart }, { 252f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_YVYU8_1X16, 253f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_YUV422_8BIT, 254f1403802SLaurent Pinchart }, { 255f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_SBGGR12_1X12, 256f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_RAW12, 257f1403802SLaurent Pinchart }, { 258f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_SGBRG12_1X12, 259f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_RAW12, 260f1403802SLaurent Pinchart }, { 261f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_SGRBG12_1X12, 262f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_RAW12, 263f1403802SLaurent Pinchart }, { 264f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_SRGGB12_1X12, 265f1403802SLaurent Pinchart .datatype = MAX9286_DATATYPE_RAW12, 266f1403802SLaurent Pinchart }, 267f1403802SLaurent Pinchart }; 268f1403802SLaurent Pinchart 269e332061bSLaurent Pinchart static const struct max9286_i2c_speed max9286_i2c_speeds[] = { 270e332061bSLaurent Pinchart { .rate = 8470, .mstbt = MAX9286_I2CMSTBT_8KBPS }, 271e332061bSLaurent Pinchart { .rate = 28300, .mstbt = MAX9286_I2CMSTBT_28KBPS }, 272e332061bSLaurent Pinchart { .rate = 84700, .mstbt = MAX9286_I2CMSTBT_84KBPS }, 273e332061bSLaurent Pinchart { .rate = 105000, .mstbt = MAX9286_I2CMSTBT_105KBPS }, 274e332061bSLaurent Pinchart { .rate = 173000, .mstbt = MAX9286_I2CMSTBT_173KBPS }, 275e332061bSLaurent Pinchart { .rate = 339000, .mstbt = MAX9286_I2CMSTBT_339KBPS }, 276e332061bSLaurent Pinchart { .rate = 533000, .mstbt = MAX9286_I2CMSTBT_533KBPS }, 277e332061bSLaurent Pinchart { .rate = 837000, .mstbt = MAX9286_I2CMSTBT_837KBPS }, 278e332061bSLaurent Pinchart }; 279e332061bSLaurent Pinchart 28066d8c9d2SKieran Bingham /* ----------------------------------------------------------------------------- 28166d8c9d2SKieran Bingham * I2C IO 28266d8c9d2SKieran Bingham */ 28366d8c9d2SKieran Bingham 28466d8c9d2SKieran Bingham static int max9286_read(struct max9286_priv *priv, u8 reg) 28566d8c9d2SKieran Bingham { 28666d8c9d2SKieran Bingham int ret; 28766d8c9d2SKieran Bingham 28866d8c9d2SKieran Bingham ret = i2c_smbus_read_byte_data(priv->client, reg); 28966d8c9d2SKieran Bingham if (ret < 0) 29066d8c9d2SKieran Bingham dev_err(&priv->client->dev, 29166d8c9d2SKieran Bingham "%s: register 0x%02x read failed (%d)\n", 29266d8c9d2SKieran Bingham __func__, reg, ret); 29366d8c9d2SKieran Bingham 29466d8c9d2SKieran Bingham return ret; 29566d8c9d2SKieran Bingham } 29666d8c9d2SKieran Bingham 29766d8c9d2SKieran Bingham static int max9286_write(struct max9286_priv *priv, u8 reg, u8 val) 29866d8c9d2SKieran Bingham { 29966d8c9d2SKieran Bingham int ret; 30066d8c9d2SKieran Bingham 30166d8c9d2SKieran Bingham ret = i2c_smbus_write_byte_data(priv->client, reg, val); 30266d8c9d2SKieran Bingham if (ret < 0) 30366d8c9d2SKieran Bingham dev_err(&priv->client->dev, 30466d8c9d2SKieran Bingham "%s: register 0x%02x write failed (%d)\n", 30566d8c9d2SKieran Bingham __func__, reg, ret); 30666d8c9d2SKieran Bingham 30766d8c9d2SKieran Bingham return ret; 30866d8c9d2SKieran Bingham } 30966d8c9d2SKieran Bingham 31066d8c9d2SKieran Bingham /* ----------------------------------------------------------------------------- 31166d8c9d2SKieran Bingham * I2C Multiplexer 31266d8c9d2SKieran Bingham */ 31366d8c9d2SKieran Bingham 31466d8c9d2SKieran Bingham static void max9286_i2c_mux_configure(struct max9286_priv *priv, u8 conf) 31566d8c9d2SKieran Bingham { 31666d8c9d2SKieran Bingham max9286_write(priv, 0x0a, conf); 31766d8c9d2SKieran Bingham 31866d8c9d2SKieran Bingham /* 31966d8c9d2SKieran Bingham * We must sleep after any change to the forward or reverse channel 32066d8c9d2SKieran Bingham * configuration. 32166d8c9d2SKieran Bingham */ 32266d8c9d2SKieran Bingham usleep_range(3000, 5000); 32366d8c9d2SKieran Bingham } 32466d8c9d2SKieran Bingham 32566d8c9d2SKieran Bingham static void max9286_i2c_mux_open(struct max9286_priv *priv) 32666d8c9d2SKieran Bingham { 32766d8c9d2SKieran Bingham /* Open all channels on the MAX9286 */ 32866d8c9d2SKieran Bingham max9286_i2c_mux_configure(priv, 0xff); 32966d8c9d2SKieran Bingham 33066d8c9d2SKieran Bingham priv->mux_open = true; 33166d8c9d2SKieran Bingham } 33266d8c9d2SKieran Bingham 33366d8c9d2SKieran Bingham static void max9286_i2c_mux_close(struct max9286_priv *priv) 33466d8c9d2SKieran Bingham { 33566d8c9d2SKieran Bingham /* 33666d8c9d2SKieran Bingham * Ensure that both the forward and reverse channel are disabled on the 33766d8c9d2SKieran Bingham * mux, and that the channel ID is invalidated to ensure we reconfigure 33866d8c9d2SKieran Bingham * on the next max9286_i2c_mux_select() call. 33966d8c9d2SKieran Bingham */ 34066d8c9d2SKieran Bingham max9286_i2c_mux_configure(priv, 0x00); 34166d8c9d2SKieran Bingham 34266d8c9d2SKieran Bingham priv->mux_open = false; 34366d8c9d2SKieran Bingham priv->mux_channel = -1; 34466d8c9d2SKieran Bingham } 34566d8c9d2SKieran Bingham 34666d8c9d2SKieran Bingham static int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) 34766d8c9d2SKieran Bingham { 34866d8c9d2SKieran Bingham struct max9286_priv *priv = i2c_mux_priv(muxc); 34966d8c9d2SKieran Bingham 35066d8c9d2SKieran Bingham /* Channel select is disabled when configured in the opened state. */ 35166d8c9d2SKieran Bingham if (priv->mux_open) 35266d8c9d2SKieran Bingham return 0; 35366d8c9d2SKieran Bingham 35466d8c9d2SKieran Bingham if (priv->mux_channel == chan) 35566d8c9d2SKieran Bingham return 0; 35666d8c9d2SKieran Bingham 35766d8c9d2SKieran Bingham priv->mux_channel = chan; 35866d8c9d2SKieran Bingham 3593de09c7aSJacopo Mondi max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) | 36066d8c9d2SKieran Bingham MAX9286_REVCCEN(chan)); 36166d8c9d2SKieran Bingham 36266d8c9d2SKieran Bingham return 0; 36366d8c9d2SKieran Bingham } 36466d8c9d2SKieran Bingham 36566d8c9d2SKieran Bingham static int max9286_i2c_mux_init(struct max9286_priv *priv) 36666d8c9d2SKieran Bingham { 36766d8c9d2SKieran Bingham struct max9286_source *source; 36866d8c9d2SKieran Bingham int ret; 36966d8c9d2SKieran Bingham 37066d8c9d2SKieran Bingham if (!i2c_check_functionality(priv->client->adapter, 37166d8c9d2SKieran Bingham I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 37266d8c9d2SKieran Bingham return -ENODEV; 37366d8c9d2SKieran Bingham 37466d8c9d2SKieran Bingham priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev, 37566d8c9d2SKieran Bingham priv->nsources, 0, I2C_MUX_LOCKED, 37666d8c9d2SKieran Bingham max9286_i2c_mux_select, NULL); 37766d8c9d2SKieran Bingham if (!priv->mux) 37866d8c9d2SKieran Bingham return -ENOMEM; 37966d8c9d2SKieran Bingham 38066d8c9d2SKieran Bingham priv->mux->priv = priv; 38166d8c9d2SKieran Bingham 38266d8c9d2SKieran Bingham for_each_source(priv, source) { 38366d8c9d2SKieran Bingham unsigned int index = to_index(priv, source); 38466d8c9d2SKieran Bingham 38566d8c9d2SKieran Bingham ret = i2c_mux_add_adapter(priv->mux, 0, index, 0); 38666d8c9d2SKieran Bingham if (ret < 0) 38766d8c9d2SKieran Bingham goto error; 38866d8c9d2SKieran Bingham } 38966d8c9d2SKieran Bingham 39066d8c9d2SKieran Bingham return 0; 39166d8c9d2SKieran Bingham 39266d8c9d2SKieran Bingham error: 39366d8c9d2SKieran Bingham i2c_mux_del_adapters(priv->mux); 39466d8c9d2SKieran Bingham return ret; 39566d8c9d2SKieran Bingham } 39666d8c9d2SKieran Bingham 39766d8c9d2SKieran Bingham static void max9286_configure_i2c(struct max9286_priv *priv, bool localack) 39866d8c9d2SKieran Bingham { 39966d8c9d2SKieran Bingham u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US | 400e332061bSLaurent Pinchart priv->i2c_mstbt; 40166d8c9d2SKieran Bingham 40266d8c9d2SKieran Bingham if (localack) 40366d8c9d2SKieran Bingham config |= MAX9286_I2CLOCACK; 40466d8c9d2SKieran Bingham 40566d8c9d2SKieran Bingham max9286_write(priv, 0x34, config); 40666d8c9d2SKieran Bingham usleep_range(3000, 5000); 40766d8c9d2SKieran Bingham } 40866d8c9d2SKieran Bingham 4095a386b1fSJacopo Mondi static void max9286_reverse_channel_setup(struct max9286_priv *priv, 4105a386b1fSJacopo Mondi unsigned int chan_amplitude) 41102b57eb3SJacopo Mondi { 412902edc2aSJacopo Mondi u8 chan_config; 413902edc2aSJacopo Mondi 414902edc2aSJacopo Mondi if (priv->rev_chan_mv == chan_amplitude) 415902edc2aSJacopo Mondi return; 416902edc2aSJacopo Mondi 417902edc2aSJacopo Mondi priv->rev_chan_mv = chan_amplitude; 418902edc2aSJacopo Mondi 4195a386b1fSJacopo Mondi /* Reverse channel transmission time: default to 1. */ 420902edc2aSJacopo Mondi chan_config = MAX9286_REV_TRF(1); 4215a386b1fSJacopo Mondi 42202b57eb3SJacopo Mondi /* 42302b57eb3SJacopo Mondi * Reverse channel setup. 42402b57eb3SJacopo Mondi * 42502b57eb3SJacopo Mondi * - Enable custom reverse channel configuration (through register 0x3f) 42602b57eb3SJacopo Mondi * and set the first pulse length to 35 clock cycles. 4275a386b1fSJacopo Mondi * - Adjust reverse channel amplitude: values > 130 are programmed 4285a386b1fSJacopo Mondi * using the additional +100mV REV_AMP_X boost flag 42902b57eb3SJacopo Mondi */ 43002b57eb3SJacopo Mondi max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35)); 4315a386b1fSJacopo Mondi 4325a386b1fSJacopo Mondi if (chan_amplitude > 100) { 4335a386b1fSJacopo Mondi /* It is not possible to express values (100 < x < 130) */ 4345a386b1fSJacopo Mondi chan_amplitude = max(30U, chan_amplitude - 100); 4355a386b1fSJacopo Mondi chan_config |= MAX9286_REV_AMP_X; 4365a386b1fSJacopo Mondi } 4375a386b1fSJacopo Mondi max9286_write(priv, 0x3b, chan_config | MAX9286_REV_AMP(chan_amplitude)); 43802b57eb3SJacopo Mondi usleep_range(2000, 2500); 43902b57eb3SJacopo Mondi } 44002b57eb3SJacopo Mondi 44166d8c9d2SKieran Bingham /* 44266d8c9d2SKieran Bingham * max9286_check_video_links() - Make sure video links are detected and locked 44366d8c9d2SKieran Bingham * 44466d8c9d2SKieran Bingham * Performs safety checks on video link status. Make sure they are detected 44566d8c9d2SKieran Bingham * and all enabled links are locked. 44666d8c9d2SKieran Bingham * 44766d8c9d2SKieran Bingham * Returns 0 for success, -EIO for errors. 44866d8c9d2SKieran Bingham */ 44966d8c9d2SKieran Bingham static int max9286_check_video_links(struct max9286_priv *priv) 45066d8c9d2SKieran Bingham { 45166d8c9d2SKieran Bingham unsigned int i; 45266d8c9d2SKieran Bingham int ret; 45366d8c9d2SKieran Bingham 45466d8c9d2SKieran Bingham /* 45566d8c9d2SKieran Bingham * Make sure valid video links are detected. 45666d8c9d2SKieran Bingham * The delay is not characterized in de-serializer manual, wait up 45766d8c9d2SKieran Bingham * to 5 ms. 45866d8c9d2SKieran Bingham */ 45966d8c9d2SKieran Bingham for (i = 0; i < 10; i++) { 46066d8c9d2SKieran Bingham ret = max9286_read(priv, 0x49); 46166d8c9d2SKieran Bingham if (ret < 0) 46266d8c9d2SKieran Bingham return -EIO; 46366d8c9d2SKieran Bingham 46466d8c9d2SKieran Bingham if ((ret & MAX9286_VIDEO_DETECT_MASK) == priv->source_mask) 46566d8c9d2SKieran Bingham break; 46666d8c9d2SKieran Bingham 46766d8c9d2SKieran Bingham usleep_range(350, 500); 46866d8c9d2SKieran Bingham } 46966d8c9d2SKieran Bingham 47066d8c9d2SKieran Bingham if (i == 10) { 47166d8c9d2SKieran Bingham dev_err(&priv->client->dev, 47266d8c9d2SKieran Bingham "Unable to detect video links: 0x%02x\n", ret); 47366d8c9d2SKieran Bingham return -EIO; 47466d8c9d2SKieran Bingham } 47566d8c9d2SKieran Bingham 47666d8c9d2SKieran Bingham /* Make sure all enabled links are locked (4ms max). */ 47766d8c9d2SKieran Bingham for (i = 0; i < 10; i++) { 47866d8c9d2SKieran Bingham ret = max9286_read(priv, 0x27); 47966d8c9d2SKieran Bingham if (ret < 0) 48066d8c9d2SKieran Bingham return -EIO; 48166d8c9d2SKieran Bingham 48266d8c9d2SKieran Bingham if (ret & MAX9286_LOCKED) 48366d8c9d2SKieran Bingham break; 48466d8c9d2SKieran Bingham 48566d8c9d2SKieran Bingham usleep_range(350, 450); 48666d8c9d2SKieran Bingham } 48766d8c9d2SKieran Bingham 48866d8c9d2SKieran Bingham if (i == 10) { 48966d8c9d2SKieran Bingham dev_err(&priv->client->dev, "Not all enabled links locked\n"); 49066d8c9d2SKieran Bingham return -EIO; 49166d8c9d2SKieran Bingham } 49266d8c9d2SKieran Bingham 49366d8c9d2SKieran Bingham return 0; 49466d8c9d2SKieran Bingham } 49566d8c9d2SKieran Bingham 49666d8c9d2SKieran Bingham /* 49766d8c9d2SKieran Bingham * max9286_check_config_link() - Detect and wait for configuration links 49866d8c9d2SKieran Bingham * 49966d8c9d2SKieran Bingham * Determine if the configuration channel is up and settled for a link. 50066d8c9d2SKieran Bingham * 50166d8c9d2SKieran Bingham * Returns 0 for success, -EIO for errors. 50266d8c9d2SKieran Bingham */ 50366d8c9d2SKieran Bingham static int max9286_check_config_link(struct max9286_priv *priv, 50466d8c9d2SKieran Bingham unsigned int source_mask) 50566d8c9d2SKieran Bingham { 50666d8c9d2SKieran Bingham unsigned int conflink_mask = (source_mask & 0x0f) << 4; 50766d8c9d2SKieran Bingham unsigned int i; 50866d8c9d2SKieran Bingham int ret; 50966d8c9d2SKieran Bingham 51066d8c9d2SKieran Bingham /* 51166d8c9d2SKieran Bingham * Make sure requested configuration links are detected. 51266d8c9d2SKieran Bingham * The delay is not characterized in the chip manual: wait up 51366d8c9d2SKieran Bingham * to 5 milliseconds. 51466d8c9d2SKieran Bingham */ 51566d8c9d2SKieran Bingham for (i = 0; i < 10; i++) { 516e5b95c8fSColin Ian King ret = max9286_read(priv, 0x49); 51766d8c9d2SKieran Bingham if (ret < 0) 51866d8c9d2SKieran Bingham return -EIO; 51966d8c9d2SKieran Bingham 520e5b95c8fSColin Ian King ret &= 0xf0; 52166d8c9d2SKieran Bingham if (ret == conflink_mask) 52266d8c9d2SKieran Bingham break; 52366d8c9d2SKieran Bingham 52466d8c9d2SKieran Bingham usleep_range(350, 500); 52566d8c9d2SKieran Bingham } 52666d8c9d2SKieran Bingham 52766d8c9d2SKieran Bingham if (ret != conflink_mask) { 52866d8c9d2SKieran Bingham dev_err(&priv->client->dev, 52966d8c9d2SKieran Bingham "Unable to detect configuration links: 0x%02x expected 0x%02x\n", 53066d8c9d2SKieran Bingham ret, conflink_mask); 53166d8c9d2SKieran Bingham return -EIO; 53266d8c9d2SKieran Bingham } 53366d8c9d2SKieran Bingham 53466d8c9d2SKieran Bingham dev_info(&priv->client->dev, 53566d8c9d2SKieran Bingham "Successfully detected configuration links after %u loops: 0x%02x\n", 53666d8c9d2SKieran Bingham i, conflink_mask); 53766d8c9d2SKieran Bingham 53866d8c9d2SKieran Bingham return 0; 53966d8c9d2SKieran Bingham } 54066d8c9d2SKieran Bingham 541f1403802SLaurent Pinchart static void max9286_set_video_format(struct max9286_priv *priv, 542f1403802SLaurent Pinchart const struct v4l2_mbus_framefmt *format) 543f1403802SLaurent Pinchart { 544f1403802SLaurent Pinchart const struct max9286_format_info *info = NULL; 545f1403802SLaurent Pinchart unsigned int i; 546f1403802SLaurent Pinchart 547f1403802SLaurent Pinchart for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { 548f1403802SLaurent Pinchart if (max9286_formats[i].code == format->code) { 549f1403802SLaurent Pinchart info = &max9286_formats[i]; 550f1403802SLaurent Pinchart break; 551f1403802SLaurent Pinchart } 552f1403802SLaurent Pinchart } 553f1403802SLaurent Pinchart 554f1403802SLaurent Pinchart if (WARN_ON(!info)) 555f1403802SLaurent Pinchart return; 556f1403802SLaurent Pinchart 557f1403802SLaurent Pinchart /* 558cdcb186eSLaurent Pinchart * Video format setup: disable CSI output, set VC according to Link 559cdcb186eSLaurent Pinchart * number, enable I2C clock stretching when CCBSY is low, enable CCBSY 560cdcb186eSLaurent Pinchart * in external GPI-to-GPO mode. 561f1403802SLaurent Pinchart */ 562cdcb186eSLaurent Pinchart max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_EN_CCBSYB_CLK_STR | 563cdcb186eSLaurent Pinchart MAX9286_EN_GPI_CCBSYB); 564f1403802SLaurent Pinchart 565f1403802SLaurent Pinchart /* Enable CSI-2 Lane D0-D3 only, DBL mode. */ 566f1403802SLaurent Pinchart max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL | 567f1403802SLaurent Pinchart MAX9286_CSILANECNT(priv->csi2_data_lanes) | 568f1403802SLaurent Pinchart info->datatype); 569f1403802SLaurent Pinchart 57040f75457SLaurent Pinchart /* 57140f75457SLaurent Pinchart * Enable HS/VS encoding, use HS as line valid source, use D14/15 for 57240f75457SLaurent Pinchart * HS/VS, invert VS. 57340f75457SLaurent Pinchart */ 57440f75457SLaurent Pinchart max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_DESEL | 57540f75457SLaurent Pinchart MAX9286_INVVS | MAX9286_HVSRC_D14); 576f1403802SLaurent Pinchart } 577f1403802SLaurent Pinchart 578cffc9fb1SLaurent Pinchart static void max9286_set_fsync_period(struct max9286_priv *priv) 579cffc9fb1SLaurent Pinchart { 580cffc9fb1SLaurent Pinchart u32 fsync; 581cffc9fb1SLaurent Pinchart 582cffc9fb1SLaurent Pinchart if (!priv->interval.numerator || !priv->interval.denominator) { 583cffc9fb1SLaurent Pinchart /* 584cffc9fb1SLaurent Pinchart * Special case, a null interval enables automatic FRAMESYNC 585cffc9fb1SLaurent Pinchart * mode. FRAMESYNC is taken from the slowest link. 586cffc9fb1SLaurent Pinchart */ 587cffc9fb1SLaurent Pinchart max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ | 588cffc9fb1SLaurent Pinchart MAX9286_FSYNCMETH_AUTO); 589cffc9fb1SLaurent Pinchart return; 590cffc9fb1SLaurent Pinchart } 591cffc9fb1SLaurent Pinchart 592cffc9fb1SLaurent Pinchart /* 593cffc9fb1SLaurent Pinchart * Manual FRAMESYNC 594cffc9fb1SLaurent Pinchart * 595cffc9fb1SLaurent Pinchart * The FRAMESYNC generator is configured with a period expressed as a 596cffc9fb1SLaurent Pinchart * number of PCLK periods. 597cffc9fb1SLaurent Pinchart */ 598cffc9fb1SLaurent Pinchart fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator, 599cffc9fb1SLaurent Pinchart priv->interval.denominator); 600cffc9fb1SLaurent Pinchart 601cffc9fb1SLaurent Pinchart dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, 602cffc9fb1SLaurent Pinchart priv->pixelrate); 603cffc9fb1SLaurent Pinchart 604cffc9fb1SLaurent Pinchart max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT | 605cffc9fb1SLaurent Pinchart MAX9286_FSYNCMETH_MANUAL); 606cffc9fb1SLaurent Pinchart 607cffc9fb1SLaurent Pinchart max9286_write(priv, 0x06, (fsync >> 0) & 0xff); 608cffc9fb1SLaurent Pinchart max9286_write(priv, 0x07, (fsync >> 8) & 0xff); 609cffc9fb1SLaurent Pinchart max9286_write(priv, 0x08, (fsync >> 16) & 0xff); 610cffc9fb1SLaurent Pinchart } 611cffc9fb1SLaurent Pinchart 61266d8c9d2SKieran Bingham /* ----------------------------------------------------------------------------- 61366d8c9d2SKieran Bingham * V4L2 Subdev 61466d8c9d2SKieran Bingham */ 61566d8c9d2SKieran Bingham 61666d8c9d2SKieran Bingham static int max9286_set_pixelrate(struct max9286_priv *priv) 61766d8c9d2SKieran Bingham { 61866d8c9d2SKieran Bingham struct max9286_source *source = NULL; 61966d8c9d2SKieran Bingham u64 pixelrate = 0; 62066d8c9d2SKieran Bingham 62166d8c9d2SKieran Bingham for_each_source(priv, source) { 62266d8c9d2SKieran Bingham struct v4l2_ctrl *ctrl; 62366d8c9d2SKieran Bingham u64 source_rate = 0; 62466d8c9d2SKieran Bingham 62566d8c9d2SKieran Bingham /* Pixel rate is mandatory to be reported by sources. */ 62666d8c9d2SKieran Bingham ctrl = v4l2_ctrl_find(source->sd->ctrl_handler, 62766d8c9d2SKieran Bingham V4L2_CID_PIXEL_RATE); 62866d8c9d2SKieran Bingham if (!ctrl) { 62966d8c9d2SKieran Bingham pixelrate = 0; 63066d8c9d2SKieran Bingham break; 63166d8c9d2SKieran Bingham } 63266d8c9d2SKieran Bingham 63366d8c9d2SKieran Bingham /* All source must report the same pixel rate. */ 63466d8c9d2SKieran Bingham source_rate = v4l2_ctrl_g_ctrl_int64(ctrl); 63566d8c9d2SKieran Bingham if (!pixelrate) { 63666d8c9d2SKieran Bingham pixelrate = source_rate; 63766d8c9d2SKieran Bingham } else if (pixelrate != source_rate) { 63866d8c9d2SKieran Bingham dev_err(&priv->client->dev, 63966d8c9d2SKieran Bingham "Unable to calculate pixel rate\n"); 64066d8c9d2SKieran Bingham return -EINVAL; 64166d8c9d2SKieran Bingham } 64266d8c9d2SKieran Bingham } 64366d8c9d2SKieran Bingham 64466d8c9d2SKieran Bingham if (!pixelrate) { 64566d8c9d2SKieran Bingham dev_err(&priv->client->dev, 64666d8c9d2SKieran Bingham "No pixel rate control available in sources\n"); 64766d8c9d2SKieran Bingham return -EINVAL; 64866d8c9d2SKieran Bingham } 64966d8c9d2SKieran Bingham 650cffc9fb1SLaurent Pinchart priv->pixelrate = pixelrate; 651cffc9fb1SLaurent Pinchart 65266d8c9d2SKieran Bingham /* 65366d8c9d2SKieran Bingham * The CSI-2 transmitter pixel rate is the single source rate multiplied 65466d8c9d2SKieran Bingham * by the number of available sources. 65566d8c9d2SKieran Bingham */ 656cffc9fb1SLaurent Pinchart return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl, 65766d8c9d2SKieran Bingham pixelrate * priv->nsources); 65866d8c9d2SKieran Bingham } 65966d8c9d2SKieran Bingham 66066d8c9d2SKieran Bingham static int max9286_notify_bound(struct v4l2_async_notifier *notifier, 66166d8c9d2SKieran Bingham struct v4l2_subdev *subdev, 66266d8c9d2SKieran Bingham struct v4l2_async_subdev *asd) 66366d8c9d2SKieran Bingham { 66466d8c9d2SKieran Bingham struct max9286_priv *priv = sd_to_max9286(notifier->sd); 66586d37bf3SLaurent Pinchart struct max9286_source *source = to_max9286_asd(asd)->source; 66666d8c9d2SKieran Bingham unsigned int index = to_index(priv, source); 66766d8c9d2SKieran Bingham unsigned int src_pad; 66866d8c9d2SKieran Bingham int ret; 66966d8c9d2SKieran Bingham 67066d8c9d2SKieran Bingham ret = media_entity_get_fwnode_pad(&subdev->entity, 67166d8c9d2SKieran Bingham source->fwnode, 67266d8c9d2SKieran Bingham MEDIA_PAD_FL_SOURCE); 67366d8c9d2SKieran Bingham if (ret < 0) { 67466d8c9d2SKieran Bingham dev_err(&priv->client->dev, 67566d8c9d2SKieran Bingham "Failed to find pad for %s\n", subdev->name); 67666d8c9d2SKieran Bingham return ret; 67766d8c9d2SKieran Bingham } 67866d8c9d2SKieran Bingham 67966d8c9d2SKieran Bingham priv->bound_sources |= BIT(index); 68066d8c9d2SKieran Bingham source->sd = subdev; 68166d8c9d2SKieran Bingham src_pad = ret; 68266d8c9d2SKieran Bingham 68366d8c9d2SKieran Bingham ret = media_create_pad_link(&source->sd->entity, src_pad, 68466d8c9d2SKieran Bingham &priv->sd.entity, index, 68566d8c9d2SKieran Bingham MEDIA_LNK_FL_ENABLED | 68666d8c9d2SKieran Bingham MEDIA_LNK_FL_IMMUTABLE); 68766d8c9d2SKieran Bingham if (ret) { 68866d8c9d2SKieran Bingham dev_err(&priv->client->dev, 68966d8c9d2SKieran Bingham "Unable to link %s:%u -> %s:%u\n", 69066d8c9d2SKieran Bingham source->sd->name, src_pad, priv->sd.name, index); 69166d8c9d2SKieran Bingham return ret; 69266d8c9d2SKieran Bingham } 69366d8c9d2SKieran Bingham 69466d8c9d2SKieran Bingham dev_dbg(&priv->client->dev, "Bound %s pad: %u on index %u\n", 69566d8c9d2SKieran Bingham subdev->name, src_pad, index); 69666d8c9d2SKieran Bingham 69766d8c9d2SKieran Bingham /* 6984ff5278dSJacopo Mondi * As we register a subdev notifiers we won't get a .complete() callback 6994ff5278dSJacopo Mondi * here, so we have to use bound_sources to identify when all remote 7004ff5278dSJacopo Mondi * serializers have probed. 70166d8c9d2SKieran Bingham */ 70266d8c9d2SKieran Bingham if (priv->bound_sources != priv->source_mask) 70366d8c9d2SKieran Bingham return 0; 70466d8c9d2SKieran Bingham 70566d8c9d2SKieran Bingham /* 70666d8c9d2SKieran Bingham * All enabled sources have probed and enabled their reverse control 70766d8c9d2SKieran Bingham * channels: 70866d8c9d2SKieran Bingham * 70985cb767cSJacopo Mondi * - Increase the reverse channel amplitude to compensate for the 710731c24ffSJacopo Mondi * remote ends high threshold 71166d8c9d2SKieran Bingham * - Verify all configuration links are properly detected 71266d8c9d2SKieran Bingham * - Disable auto-ack as communication on the control channel are now 71366d8c9d2SKieran Bingham * stable. 71466d8c9d2SKieran Bingham */ 715731c24ffSJacopo Mondi max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH); 71666d8c9d2SKieran Bingham max9286_check_config_link(priv, priv->source_mask); 71766d8c9d2SKieran Bingham max9286_configure_i2c(priv, false); 71866d8c9d2SKieran Bingham 71966d8c9d2SKieran Bingham return max9286_set_pixelrate(priv); 72066d8c9d2SKieran Bingham } 72166d8c9d2SKieran Bingham 72266d8c9d2SKieran Bingham static void max9286_notify_unbind(struct v4l2_async_notifier *notifier, 72366d8c9d2SKieran Bingham struct v4l2_subdev *subdev, 72466d8c9d2SKieran Bingham struct v4l2_async_subdev *asd) 72566d8c9d2SKieran Bingham { 72666d8c9d2SKieran Bingham struct max9286_priv *priv = sd_to_max9286(notifier->sd); 72786d37bf3SLaurent Pinchart struct max9286_source *source = to_max9286_asd(asd)->source; 72866d8c9d2SKieran Bingham unsigned int index = to_index(priv, source); 72966d8c9d2SKieran Bingham 73066d8c9d2SKieran Bingham source->sd = NULL; 73166d8c9d2SKieran Bingham priv->bound_sources &= ~BIT(index); 73266d8c9d2SKieran Bingham } 73366d8c9d2SKieran Bingham 73466d8c9d2SKieran Bingham static const struct v4l2_async_notifier_operations max9286_notify_ops = { 73566d8c9d2SKieran Bingham .bound = max9286_notify_bound, 73666d8c9d2SKieran Bingham .unbind = max9286_notify_unbind, 73766d8c9d2SKieran Bingham }; 73866d8c9d2SKieran Bingham 73966d8c9d2SKieran Bingham static int max9286_v4l2_notifier_register(struct max9286_priv *priv) 74066d8c9d2SKieran Bingham { 74166d8c9d2SKieran Bingham struct device *dev = &priv->client->dev; 74266d8c9d2SKieran Bingham struct max9286_source *source = NULL; 74366d8c9d2SKieran Bingham int ret; 74466d8c9d2SKieran Bingham 74566d8c9d2SKieran Bingham if (!priv->nsources) 74666d8c9d2SKieran Bingham return 0; 74766d8c9d2SKieran Bingham 7483c8c1539SSakari Ailus v4l2_async_nf_init(&priv->notifier); 74966d8c9d2SKieran Bingham 75066d8c9d2SKieran Bingham for_each_source(priv, source) { 75166d8c9d2SKieran Bingham unsigned int i = to_index(priv, source); 752b01edcbdSLaurent Pinchart struct max9286_asd *mas; 75366d8c9d2SKieran Bingham 7543c8c1539SSakari Ailus mas = v4l2_async_nf_add_fwnode(&priv->notifier, source->fwnode, 755b01edcbdSLaurent Pinchart struct max9286_asd); 756b01edcbdSLaurent Pinchart if (IS_ERR(mas)) { 75786d37bf3SLaurent Pinchart dev_err(dev, "Failed to add subdev for source %u: %ld", 758b01edcbdSLaurent Pinchart i, PTR_ERR(mas)); 7593c8c1539SSakari Ailus v4l2_async_nf_cleanup(&priv->notifier); 760b01edcbdSLaurent Pinchart return PTR_ERR(mas); 76166d8c9d2SKieran Bingham } 76266d8c9d2SKieran Bingham 763b01edcbdSLaurent Pinchart mas->source = source; 76466d8c9d2SKieran Bingham } 76566d8c9d2SKieran Bingham 76666d8c9d2SKieran Bingham priv->notifier.ops = &max9286_notify_ops; 76766d8c9d2SKieran Bingham 7683c8c1539SSakari Ailus ret = v4l2_async_subdev_nf_register(&priv->sd, &priv->notifier); 76966d8c9d2SKieran Bingham if (ret) { 77066d8c9d2SKieran Bingham dev_err(dev, "Failed to register subdev_notifier"); 7713c8c1539SSakari Ailus v4l2_async_nf_cleanup(&priv->notifier); 77266d8c9d2SKieran Bingham return ret; 77366d8c9d2SKieran Bingham } 77466d8c9d2SKieran Bingham 77566d8c9d2SKieran Bingham return 0; 77666d8c9d2SKieran Bingham } 77766d8c9d2SKieran Bingham 77866d8c9d2SKieran Bingham static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) 77966d8c9d2SKieran Bingham { 78066d8c9d2SKieran Bingham if (!priv->nsources) 78166d8c9d2SKieran Bingham return; 78266d8c9d2SKieran Bingham 7833c8c1539SSakari Ailus v4l2_async_nf_unregister(&priv->notifier); 7843c8c1539SSakari Ailus v4l2_async_nf_cleanup(&priv->notifier); 78566d8c9d2SKieran Bingham } 78666d8c9d2SKieran Bingham 78766d8c9d2SKieran Bingham static int max9286_s_stream(struct v4l2_subdev *sd, int enable) 78866d8c9d2SKieran Bingham { 78966d8c9d2SKieran Bingham struct max9286_priv *priv = sd_to_max9286(sd); 79066d8c9d2SKieran Bingham struct max9286_source *source; 79166d8c9d2SKieran Bingham unsigned int i; 79266d8c9d2SKieran Bingham bool sync = false; 79366d8c9d2SKieran Bingham int ret; 79466d8c9d2SKieran Bingham 79566d8c9d2SKieran Bingham if (enable) { 796f1403802SLaurent Pinchart const struct v4l2_mbus_framefmt *format; 797f1403802SLaurent Pinchart 798f1403802SLaurent Pinchart /* 799f1403802SLaurent Pinchart * Get the format from the first used sink pad, as all sink 800f1403802SLaurent Pinchart * formats must be identical. 801f1403802SLaurent Pinchart */ 802f1403802SLaurent Pinchart format = &priv->fmt[__ffs(priv->bound_sources)]; 803f1403802SLaurent Pinchart 804f1403802SLaurent Pinchart max9286_set_video_format(priv, format); 805cffc9fb1SLaurent Pinchart max9286_set_fsync_period(priv); 806cffc9fb1SLaurent Pinchart 80766d8c9d2SKieran Bingham /* 80866d8c9d2SKieran Bingham * The frame sync between cameras is transmitted across the 80966d8c9d2SKieran Bingham * reverse channel as GPIO. We must open all channels while 81066d8c9d2SKieran Bingham * streaming to allow this synchronisation signal to be shared. 81166d8c9d2SKieran Bingham */ 81266d8c9d2SKieran Bingham max9286_i2c_mux_open(priv); 81366d8c9d2SKieran Bingham 81466d8c9d2SKieran Bingham /* Start all cameras. */ 81566d8c9d2SKieran Bingham for_each_source(priv, source) { 81666d8c9d2SKieran Bingham ret = v4l2_subdev_call(source->sd, video, s_stream, 1); 81766d8c9d2SKieran Bingham if (ret) 81866d8c9d2SKieran Bingham return ret; 81966d8c9d2SKieran Bingham } 82066d8c9d2SKieran Bingham 82166d8c9d2SKieran Bingham ret = max9286_check_video_links(priv); 82266d8c9d2SKieran Bingham if (ret) 82366d8c9d2SKieran Bingham return ret; 82466d8c9d2SKieran Bingham 82566d8c9d2SKieran Bingham /* 82666d8c9d2SKieran Bingham * Wait until frame synchronization is locked. 82766d8c9d2SKieran Bingham * 82866d8c9d2SKieran Bingham * Manual says frame sync locking should take ~6 VTS. 82966d8c9d2SKieran Bingham * From practical experience at least 8 are required. Give 83066d8c9d2SKieran Bingham * 12 complete frames time (~400ms at 30 fps) to achieve frame 83166d8c9d2SKieran Bingham * locking before returning error. 83266d8c9d2SKieran Bingham */ 83366d8c9d2SKieran Bingham for (i = 0; i < 40; i++) { 83466d8c9d2SKieran Bingham if (max9286_read(priv, 0x31) & MAX9286_FSYNC_LOCKED) { 83566d8c9d2SKieran Bingham sync = true; 83666d8c9d2SKieran Bingham break; 83766d8c9d2SKieran Bingham } 83866d8c9d2SKieran Bingham usleep_range(9000, 11000); 83966d8c9d2SKieran Bingham } 84066d8c9d2SKieran Bingham 84166d8c9d2SKieran Bingham if (!sync) { 84266d8c9d2SKieran Bingham dev_err(&priv->client->dev, 84366d8c9d2SKieran Bingham "Failed to get frame synchronization\n"); 84466d8c9d2SKieran Bingham return -EXDEV; /* Invalid cross-device link */ 84566d8c9d2SKieran Bingham } 84666d8c9d2SKieran Bingham 84766d8c9d2SKieran Bingham /* 848cdcb186eSLaurent Pinchart * Configure the CSI-2 output to line interleaved mode (W x (N 849cdcb186eSLaurent Pinchart * x H), as opposed to the (N x W) x H mode that outputs the 850cdcb186eSLaurent Pinchart * images stitched side-by-side) and enable it. 85166d8c9d2SKieran Bingham */ 852cdcb186eSLaurent Pinchart max9286_write(priv, 0x15, MAX9286_CSI_IMAGE_TYP | MAX9286_VCTYPE | 853cdcb186eSLaurent Pinchart MAX9286_CSIOUTEN | MAX9286_EN_CCBSYB_CLK_STR | 854cdcb186eSLaurent Pinchart MAX9286_EN_GPI_CCBSYB); 85566d8c9d2SKieran Bingham } else { 856cdcb186eSLaurent Pinchart max9286_write(priv, 0x15, MAX9286_VCTYPE | 857cdcb186eSLaurent Pinchart MAX9286_EN_CCBSYB_CLK_STR | 858cdcb186eSLaurent Pinchart MAX9286_EN_GPI_CCBSYB); 85966d8c9d2SKieran Bingham 86066d8c9d2SKieran Bingham /* Stop all cameras. */ 86166d8c9d2SKieran Bingham for_each_source(priv, source) 86266d8c9d2SKieran Bingham v4l2_subdev_call(source->sd, video, s_stream, 0); 86366d8c9d2SKieran Bingham 86466d8c9d2SKieran Bingham max9286_i2c_mux_close(priv); 86566d8c9d2SKieran Bingham } 86666d8c9d2SKieran Bingham 86766d8c9d2SKieran Bingham return 0; 86866d8c9d2SKieran Bingham } 86966d8c9d2SKieran Bingham 870cffc9fb1SLaurent Pinchart static int max9286_g_frame_interval(struct v4l2_subdev *sd, 871cffc9fb1SLaurent Pinchart struct v4l2_subdev_frame_interval *interval) 872cffc9fb1SLaurent Pinchart { 873cffc9fb1SLaurent Pinchart struct max9286_priv *priv = sd_to_max9286(sd); 874cffc9fb1SLaurent Pinchart 875cffc9fb1SLaurent Pinchart if (interval->pad != MAX9286_SRC_PAD) 876cffc9fb1SLaurent Pinchart return -EINVAL; 877cffc9fb1SLaurent Pinchart 878cffc9fb1SLaurent Pinchart interval->interval = priv->interval; 879cffc9fb1SLaurent Pinchart 880cffc9fb1SLaurent Pinchart return 0; 881cffc9fb1SLaurent Pinchart } 882cffc9fb1SLaurent Pinchart 883cffc9fb1SLaurent Pinchart static int max9286_s_frame_interval(struct v4l2_subdev *sd, 884cffc9fb1SLaurent Pinchart struct v4l2_subdev_frame_interval *interval) 885cffc9fb1SLaurent Pinchart { 886cffc9fb1SLaurent Pinchart struct max9286_priv *priv = sd_to_max9286(sd); 887cffc9fb1SLaurent Pinchart 888cffc9fb1SLaurent Pinchart if (interval->pad != MAX9286_SRC_PAD) 889cffc9fb1SLaurent Pinchart return -EINVAL; 890cffc9fb1SLaurent Pinchart 891cffc9fb1SLaurent Pinchart priv->interval = interval->interval; 892cffc9fb1SLaurent Pinchart 893cffc9fb1SLaurent Pinchart return 0; 894cffc9fb1SLaurent Pinchart } 895cffc9fb1SLaurent Pinchart 89666d8c9d2SKieran Bingham static int max9286_enum_mbus_code(struct v4l2_subdev *sd, 8970d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 89866d8c9d2SKieran Bingham struct v4l2_subdev_mbus_code_enum *code) 89966d8c9d2SKieran Bingham { 90066d8c9d2SKieran Bingham if (code->pad || code->index > 0) 90166d8c9d2SKieran Bingham return -EINVAL; 90266d8c9d2SKieran Bingham 90366d8c9d2SKieran Bingham code->code = MEDIA_BUS_FMT_UYVY8_1X16; 90466d8c9d2SKieran Bingham 90566d8c9d2SKieran Bingham return 0; 90666d8c9d2SKieran Bingham } 90766d8c9d2SKieran Bingham 90866d8c9d2SKieran Bingham static struct v4l2_mbus_framefmt * 90966d8c9d2SKieran Bingham max9286_get_pad_format(struct max9286_priv *priv, 9100d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 91166d8c9d2SKieran Bingham unsigned int pad, u32 which) 91266d8c9d2SKieran Bingham { 91366d8c9d2SKieran Bingham switch (which) { 91466d8c9d2SKieran Bingham case V4L2_SUBDEV_FORMAT_TRY: 9150d346d2aSTomi Valkeinen return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); 91666d8c9d2SKieran Bingham case V4L2_SUBDEV_FORMAT_ACTIVE: 91766d8c9d2SKieran Bingham return &priv->fmt[pad]; 91866d8c9d2SKieran Bingham default: 91966d8c9d2SKieran Bingham return NULL; 92066d8c9d2SKieran Bingham } 92166d8c9d2SKieran Bingham } 92266d8c9d2SKieran Bingham 92366d8c9d2SKieran Bingham static int max9286_set_fmt(struct v4l2_subdev *sd, 9240d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 92566d8c9d2SKieran Bingham struct v4l2_subdev_format *format) 92666d8c9d2SKieran Bingham { 92766d8c9d2SKieran Bingham struct max9286_priv *priv = sd_to_max9286(sd); 92866d8c9d2SKieran Bingham struct v4l2_mbus_framefmt *cfg_fmt; 929f1403802SLaurent Pinchart unsigned int i; 93066d8c9d2SKieran Bingham 93166d8c9d2SKieran Bingham if (format->pad == MAX9286_SRC_PAD) 93266d8c9d2SKieran Bingham return -EINVAL; 93366d8c9d2SKieran Bingham 934f1403802SLaurent Pinchart /* Validate the format. */ 935f1403802SLaurent Pinchart for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { 936f1403802SLaurent Pinchart if (max9286_formats[i].code == format->format.code) 93766d8c9d2SKieran Bingham break; 93866d8c9d2SKieran Bingham } 93966d8c9d2SKieran Bingham 940f1403802SLaurent Pinchart if (i == ARRAY_SIZE(max9286_formats)) 941f1403802SLaurent Pinchart format->format.code = max9286_formats[0].code; 942f1403802SLaurent Pinchart 9430d346d2aSTomi Valkeinen cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad, 9440d346d2aSTomi Valkeinen format->which); 94566d8c9d2SKieran Bingham if (!cfg_fmt) 94666d8c9d2SKieran Bingham return -EINVAL; 94766d8c9d2SKieran Bingham 94866d8c9d2SKieran Bingham mutex_lock(&priv->mutex); 94966d8c9d2SKieran Bingham *cfg_fmt = format->format; 95066d8c9d2SKieran Bingham mutex_unlock(&priv->mutex); 95166d8c9d2SKieran Bingham 95266d8c9d2SKieran Bingham return 0; 95366d8c9d2SKieran Bingham } 95466d8c9d2SKieran Bingham 95566d8c9d2SKieran Bingham static int max9286_get_fmt(struct v4l2_subdev *sd, 9560d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state, 95766d8c9d2SKieran Bingham struct v4l2_subdev_format *format) 95866d8c9d2SKieran Bingham { 95966d8c9d2SKieran Bingham struct max9286_priv *priv = sd_to_max9286(sd); 96066d8c9d2SKieran Bingham struct v4l2_mbus_framefmt *cfg_fmt; 96166d8c9d2SKieran Bingham unsigned int pad = format->pad; 96266d8c9d2SKieran Bingham 96366d8c9d2SKieran Bingham /* 96466d8c9d2SKieran Bingham * Multiplexed Stream Support: Support link validation by returning the 96566d8c9d2SKieran Bingham * format of the first bound link. All links must have the same format, 96666d8c9d2SKieran Bingham * as we do not support mixing and matching of cameras connected to the 96766d8c9d2SKieran Bingham * max9286. 96866d8c9d2SKieran Bingham */ 96966d8c9d2SKieran Bingham if (pad == MAX9286_SRC_PAD) 97066d8c9d2SKieran Bingham pad = __ffs(priv->bound_sources); 97166d8c9d2SKieran Bingham 9720d346d2aSTomi Valkeinen cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which); 97366d8c9d2SKieran Bingham if (!cfg_fmt) 97466d8c9d2SKieran Bingham return -EINVAL; 97566d8c9d2SKieran Bingham 97666d8c9d2SKieran Bingham mutex_lock(&priv->mutex); 97766d8c9d2SKieran Bingham format->format = *cfg_fmt; 97866d8c9d2SKieran Bingham mutex_unlock(&priv->mutex); 97966d8c9d2SKieran Bingham 98066d8c9d2SKieran Bingham return 0; 98166d8c9d2SKieran Bingham } 98266d8c9d2SKieran Bingham 98366d8c9d2SKieran Bingham static const struct v4l2_subdev_video_ops max9286_video_ops = { 98466d8c9d2SKieran Bingham .s_stream = max9286_s_stream, 985cffc9fb1SLaurent Pinchart .g_frame_interval = max9286_g_frame_interval, 986cffc9fb1SLaurent Pinchart .s_frame_interval = max9286_s_frame_interval, 98766d8c9d2SKieran Bingham }; 98866d8c9d2SKieran Bingham 98966d8c9d2SKieran Bingham static const struct v4l2_subdev_pad_ops max9286_pad_ops = { 99066d8c9d2SKieran Bingham .enum_mbus_code = max9286_enum_mbus_code, 99166d8c9d2SKieran Bingham .get_fmt = max9286_get_fmt, 99266d8c9d2SKieran Bingham .set_fmt = max9286_set_fmt, 99366d8c9d2SKieran Bingham }; 99466d8c9d2SKieran Bingham 99566d8c9d2SKieran Bingham static const struct v4l2_subdev_ops max9286_subdev_ops = { 99666d8c9d2SKieran Bingham .video = &max9286_video_ops, 99766d8c9d2SKieran Bingham .pad = &max9286_pad_ops, 99866d8c9d2SKieran Bingham }; 99966d8c9d2SKieran Bingham 1000f1403802SLaurent Pinchart static const struct v4l2_mbus_framefmt max9286_default_format = { 1001f1403802SLaurent Pinchart .width = 1280, 1002f1403802SLaurent Pinchart .height = 800, 1003f1403802SLaurent Pinchart .code = MEDIA_BUS_FMT_UYVY8_1X16, 1004f1403802SLaurent Pinchart .colorspace = V4L2_COLORSPACE_SRGB, 1005f1403802SLaurent Pinchart .field = V4L2_FIELD_NONE, 1006f1403802SLaurent Pinchart .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, 1007f1403802SLaurent Pinchart .quantization = V4L2_QUANTIZATION_DEFAULT, 1008f1403802SLaurent Pinchart .xfer_func = V4L2_XFER_FUNC_DEFAULT, 1009f1403802SLaurent Pinchart }; 1010f1403802SLaurent Pinchart 101166d8c9d2SKieran Bingham static void max9286_init_format(struct v4l2_mbus_framefmt *fmt) 101266d8c9d2SKieran Bingham { 1013f1403802SLaurent Pinchart *fmt = max9286_default_format; 101466d8c9d2SKieran Bingham } 101566d8c9d2SKieran Bingham 101666d8c9d2SKieran Bingham static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) 101766d8c9d2SKieran Bingham { 101866d8c9d2SKieran Bingham struct v4l2_mbus_framefmt *format; 101966d8c9d2SKieran Bingham unsigned int i; 102066d8c9d2SKieran Bingham 102166d8c9d2SKieran Bingham for (i = 0; i < MAX9286_N_SINKS; i++) { 10220d346d2aSTomi Valkeinen format = v4l2_subdev_get_try_format(subdev, fh->state, i); 102366d8c9d2SKieran Bingham max9286_init_format(format); 102466d8c9d2SKieran Bingham } 102566d8c9d2SKieran Bingham 102666d8c9d2SKieran Bingham return 0; 102766d8c9d2SKieran Bingham } 102866d8c9d2SKieran Bingham 102966d8c9d2SKieran Bingham static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = { 103066d8c9d2SKieran Bingham .open = max9286_open, 103166d8c9d2SKieran Bingham }; 103266d8c9d2SKieran Bingham 10331fe6ae4eSLaurent Pinchart static const struct media_entity_operations max9286_media_ops = { 10341fe6ae4eSLaurent Pinchart .link_validate = v4l2_subdev_link_validate 10351fe6ae4eSLaurent Pinchart }; 10361fe6ae4eSLaurent Pinchart 103766d8c9d2SKieran Bingham static int max9286_s_ctrl(struct v4l2_ctrl *ctrl) 103866d8c9d2SKieran Bingham { 103966d8c9d2SKieran Bingham switch (ctrl->id) { 104066d8c9d2SKieran Bingham case V4L2_CID_PIXEL_RATE: 104166d8c9d2SKieran Bingham return 0; 104266d8c9d2SKieran Bingham default: 104366d8c9d2SKieran Bingham return -EINVAL; 104466d8c9d2SKieran Bingham } 104566d8c9d2SKieran Bingham } 104666d8c9d2SKieran Bingham 104766d8c9d2SKieran Bingham static const struct v4l2_ctrl_ops max9286_ctrl_ops = { 104866d8c9d2SKieran Bingham .s_ctrl = max9286_s_ctrl, 104966d8c9d2SKieran Bingham }; 105066d8c9d2SKieran Bingham 105166d8c9d2SKieran Bingham static int max9286_v4l2_register(struct max9286_priv *priv) 105266d8c9d2SKieran Bingham { 105366d8c9d2SKieran Bingham struct device *dev = &priv->client->dev; 105466d8c9d2SKieran Bingham struct fwnode_handle *ep; 105566d8c9d2SKieran Bingham int ret; 105666d8c9d2SKieran Bingham int i; 105766d8c9d2SKieran Bingham 105866d8c9d2SKieran Bingham /* Register v4l2 async notifiers for connected Camera subdevices */ 105966d8c9d2SKieran Bingham ret = max9286_v4l2_notifier_register(priv); 106066d8c9d2SKieran Bingham if (ret) { 106166d8c9d2SKieran Bingham dev_err(dev, "Unable to register V4L2 async notifiers\n"); 106266d8c9d2SKieran Bingham return ret; 106366d8c9d2SKieran Bingham } 106466d8c9d2SKieran Bingham 106566d8c9d2SKieran Bingham /* Configure V4L2 for the MAX9286 itself */ 106666d8c9d2SKieran Bingham 106766d8c9d2SKieran Bingham for (i = 0; i < MAX9286_N_SINKS; i++) 106866d8c9d2SKieran Bingham max9286_init_format(&priv->fmt[i]); 106966d8c9d2SKieran Bingham 107066d8c9d2SKieran Bingham v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); 107166d8c9d2SKieran Bingham priv->sd.internal_ops = &max9286_subdev_internal_ops; 107266d8c9d2SKieran Bingham priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 107366d8c9d2SKieran Bingham 107466d8c9d2SKieran Bingham v4l2_ctrl_handler_init(&priv->ctrls, 1); 1075cffc9fb1SLaurent Pinchart priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls, 107666d8c9d2SKieran Bingham &max9286_ctrl_ops, 107766d8c9d2SKieran Bingham V4L2_CID_PIXEL_RATE, 107866d8c9d2SKieran Bingham 1, INT_MAX, 1, 50000000); 107966d8c9d2SKieran Bingham 108066d8c9d2SKieran Bingham priv->sd.ctrl_handler = &priv->ctrls; 108166d8c9d2SKieran Bingham ret = priv->ctrls.error; 108266d8c9d2SKieran Bingham if (ret) 108366d8c9d2SKieran Bingham goto err_async; 108466d8c9d2SKieran Bingham 108566d8c9d2SKieran Bingham priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 10861fe6ae4eSLaurent Pinchart priv->sd.entity.ops = &max9286_media_ops; 108766d8c9d2SKieran Bingham 108866d8c9d2SKieran Bingham priv->pads[MAX9286_SRC_PAD].flags = MEDIA_PAD_FL_SOURCE; 108966d8c9d2SKieran Bingham for (i = 0; i < MAX9286_SRC_PAD; i++) 109066d8c9d2SKieran Bingham priv->pads[i].flags = MEDIA_PAD_FL_SINK; 109166d8c9d2SKieran Bingham ret = media_entity_pads_init(&priv->sd.entity, MAX9286_N_PADS, 109266d8c9d2SKieran Bingham priv->pads); 109366d8c9d2SKieran Bingham if (ret) 109466d8c9d2SKieran Bingham goto err_async; 109566d8c9d2SKieran Bingham 109666d8c9d2SKieran Bingham ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), MAX9286_SRC_PAD, 109766d8c9d2SKieran Bingham 0, 0); 109866d8c9d2SKieran Bingham if (!ep) { 109966d8c9d2SKieran Bingham dev_err(dev, "Unable to retrieve endpoint on \"port@4\"\n"); 110066d8c9d2SKieran Bingham ret = -ENOENT; 110166d8c9d2SKieran Bingham goto err_async; 110266d8c9d2SKieran Bingham } 110366d8c9d2SKieran Bingham priv->sd.fwnode = ep; 110466d8c9d2SKieran Bingham 110566d8c9d2SKieran Bingham ret = v4l2_async_register_subdev(&priv->sd); 110666d8c9d2SKieran Bingham if (ret < 0) { 110766d8c9d2SKieran Bingham dev_err(dev, "Unable to register subdevice\n"); 110866d8c9d2SKieran Bingham goto err_put_node; 110966d8c9d2SKieran Bingham } 111066d8c9d2SKieran Bingham 111166d8c9d2SKieran Bingham return 0; 111266d8c9d2SKieran Bingham 111366d8c9d2SKieran Bingham err_put_node: 111466d8c9d2SKieran Bingham fwnode_handle_put(ep); 111566d8c9d2SKieran Bingham err_async: 111666d8c9d2SKieran Bingham max9286_v4l2_notifier_unregister(priv); 111766d8c9d2SKieran Bingham 111866d8c9d2SKieran Bingham return ret; 111966d8c9d2SKieran Bingham } 112066d8c9d2SKieran Bingham 112166d8c9d2SKieran Bingham static void max9286_v4l2_unregister(struct max9286_priv *priv) 112266d8c9d2SKieran Bingham { 112366d8c9d2SKieran Bingham fwnode_handle_put(priv->sd.fwnode); 112466d8c9d2SKieran Bingham v4l2_async_unregister_subdev(&priv->sd); 112566d8c9d2SKieran Bingham max9286_v4l2_notifier_unregister(priv); 112666d8c9d2SKieran Bingham } 112766d8c9d2SKieran Bingham 112866d8c9d2SKieran Bingham /* ----------------------------------------------------------------------------- 112966d8c9d2SKieran Bingham * Probe/Remove 113066d8c9d2SKieran Bingham */ 113166d8c9d2SKieran Bingham 113266d8c9d2SKieran Bingham static int max9286_setup(struct max9286_priv *priv) 113366d8c9d2SKieran Bingham { 113466d8c9d2SKieran Bingham /* 113566d8c9d2SKieran Bingham * Link ordering values for all enabled links combinations. Orders must 113666d8c9d2SKieran Bingham * be assigned sequentially from 0 to the number of enabled links 113766d8c9d2SKieran Bingham * without leaving any hole for disabled links. We thus assign orders to 113866d8c9d2SKieran Bingham * enabled links first, and use the remaining order values for disabled 113966d8c9d2SKieran Bingham * links are all links must have a different order value; 114066d8c9d2SKieran Bingham */ 114166d8c9d2SKieran Bingham static const u8 link_order[] = { 114266d8c9d2SKieran Bingham (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxxx */ 114366d8c9d2SKieran Bingham (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxx0 */ 114466d8c9d2SKieran Bingham (3 << 6) | (2 << 4) | (0 << 2) | (1 << 0), /* xx0x */ 114566d8c9d2SKieran Bingham (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xx10 */ 114666d8c9d2SKieran Bingham (3 << 6) | (0 << 4) | (2 << 2) | (1 << 0), /* x0xx */ 114766d8c9d2SKieran Bingham (3 << 6) | (1 << 4) | (2 << 2) | (0 << 0), /* x1x0 */ 114866d8c9d2SKieran Bingham (3 << 6) | (1 << 4) | (0 << 2) | (2 << 0), /* x10x */ 114966d8c9d2SKieran Bingham (3 << 6) | (1 << 4) | (1 << 2) | (0 << 0), /* x210 */ 115066d8c9d2SKieran Bingham (0 << 6) | (3 << 4) | (2 << 2) | (1 << 0), /* 0xxx */ 115166d8c9d2SKieran Bingham (1 << 6) | (3 << 4) | (2 << 2) | (0 << 0), /* 1xx0 */ 115266d8c9d2SKieran Bingham (1 << 6) | (3 << 4) | (0 << 2) | (2 << 0), /* 1x0x */ 115366d8c9d2SKieran Bingham (2 << 6) | (3 << 4) | (1 << 2) | (0 << 0), /* 2x10 */ 115466d8c9d2SKieran Bingham (1 << 6) | (0 << 4) | (3 << 2) | (2 << 0), /* 10xx */ 115566d8c9d2SKieran Bingham (2 << 6) | (1 << 4) | (3 << 2) | (0 << 0), /* 21x0 */ 115666d8c9d2SKieran Bingham (2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */ 115766d8c9d2SKieran Bingham (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */ 115866d8c9d2SKieran Bingham }; 1159*defcedfbSLaurent Pinchart int cfg; 116066d8c9d2SKieran Bingham 116166d8c9d2SKieran Bingham /* 116266d8c9d2SKieran Bingham * Set the I2C bus speed. 116366d8c9d2SKieran Bingham * 116466d8c9d2SKieran Bingham * Enable I2C Local Acknowledge during the probe sequences of the camera 116566d8c9d2SKieran Bingham * only. This should be disabled after the mux is initialised. 116666d8c9d2SKieran Bingham */ 116766d8c9d2SKieran Bingham max9286_configure_i2c(priv, true); 1168f78723ebSJacopo Mondi max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv); 116966d8c9d2SKieran Bingham 117066d8c9d2SKieran Bingham /* 117166d8c9d2SKieran Bingham * Enable GMSL links, mask unused ones and autodetect link 117266d8c9d2SKieran Bingham * used as CSI clock source. 117366d8c9d2SKieran Bingham */ 117466d8c9d2SKieran Bingham max9286_write(priv, 0x00, MAX9286_MSTLINKSEL_AUTO | priv->route_mask); 117566d8c9d2SKieran Bingham max9286_write(priv, 0x0b, link_order[priv->route_mask]); 117666d8c9d2SKieran Bingham max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); 117766d8c9d2SKieran Bingham 1178f1403802SLaurent Pinchart max9286_set_video_format(priv, &max9286_default_format); 1179cffc9fb1SLaurent Pinchart max9286_set_fsync_period(priv); 118066d8c9d2SKieran Bingham 1181*defcedfbSLaurent Pinchart cfg = max9286_read(priv, 0x1c); 1182*defcedfbSLaurent Pinchart if (cfg < 0) 1183*defcedfbSLaurent Pinchart return cfg; 1184*defcedfbSLaurent Pinchart 1185*defcedfbSLaurent Pinchart dev_dbg(&priv->client->dev, "power-up config: %s immunity, %u-bit bus\n", 1186*defcedfbSLaurent Pinchart cfg & MAX9286_HIGHIMM(0) ? "high" : "legacy", 1187*defcedfbSLaurent Pinchart cfg & MAX9286_BWS ? 32 : cfg & MAX9286_HIBW ? 27 : 24); 1188*defcedfbSLaurent Pinchart 11893697f108SLaurent Pinchart if (priv->bus_width) { 1190*defcedfbSLaurent Pinchart cfg &= ~(MAX9286_HIBW | MAX9286_BWS); 11913697f108SLaurent Pinchart 11923697f108SLaurent Pinchart if (priv->bus_width == 27) 1193*defcedfbSLaurent Pinchart cfg |= MAX9286_HIBW; 11943697f108SLaurent Pinchart else if (priv->bus_width == 32) 1195*defcedfbSLaurent Pinchart cfg |= MAX9286_BWS; 11963697f108SLaurent Pinchart 1197*defcedfbSLaurent Pinchart max9286_write(priv, 0x1c, cfg); 11983697f108SLaurent Pinchart } 11993697f108SLaurent Pinchart 120066d8c9d2SKieran Bingham /* 120166d8c9d2SKieran Bingham * The overlap window seems to provide additional validation by tracking 120266d8c9d2SKieran Bingham * the delay between vsync and frame sync, generating an error if the 120366d8c9d2SKieran Bingham * delay is bigger than the programmed window, though it's not yet clear 120466d8c9d2SKieran Bingham * what value should be set. 120566d8c9d2SKieran Bingham * 120666d8c9d2SKieran Bingham * As it's an optional value and can be disabled, we do so by setting 120766d8c9d2SKieran Bingham * a 0 overlap value. 120866d8c9d2SKieran Bingham */ 120966d8c9d2SKieran Bingham max9286_write(priv, 0x63, 0); 121066d8c9d2SKieran Bingham max9286_write(priv, 0x64, 0); 121166d8c9d2SKieran Bingham 121266d8c9d2SKieran Bingham /* 121366d8c9d2SKieran Bingham * Wait for 2ms to allow the link to resynchronize after the 121466d8c9d2SKieran Bingham * configuration change. 121566d8c9d2SKieran Bingham */ 121666d8c9d2SKieran Bingham usleep_range(2000, 5000); 121766d8c9d2SKieran Bingham 121866d8c9d2SKieran Bingham return 0; 121966d8c9d2SKieran Bingham } 122066d8c9d2SKieran Bingham 1221c9352df7SJacopo Mondi static int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset, 1222c9352df7SJacopo Mondi int value) 122366d8c9d2SKieran Bingham { 122466d8c9d2SKieran Bingham if (value) 122566d8c9d2SKieran Bingham priv->gpio_state |= BIT(offset); 122666d8c9d2SKieran Bingham else 122766d8c9d2SKieran Bingham priv->gpio_state &= ~BIT(offset); 122866d8c9d2SKieran Bingham 1229c9352df7SJacopo Mondi return max9286_write(priv, 0x0f, 1230c9352df7SJacopo Mondi MAX9286_0X0F_RESERVED | priv->gpio_state); 123166d8c9d2SKieran Bingham } 123266d8c9d2SKieran Bingham 1233c9352df7SJacopo Mondi static void max9286_gpiochip_set(struct gpio_chip *chip, 1234c9352df7SJacopo Mondi unsigned int offset, int value) 1235c9352df7SJacopo Mondi { 1236c9352df7SJacopo Mondi struct max9286_priv *priv = gpiochip_get_data(chip); 1237c9352df7SJacopo Mondi 1238c9352df7SJacopo Mondi max9286_gpio_set(priv, offset, value); 1239c9352df7SJacopo Mondi } 1240c9352df7SJacopo Mondi 1241c9352df7SJacopo Mondi static int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset) 124266d8c9d2SKieran Bingham { 124366d8c9d2SKieran Bingham struct max9286_priv *priv = gpiochip_get_data(chip); 124466d8c9d2SKieran Bingham 124566d8c9d2SKieran Bingham return priv->gpio_state & BIT(offset); 124666d8c9d2SKieran Bingham } 124766d8c9d2SKieran Bingham 124866d8c9d2SKieran Bingham static int max9286_register_gpio(struct max9286_priv *priv) 124966d8c9d2SKieran Bingham { 125066d8c9d2SKieran Bingham struct device *dev = &priv->client->dev; 125166d8c9d2SKieran Bingham struct gpio_chip *gpio = &priv->gpio; 125266d8c9d2SKieran Bingham int ret; 125366d8c9d2SKieran Bingham 125466d8c9d2SKieran Bingham /* Configure the GPIO */ 125566d8c9d2SKieran Bingham gpio->label = dev_name(dev); 125666d8c9d2SKieran Bingham gpio->parent = dev; 125766d8c9d2SKieran Bingham gpio->owner = THIS_MODULE; 125866d8c9d2SKieran Bingham gpio->ngpio = 2; 125966d8c9d2SKieran Bingham gpio->base = -1; 1260c9352df7SJacopo Mondi gpio->set = max9286_gpiochip_set; 1261c9352df7SJacopo Mondi gpio->get = max9286_gpiochip_get; 126266d8c9d2SKieran Bingham gpio->can_sleep = true; 126366d8c9d2SKieran Bingham 126466d8c9d2SKieran Bingham ret = devm_gpiochip_add_data(dev, gpio, priv); 126566d8c9d2SKieran Bingham if (ret) 126666d8c9d2SKieran Bingham dev_err(dev, "Unable to create gpio_chip\n"); 126766d8c9d2SKieran Bingham 126866d8c9d2SKieran Bingham return ret; 126966d8c9d2SKieran Bingham } 127066d8c9d2SKieran Bingham 1271c9352df7SJacopo Mondi static int max9286_parse_gpios(struct max9286_priv *priv) 1272c9352df7SJacopo Mondi { 1273c9352df7SJacopo Mondi struct device *dev = &priv->client->dev; 1274c9352df7SJacopo Mondi int ret; 1275c9352df7SJacopo Mondi 1276c9352df7SJacopo Mondi /* 1277c9352df7SJacopo Mondi * Parse the "gpio-poc" vendor property. If the property is not 1278c9352df7SJacopo Mondi * specified the camera power is controlled by a regulator. 1279c9352df7SJacopo Mondi */ 1280c9352df7SJacopo Mondi ret = of_property_read_u32_array(dev->of_node, "maxim,gpio-poc", 1281c9352df7SJacopo Mondi priv->gpio_poc, 2); 1282c9352df7SJacopo Mondi if (ret == -EINVAL) { 1283c9352df7SJacopo Mondi /* 1284c9352df7SJacopo Mondi * If gpio lines are not used for the camera power, register 1285c9352df7SJacopo Mondi * a gpio controller for consumers. 1286c9352df7SJacopo Mondi */ 1287817660f4SThomas Nizan return max9286_register_gpio(priv); 1288c9352df7SJacopo Mondi } 1289c9352df7SJacopo Mondi 1290c9352df7SJacopo Mondi /* If the property is specified make sure it is well formed. */ 1291c9352df7SJacopo Mondi if (ret || priv->gpio_poc[0] > 1 || 1292c9352df7SJacopo Mondi (priv->gpio_poc[1] != GPIO_ACTIVE_HIGH && 1293c9352df7SJacopo Mondi priv->gpio_poc[1] != GPIO_ACTIVE_LOW)) { 1294c9352df7SJacopo Mondi dev_err(dev, "Invalid 'gpio-poc' property\n"); 1295c9352df7SJacopo Mondi return -EINVAL; 1296c9352df7SJacopo Mondi } 1297c9352df7SJacopo Mondi 1298817660f4SThomas Nizan priv->use_gpio_poc = true; 1299c9352df7SJacopo Mondi return 0; 1300c9352df7SJacopo Mondi } 1301c9352df7SJacopo Mondi 1302817660f4SThomas Nizan static int max9286_poc_power_on(struct max9286_priv *priv) 1303817660f4SThomas Nizan { 1304817660f4SThomas Nizan struct max9286_source *source; 1305817660f4SThomas Nizan unsigned int enabled = 0; 1306817660f4SThomas Nizan int ret; 1307817660f4SThomas Nizan 1308817660f4SThomas Nizan /* Enable the global regulator if available. */ 1309817660f4SThomas Nizan if (priv->regulator) 1310817660f4SThomas Nizan return regulator_enable(priv->regulator); 1311817660f4SThomas Nizan 1312817660f4SThomas Nizan if (priv->use_gpio_poc) 1313817660f4SThomas Nizan return max9286_gpio_set(priv, priv->gpio_poc[0], 1314817660f4SThomas Nizan !priv->gpio_poc[1]); 1315817660f4SThomas Nizan 1316817660f4SThomas Nizan /* Otherwise use the per-port regulators. */ 1317817660f4SThomas Nizan for_each_source(priv, source) { 1318817660f4SThomas Nizan ret = regulator_enable(source->regulator); 1319817660f4SThomas Nizan if (ret < 0) 1320817660f4SThomas Nizan goto error; 1321817660f4SThomas Nizan 1322817660f4SThomas Nizan enabled |= BIT(to_index(priv, source)); 1323817660f4SThomas Nizan } 1324817660f4SThomas Nizan 1325817660f4SThomas Nizan return 0; 1326817660f4SThomas Nizan 1327817660f4SThomas Nizan error: 1328817660f4SThomas Nizan for_each_source(priv, source) { 1329817660f4SThomas Nizan if (enabled & BIT(to_index(priv, source))) 1330817660f4SThomas Nizan regulator_disable(source->regulator); 1331817660f4SThomas Nizan } 1332817660f4SThomas Nizan 1333817660f4SThomas Nizan return ret; 1334817660f4SThomas Nizan } 1335817660f4SThomas Nizan 1336817660f4SThomas Nizan static int max9286_poc_power_off(struct max9286_priv *priv) 1337817660f4SThomas Nizan { 1338817660f4SThomas Nizan struct max9286_source *source; 1339817660f4SThomas Nizan int ret = 0; 1340817660f4SThomas Nizan 1341817660f4SThomas Nizan if (priv->regulator) 1342817660f4SThomas Nizan return regulator_disable(priv->regulator); 1343817660f4SThomas Nizan 1344817660f4SThomas Nizan if (priv->use_gpio_poc) 1345817660f4SThomas Nizan return max9286_gpio_set(priv, priv->gpio_poc[0], 1346817660f4SThomas Nizan priv->gpio_poc[1]); 1347817660f4SThomas Nizan 1348817660f4SThomas Nizan for_each_source(priv, source) { 1349817660f4SThomas Nizan int err; 1350817660f4SThomas Nizan 1351817660f4SThomas Nizan err = regulator_disable(source->regulator); 1352817660f4SThomas Nizan if (!ret) 1353817660f4SThomas Nizan ret = err; 1354817660f4SThomas Nizan } 1355817660f4SThomas Nizan 1356817660f4SThomas Nizan return ret; 1357817660f4SThomas Nizan } 1358817660f4SThomas Nizan 1359c9352df7SJacopo Mondi static int max9286_poc_enable(struct max9286_priv *priv, bool enable) 1360c9352df7SJacopo Mondi { 1361c9352df7SJacopo Mondi int ret; 1362c9352df7SJacopo Mondi 1363817660f4SThomas Nizan if (enable) 1364817660f4SThomas Nizan ret = max9286_poc_power_on(priv); 1365c9352df7SJacopo Mondi else 1366817660f4SThomas Nizan ret = max9286_poc_power_off(priv); 1367c9352df7SJacopo Mondi 1368c9352df7SJacopo Mondi if (ret < 0) 1369c9352df7SJacopo Mondi dev_err(&priv->client->dev, "Unable to turn power %s\n", 1370c9352df7SJacopo Mondi enable ? "on" : "off"); 1371c9352df7SJacopo Mondi 1372c9352df7SJacopo Mondi return ret; 1373c9352df7SJacopo Mondi } 1374c9352df7SJacopo Mondi 1375365ab7ebSLaurentiu Palcu static int max9286_init(struct max9286_priv *priv) 137666d8c9d2SKieran Bingham { 1377365ab7ebSLaurentiu Palcu struct i2c_client *client = priv->client; 137866d8c9d2SKieran Bingham int ret; 137966d8c9d2SKieran Bingham 1380c9352df7SJacopo Mondi ret = max9286_poc_enable(priv, true); 1381c9352df7SJacopo Mondi if (ret) 138266d8c9d2SKieran Bingham return ret; 138366d8c9d2SKieran Bingham 138466d8c9d2SKieran Bingham ret = max9286_setup(priv); 138566d8c9d2SKieran Bingham if (ret) { 1386365ab7ebSLaurentiu Palcu dev_err(&client->dev, "Unable to setup max9286\n"); 1387c9352df7SJacopo Mondi goto err_poc_disable; 138866d8c9d2SKieran Bingham } 138966d8c9d2SKieran Bingham 139066d8c9d2SKieran Bingham /* 139166d8c9d2SKieran Bingham * Register all V4L2 interactions for the MAX9286 and notifiers for 139266d8c9d2SKieran Bingham * any subdevices connected. 139366d8c9d2SKieran Bingham */ 139466d8c9d2SKieran Bingham ret = max9286_v4l2_register(priv); 139566d8c9d2SKieran Bingham if (ret) { 1396365ab7ebSLaurentiu Palcu dev_err(&client->dev, "Failed to register with V4L2\n"); 1397c9352df7SJacopo Mondi goto err_poc_disable; 139866d8c9d2SKieran Bingham } 139966d8c9d2SKieran Bingham 140066d8c9d2SKieran Bingham ret = max9286_i2c_mux_init(priv); 140166d8c9d2SKieran Bingham if (ret) { 1402365ab7ebSLaurentiu Palcu dev_err(&client->dev, "Unable to initialize I2C multiplexer\n"); 140366d8c9d2SKieran Bingham goto err_v4l2_register; 140466d8c9d2SKieran Bingham } 140566d8c9d2SKieran Bingham 140666d8c9d2SKieran Bingham /* Leave the mux channels disabled until they are selected. */ 140766d8c9d2SKieran Bingham max9286_i2c_mux_close(priv); 140866d8c9d2SKieran Bingham 140966d8c9d2SKieran Bingham return 0; 141066d8c9d2SKieran Bingham 141166d8c9d2SKieran Bingham err_v4l2_register: 141266d8c9d2SKieran Bingham max9286_v4l2_unregister(priv); 1413c9352df7SJacopo Mondi err_poc_disable: 1414c9352df7SJacopo Mondi max9286_poc_enable(priv, false); 141566d8c9d2SKieran Bingham 141666d8c9d2SKieran Bingham return ret; 141766d8c9d2SKieran Bingham } 141866d8c9d2SKieran Bingham 141966d8c9d2SKieran Bingham static void max9286_cleanup_dt(struct max9286_priv *priv) 142066d8c9d2SKieran Bingham { 142166d8c9d2SKieran Bingham struct max9286_source *source; 142266d8c9d2SKieran Bingham 142366d8c9d2SKieran Bingham for_each_source(priv, source) { 142466d8c9d2SKieran Bingham fwnode_handle_put(source->fwnode); 142566d8c9d2SKieran Bingham source->fwnode = NULL; 142666d8c9d2SKieran Bingham } 142766d8c9d2SKieran Bingham } 142866d8c9d2SKieran Bingham 142966d8c9d2SKieran Bingham static int max9286_parse_dt(struct max9286_priv *priv) 143066d8c9d2SKieran Bingham { 143166d8c9d2SKieran Bingham struct device *dev = &priv->client->dev; 143266d8c9d2SKieran Bingham struct device_node *i2c_mux; 143366d8c9d2SKieran Bingham struct device_node *node = NULL; 143466d8c9d2SKieran Bingham unsigned int i2c_mux_mask = 0; 143585cb767cSJacopo Mondi u32 reverse_channel_microvolt; 1436e332061bSLaurent Pinchart u32 i2c_clk_freq = 105000; 1437e332061bSLaurent Pinchart unsigned int i; 143866d8c9d2SKieran Bingham 143966d8c9d2SKieran Bingham /* Balance the of_node_put() performed by of_find_node_by_name(). */ 144066d8c9d2SKieran Bingham of_node_get(dev->of_node); 144166d8c9d2SKieran Bingham i2c_mux = of_find_node_by_name(dev->of_node, "i2c-mux"); 144266d8c9d2SKieran Bingham if (!i2c_mux) { 144366d8c9d2SKieran Bingham dev_err(dev, "Failed to find i2c-mux node\n"); 144466d8c9d2SKieran Bingham return -EINVAL; 144566d8c9d2SKieran Bingham } 144666d8c9d2SKieran Bingham 144766d8c9d2SKieran Bingham /* Identify which i2c-mux channels are enabled */ 144866d8c9d2SKieran Bingham for_each_child_of_node(i2c_mux, node) { 144966d8c9d2SKieran Bingham u32 id = 0; 145066d8c9d2SKieran Bingham 145166d8c9d2SKieran Bingham of_property_read_u32(node, "reg", &id); 145266d8c9d2SKieran Bingham if (id >= MAX9286_NUM_GMSL) 145366d8c9d2SKieran Bingham continue; 145466d8c9d2SKieran Bingham 145566d8c9d2SKieran Bingham if (!of_device_is_available(node)) { 145666d8c9d2SKieran Bingham dev_dbg(dev, "Skipping disabled I2C bus port %u\n", id); 145766d8c9d2SKieran Bingham continue; 145866d8c9d2SKieran Bingham } 145966d8c9d2SKieran Bingham 146066d8c9d2SKieran Bingham i2c_mux_mask |= BIT(id); 146166d8c9d2SKieran Bingham } 146266d8c9d2SKieran Bingham of_node_put(node); 146366d8c9d2SKieran Bingham of_node_put(i2c_mux); 146466d8c9d2SKieran Bingham 146566d8c9d2SKieran Bingham /* Parse the endpoints */ 146666d8c9d2SKieran Bingham for_each_endpoint_of_node(dev->of_node, node) { 146766d8c9d2SKieran Bingham struct max9286_source *source; 146866d8c9d2SKieran Bingham struct of_endpoint ep; 146966d8c9d2SKieran Bingham 147066d8c9d2SKieran Bingham of_graph_parse_endpoint(node, &ep); 147166d8c9d2SKieran Bingham dev_dbg(dev, "Endpoint %pOF on port %d", 147266d8c9d2SKieran Bingham ep.local_node, ep.port); 147366d8c9d2SKieran Bingham 147466d8c9d2SKieran Bingham if (ep.port > MAX9286_NUM_GMSL) { 147566d8c9d2SKieran Bingham dev_err(dev, "Invalid endpoint %s on port %d", 147666d8c9d2SKieran Bingham of_node_full_name(ep.local_node), ep.port); 147766d8c9d2SKieran Bingham continue; 147866d8c9d2SKieran Bingham } 147966d8c9d2SKieran Bingham 148066d8c9d2SKieran Bingham /* For the source endpoint just parse the bus configuration. */ 148166d8c9d2SKieran Bingham if (ep.port == MAX9286_SRC_PAD) { 148266d8c9d2SKieran Bingham struct v4l2_fwnode_endpoint vep = { 148366d8c9d2SKieran Bingham .bus_type = V4L2_MBUS_CSI2_DPHY 148466d8c9d2SKieran Bingham }; 148566d8c9d2SKieran Bingham int ret; 148666d8c9d2SKieran Bingham 148766d8c9d2SKieran Bingham ret = v4l2_fwnode_endpoint_parse( 148866d8c9d2SKieran Bingham of_fwnode_handle(node), &vep); 148966d8c9d2SKieran Bingham if (ret) { 149066d8c9d2SKieran Bingham of_node_put(node); 149166d8c9d2SKieran Bingham return ret; 149266d8c9d2SKieran Bingham } 149366d8c9d2SKieran Bingham 149466d8c9d2SKieran Bingham priv->csi2_data_lanes = 149566d8c9d2SKieran Bingham vep.bus.mipi_csi2.num_data_lanes; 149666d8c9d2SKieran Bingham 149766d8c9d2SKieran Bingham continue; 149866d8c9d2SKieran Bingham } 149966d8c9d2SKieran Bingham 150066d8c9d2SKieran Bingham /* Skip if the corresponding GMSL link is unavailable. */ 150166d8c9d2SKieran Bingham if (!(i2c_mux_mask & BIT(ep.port))) 150266d8c9d2SKieran Bingham continue; 150366d8c9d2SKieran Bingham 150466d8c9d2SKieran Bingham if (priv->sources[ep.port].fwnode) { 150566d8c9d2SKieran Bingham dev_err(dev, 150666d8c9d2SKieran Bingham "Multiple port endpoints are not supported: %d", 150766d8c9d2SKieran Bingham ep.port); 150866d8c9d2SKieran Bingham 150966d8c9d2SKieran Bingham continue; 151066d8c9d2SKieran Bingham } 151166d8c9d2SKieran Bingham 151266d8c9d2SKieran Bingham source = &priv->sources[ep.port]; 151366d8c9d2SKieran Bingham source->fwnode = fwnode_graph_get_remote_endpoint( 151466d8c9d2SKieran Bingham of_fwnode_handle(node)); 151566d8c9d2SKieran Bingham if (!source->fwnode) { 151666d8c9d2SKieran Bingham dev_err(dev, 151766d8c9d2SKieran Bingham "Endpoint %pOF has no remote endpoint connection\n", 151866d8c9d2SKieran Bingham ep.local_node); 151966d8c9d2SKieran Bingham 152066d8c9d2SKieran Bingham continue; 152166d8c9d2SKieran Bingham } 152266d8c9d2SKieran Bingham 152366d8c9d2SKieran Bingham priv->source_mask |= BIT(ep.port); 152466d8c9d2SKieran Bingham priv->nsources++; 152566d8c9d2SKieran Bingham } 152666d8c9d2SKieran Bingham of_node_put(node); 152766d8c9d2SKieran Bingham 15283697f108SLaurent Pinchart of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width); 15293697f108SLaurent Pinchart switch (priv->bus_width) { 15303697f108SLaurent Pinchart case 0: 15313697f108SLaurent Pinchart /* 15323697f108SLaurent Pinchart * The property isn't specified in the device tree, the driver 15333697f108SLaurent Pinchart * will keep the default value selected by the BWS pin. 15343697f108SLaurent Pinchart */ 15353697f108SLaurent Pinchart case 24: 15363697f108SLaurent Pinchart case 27: 15373697f108SLaurent Pinchart case 32: 15383697f108SLaurent Pinchart break; 15393697f108SLaurent Pinchart default: 15403697f108SLaurent Pinchart dev_err(dev, "Invalid %s value %u\n", "maxim,bus-width", 15413697f108SLaurent Pinchart priv->bus_width); 15423697f108SLaurent Pinchart return -EINVAL; 15433697f108SLaurent Pinchart } 15443697f108SLaurent Pinchart 1545e332061bSLaurent Pinchart of_property_read_u32(dev->of_node, "maxim,i2c-remote-bus-hz", 1546e332061bSLaurent Pinchart &i2c_clk_freq); 1547e332061bSLaurent Pinchart for (i = 0; i < ARRAY_SIZE(max9286_i2c_speeds); ++i) { 1548e332061bSLaurent Pinchart const struct max9286_i2c_speed *speed = &max9286_i2c_speeds[i]; 1549e332061bSLaurent Pinchart 1550e332061bSLaurent Pinchart if (speed->rate == i2c_clk_freq) { 1551e332061bSLaurent Pinchart priv->i2c_mstbt = speed->mstbt; 1552e332061bSLaurent Pinchart break; 1553e332061bSLaurent Pinchart } 1554e332061bSLaurent Pinchart } 1555e332061bSLaurent Pinchart 1556e332061bSLaurent Pinchart if (i == ARRAY_SIZE(max9286_i2c_speeds)) { 1557e332061bSLaurent Pinchart dev_err(dev, "Invalid %s value %u\n", "maxim,i2c-remote-bus-hz", 1558e332061bSLaurent Pinchart i2c_clk_freq); 1559e332061bSLaurent Pinchart return -EINVAL; 1560e332061bSLaurent Pinchart } 1561e332061bSLaurent Pinchart 156285cb767cSJacopo Mondi /* 156385cb767cSJacopo Mondi * Parse the initial value of the reverse channel amplitude from 156485cb767cSJacopo Mondi * the firmware interface and convert it to millivolts. 156585cb767cSJacopo Mondi * 156685cb767cSJacopo Mondi * Default it to 170mV for backward compatibility with DTBs that do not 156785cb767cSJacopo Mondi * provide the property. 156885cb767cSJacopo Mondi */ 156985cb767cSJacopo Mondi if (of_property_read_u32(dev->of_node, 157085cb767cSJacopo Mondi "maxim,reverse-channel-microvolt", 157185cb767cSJacopo Mondi &reverse_channel_microvolt)) 1572f78723ebSJacopo Mondi priv->init_rev_chan_mv = 170; 157385cb767cSJacopo Mondi else 1574f78723ebSJacopo Mondi priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U; 157585cb767cSJacopo Mondi 157666d8c9d2SKieran Bingham priv->route_mask = priv->source_mask; 157766d8c9d2SKieran Bingham 157866d8c9d2SKieran Bingham return 0; 157966d8c9d2SKieran Bingham } 158066d8c9d2SKieran Bingham 1581817660f4SThomas Nizan static int max9286_get_poc_supplies(struct max9286_priv *priv) 1582817660f4SThomas Nizan { 1583817660f4SThomas Nizan struct device *dev = &priv->client->dev; 1584817660f4SThomas Nizan struct max9286_source *source; 1585817660f4SThomas Nizan int ret; 1586817660f4SThomas Nizan 1587817660f4SThomas Nizan /* Start by getting the global regulator. */ 1588817660f4SThomas Nizan priv->regulator = devm_regulator_get_optional(dev, "poc"); 1589817660f4SThomas Nizan if (!IS_ERR(priv->regulator)) 1590817660f4SThomas Nizan return 0; 1591817660f4SThomas Nizan 1592817660f4SThomas Nizan if (PTR_ERR(priv->regulator) != -ENODEV) 1593817660f4SThomas Nizan return dev_err_probe(dev, PTR_ERR(priv->regulator), 1594817660f4SThomas Nizan "Unable to get PoC regulator\n"); 1595817660f4SThomas Nizan 1596817660f4SThomas Nizan /* If there's no global regulator, get per-port regulators. */ 1597817660f4SThomas Nizan dev_dbg(dev, 1598817660f4SThomas Nizan "No global PoC regulator, looking for per-port regulators\n"); 1599817660f4SThomas Nizan priv->regulator = NULL; 1600817660f4SThomas Nizan 1601817660f4SThomas Nizan for_each_source(priv, source) { 1602817660f4SThomas Nizan unsigned int index = to_index(priv, source); 1603817660f4SThomas Nizan char name[10]; 1604817660f4SThomas Nizan 1605817660f4SThomas Nizan snprintf(name, sizeof(name), "port%u-poc", index); 1606817660f4SThomas Nizan source->regulator = devm_regulator_get(dev, name); 1607817660f4SThomas Nizan if (IS_ERR(source->regulator)) { 1608817660f4SThomas Nizan ret = PTR_ERR(source->regulator); 1609817660f4SThomas Nizan dev_err_probe(dev, ret, 1610817660f4SThomas Nizan "Unable to get port %u PoC regulator\n", 1611817660f4SThomas Nizan index); 1612817660f4SThomas Nizan return ret; 1613817660f4SThomas Nizan } 1614817660f4SThomas Nizan } 1615817660f4SThomas Nizan 1616817660f4SThomas Nizan return 0; 1617817660f4SThomas Nizan } 1618817660f4SThomas Nizan 161966d8c9d2SKieran Bingham static int max9286_probe(struct i2c_client *client) 162066d8c9d2SKieran Bingham { 162166d8c9d2SKieran Bingham struct max9286_priv *priv; 162266d8c9d2SKieran Bingham int ret; 162366d8c9d2SKieran Bingham 162466d8c9d2SKieran Bingham priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 162566d8c9d2SKieran Bingham if (!priv) 162666d8c9d2SKieran Bingham return -ENOMEM; 162766d8c9d2SKieran Bingham 162866d8c9d2SKieran Bingham mutex_init(&priv->mutex); 162966d8c9d2SKieran Bingham 163066d8c9d2SKieran Bingham priv->client = client; 163166d8c9d2SKieran Bingham 1632817660f4SThomas Nizan /* GPIO values default to high */ 1633817660f4SThomas Nizan priv->gpio_state = BIT(0) | BIT(1); 1634817660f4SThomas Nizan 1635e332061bSLaurent Pinchart ret = max9286_parse_dt(priv); 1636e332061bSLaurent Pinchart if (ret) 1637e332061bSLaurent Pinchart goto err_cleanup_dt; 1638e332061bSLaurent Pinchart 163966d8c9d2SKieran Bingham priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", 164066d8c9d2SKieran Bingham GPIOD_OUT_HIGH); 1641e332061bSLaurent Pinchart if (IS_ERR(priv->gpiod_pwdn)) { 1642e332061bSLaurent Pinchart ret = PTR_ERR(priv->gpiod_pwdn); 1643e332061bSLaurent Pinchart goto err_cleanup_dt; 1644e332061bSLaurent Pinchart } 164566d8c9d2SKieran Bingham 164666d8c9d2SKieran Bingham gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn"); 164766d8c9d2SKieran Bingham gpiod_set_value_cansleep(priv->gpiod_pwdn, 1); 164866d8c9d2SKieran Bingham 164966d8c9d2SKieran Bingham /* Wait at least 4ms before the I2C lines latch to the address */ 165066d8c9d2SKieran Bingham if (priv->gpiod_pwdn) 165166d8c9d2SKieran Bingham usleep_range(4000, 5000); 165266d8c9d2SKieran Bingham 165366d8c9d2SKieran Bingham /* 165466d8c9d2SKieran Bingham * The MAX9286 starts by default with all ports enabled, we disable all 165566d8c9d2SKieran Bingham * ports early to ensure that all channels are disabled if we error out 165666d8c9d2SKieran Bingham * and keep the bus consistent. 165766d8c9d2SKieran Bingham */ 165866d8c9d2SKieran Bingham max9286_i2c_mux_close(priv); 165966d8c9d2SKieran Bingham 166066d8c9d2SKieran Bingham /* 166166d8c9d2SKieran Bingham * The MAX9286 initialises with auto-acknowledge enabled by default. 166266d8c9d2SKieran Bingham * This can be invasive to other transactions on the same bus, so 166366d8c9d2SKieran Bingham * disable it early. It will be enabled only as and when needed. 166466d8c9d2SKieran Bingham */ 166566d8c9d2SKieran Bingham max9286_configure_i2c(priv, false); 166666d8c9d2SKieran Bingham 1667c9352df7SJacopo Mondi ret = max9286_parse_gpios(priv); 166866d8c9d2SKieran Bingham if (ret) 166966d8c9d2SKieran Bingham goto err_powerdown; 167066d8c9d2SKieran Bingham 1671817660f4SThomas Nizan if (!priv->use_gpio_poc) { 1672817660f4SThomas Nizan ret = max9286_get_poc_supplies(priv); 1673817660f4SThomas Nizan if (ret) 1674817660f4SThomas Nizan goto err_cleanup_dt; 1675817660f4SThomas Nizan } 167666d8c9d2SKieran Bingham 1677365ab7ebSLaurentiu Palcu ret = max9286_init(priv); 167866d8c9d2SKieran Bingham if (ret < 0) 167966d8c9d2SKieran Bingham goto err_cleanup_dt; 168066d8c9d2SKieran Bingham 168166d8c9d2SKieran Bingham return 0; 168266d8c9d2SKieran Bingham 168366d8c9d2SKieran Bingham err_powerdown: 168466d8c9d2SKieran Bingham gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); 1685e332061bSLaurent Pinchart err_cleanup_dt: 1686e332061bSLaurent Pinchart max9286_cleanup_dt(priv); 168766d8c9d2SKieran Bingham 168866d8c9d2SKieran Bingham return ret; 168966d8c9d2SKieran Bingham } 169066d8c9d2SKieran Bingham 1691ed5c2f5fSUwe Kleine-König static void max9286_remove(struct i2c_client *client) 169266d8c9d2SKieran Bingham { 1693365ab7ebSLaurentiu Palcu struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client)); 169466d8c9d2SKieran Bingham 169566d8c9d2SKieran Bingham i2c_mux_del_adapters(priv->mux); 169666d8c9d2SKieran Bingham 169766d8c9d2SKieran Bingham max9286_v4l2_unregister(priv); 169866d8c9d2SKieran Bingham 1699c9352df7SJacopo Mondi max9286_poc_enable(priv, false); 170066d8c9d2SKieran Bingham 170166d8c9d2SKieran Bingham gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); 170266d8c9d2SKieran Bingham 170366d8c9d2SKieran Bingham max9286_cleanup_dt(priv); 170466d8c9d2SKieran Bingham } 170566d8c9d2SKieran Bingham 170666d8c9d2SKieran Bingham static const struct of_device_id max9286_dt_ids[] = { 170766d8c9d2SKieran Bingham { .compatible = "maxim,max9286" }, 170866d8c9d2SKieran Bingham {}, 170966d8c9d2SKieran Bingham }; 171066d8c9d2SKieran Bingham MODULE_DEVICE_TABLE(of, max9286_dt_ids); 171166d8c9d2SKieran Bingham 171266d8c9d2SKieran Bingham static struct i2c_driver max9286_i2c_driver = { 171366d8c9d2SKieran Bingham .driver = { 171466d8c9d2SKieran Bingham .name = "max9286", 171566d8c9d2SKieran Bingham .of_match_table = of_match_ptr(max9286_dt_ids), 171666d8c9d2SKieran Bingham }, 171766d8c9d2SKieran Bingham .probe_new = max9286_probe, 171866d8c9d2SKieran Bingham .remove = max9286_remove, 171966d8c9d2SKieran Bingham }; 172066d8c9d2SKieran Bingham 172166d8c9d2SKieran Bingham module_i2c_driver(max9286_i2c_driver); 172266d8c9d2SKieran Bingham 172366d8c9d2SKieran Bingham MODULE_DESCRIPTION("Maxim MAX9286 GMSL Deserializer Driver"); 172466d8c9d2SKieran Bingham MODULE_AUTHOR("Jacopo Mondi, Kieran Bingham, Laurent Pinchart, Niklas Söderlund, Vladimir Barinov"); 172566d8c9d2SKieran Bingham MODULE_LICENSE("GPL"); 1726