162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Maxim MAX9286 GMSL Deserializer Driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2017-2019 Jacopo Mondi 662306a36Sopenharmony_ci * Copyright (C) 2017-2019 Kieran Bingham 762306a36Sopenharmony_ci * Copyright (C) 2017-2019 Laurent Pinchart 862306a36Sopenharmony_ci * Copyright (C) 2017-2019 Niklas Söderlund 962306a36Sopenharmony_ci * Copyright (C) 2016 Renesas Electronics Corporation 1062306a36Sopenharmony_ci * Copyright (C) 2015 Cogent Embedded, Inc. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/delay.h> 1462306a36Sopenharmony_ci#include <linux/device.h> 1562306a36Sopenharmony_ci#include <linux/fwnode.h> 1662306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 1762306a36Sopenharmony_ci#include <linux/gpio/driver.h> 1862306a36Sopenharmony_ci#include <linux/gpio/machine.h> 1962306a36Sopenharmony_ci#include <linux/i2c.h> 2062306a36Sopenharmony_ci#include <linux/i2c-mux.h> 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci#include <linux/mutex.h> 2362306a36Sopenharmony_ci#include <linux/of_graph.h> 2462306a36Sopenharmony_ci#include <linux/regulator/consumer.h> 2562306a36Sopenharmony_ci#include <linux/slab.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <media/v4l2-async.h> 2862306a36Sopenharmony_ci#include <media/v4l2-ctrls.h> 2962306a36Sopenharmony_ci#include <media/v4l2-device.h> 3062306a36Sopenharmony_ci#include <media/v4l2-fwnode.h> 3162306a36Sopenharmony_ci#include <media/v4l2-subdev.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/* Register 0x00 */ 3462306a36Sopenharmony_ci#define MAX9286_MSTLINKSEL_AUTO (7 << 5) 3562306a36Sopenharmony_ci#define MAX9286_MSTLINKSEL(n) ((n) << 5) 3662306a36Sopenharmony_ci#define MAX9286_EN_VS_GEN BIT(4) 3762306a36Sopenharmony_ci#define MAX9286_LINKEN(n) (1 << (n)) 3862306a36Sopenharmony_ci/* Register 0x01 */ 3962306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_ECU (3 << 6) 4062306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_EXT (2 << 6) 4162306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_INT_OUT (1 << 6) 4262306a36Sopenharmony_ci#define MAX9286_FSYNCMODE_INT_HIZ (0 << 6) 4362306a36Sopenharmony_ci#define MAX9286_GPIEN BIT(5) 4462306a36Sopenharmony_ci#define MAX9286_ENLMO_RSTFSYNC BIT(2) 4562306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_AUTO (2 << 0) 4662306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_SEMI_AUTO (1 << 0) 4762306a36Sopenharmony_ci#define MAX9286_FSYNCMETH_MANUAL (0 << 0) 4862306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_L 0x06 4962306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_M 0x07 5062306a36Sopenharmony_ci#define MAX9286_REG_FSYNC_PERIOD_H 0x08 5162306a36Sopenharmony_ci/* Register 0x0a */ 5262306a36Sopenharmony_ci#define MAX9286_FWDCCEN(n) (1 << ((n) + 4)) 5362306a36Sopenharmony_ci#define MAX9286_REVCCEN(n) (1 << (n)) 5462306a36Sopenharmony_ci/* Register 0x0c */ 5562306a36Sopenharmony_ci#define MAX9286_HVEN BIT(7) 5662306a36Sopenharmony_ci#define MAX9286_EDC_6BIT_HAMMING (2 << 5) 5762306a36Sopenharmony_ci#define MAX9286_EDC_6BIT_CRC (1 << 5) 5862306a36Sopenharmony_ci#define MAX9286_EDC_1BIT_PARITY (0 << 5) 5962306a36Sopenharmony_ci#define MAX9286_DESEL BIT(4) 6062306a36Sopenharmony_ci#define MAX9286_INVVS BIT(3) 6162306a36Sopenharmony_ci#define MAX9286_INVHS BIT(2) 6262306a36Sopenharmony_ci#define MAX9286_HVSRC_D0 (2 << 0) 6362306a36Sopenharmony_ci#define MAX9286_HVSRC_D14 (1 << 0) 6462306a36Sopenharmony_ci#define MAX9286_HVSRC_D18 (0 << 0) 6562306a36Sopenharmony_ci/* Register 0x0f */ 6662306a36Sopenharmony_ci#define MAX9286_0X0F_RESERVED BIT(3) 6762306a36Sopenharmony_ci/* Register 0x12 */ 6862306a36Sopenharmony_ci#define MAX9286_CSILANECNT(n) (((n) - 1) << 6) 6962306a36Sopenharmony_ci#define MAX9286_CSIDBL BIT(5) 7062306a36Sopenharmony_ci#define MAX9286_DBL BIT(4) 7162306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_8BIT (11 << 0) 7262306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_YUV_12BIT (10 << 0) 7362306a36Sopenharmony_ci#define MAX9286_DATATYPE_USER_24BIT (9 << 0) 7462306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW14 (8 << 0) 7562306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW12 (7 << 0) 7662306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW10 (6 << 0) 7762306a36Sopenharmony_ci#define MAX9286_DATATYPE_RAW8 (5 << 0) 7862306a36Sopenharmony_ci#define MAX9286_DATATYPE_YUV422_10BIT (4 << 0) 7962306a36Sopenharmony_ci#define MAX9286_DATATYPE_YUV422_8BIT (3 << 0) 8062306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB555 (2 << 0) 8162306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB565 (1 << 0) 8262306a36Sopenharmony_ci#define MAX9286_DATATYPE_RGB888 (0 << 0) 8362306a36Sopenharmony_ci/* Register 0x15 */ 8462306a36Sopenharmony_ci#define MAX9286_CSI_IMAGE_TYP BIT(7) 8562306a36Sopenharmony_ci#define MAX9286_VC(n) ((n) << 5) 8662306a36Sopenharmony_ci#define MAX9286_VCTYPE BIT(4) 8762306a36Sopenharmony_ci#define MAX9286_CSIOUTEN BIT(3) 8862306a36Sopenharmony_ci#define MAX9286_SWP_ENDIAN BIT(2) 8962306a36Sopenharmony_ci#define MAX9286_EN_CCBSYB_CLK_STR BIT(1) 9062306a36Sopenharmony_ci#define MAX9286_EN_GPI_CCBSYB BIT(0) 9162306a36Sopenharmony_ci/* Register 0x1b */ 9262306a36Sopenharmony_ci#define MAX9286_SWITCHIN(n) (1 << ((n) + 4)) 9362306a36Sopenharmony_ci#define MAX9286_ENEQ(n) (1 << (n)) 9462306a36Sopenharmony_ci/* Register 0x1c */ 9562306a36Sopenharmony_ci#define MAX9286_HIGHIMM(n) BIT((n) + 4) 9662306a36Sopenharmony_ci#define MAX9286_I2CSEL BIT(2) 9762306a36Sopenharmony_ci#define MAX9286_HIBW BIT(1) 9862306a36Sopenharmony_ci#define MAX9286_BWS BIT(0) 9962306a36Sopenharmony_ci/* Register 0x27 */ 10062306a36Sopenharmony_ci#define MAX9286_LOCKED BIT(7) 10162306a36Sopenharmony_ci/* Register 0x31 */ 10262306a36Sopenharmony_ci#define MAX9286_FSYNC_LOCKED BIT(6) 10362306a36Sopenharmony_ci/* Register 0x34 */ 10462306a36Sopenharmony_ci#define MAX9286_I2CLOCACK BIT(7) 10562306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_1046NS_469NS (3 << 5) 10662306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_938NS_352NS (2 << 5) 10762306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_469NS_234NS (1 << 5) 10862306a36Sopenharmony_ci#define MAX9286_I2CSLVSH_352NS_117NS (0 << 5) 10962306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_837KBPS (7 << 2) 11062306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_533KBPS (6 << 2) 11162306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_339KBPS (5 << 2) 11262306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_173KBPS (4 << 2) 11362306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_105KBPS (3 << 2) 11462306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_84KBPS (2 << 2) 11562306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_28KBPS (1 << 2) 11662306a36Sopenharmony_ci#define MAX9286_I2CMSTBT_8KBPS (0 << 2) 11762306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_NONE (3 << 0) 11862306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_1024US (2 << 0) 11962306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_256US (1 << 0) 12062306a36Sopenharmony_ci#define MAX9286_I2CSLVTO_64US (0 << 0) 12162306a36Sopenharmony_ci/* Register 0x3b */ 12262306a36Sopenharmony_ci#define MAX9286_REV_TRF(n) ((n) << 4) 12362306a36Sopenharmony_ci#define MAX9286_REV_AMP(n) ((((n) - 30) / 10) << 1) /* in mV */ 12462306a36Sopenharmony_ci#define MAX9286_REV_AMP_X BIT(0) 12562306a36Sopenharmony_ci#define MAX9286_REV_AMP_HIGH 170 12662306a36Sopenharmony_ci/* Register 0x3f */ 12762306a36Sopenharmony_ci#define MAX9286_EN_REV_CFG BIT(6) 12862306a36Sopenharmony_ci#define MAX9286_REV_FLEN(n) ((n) - 20) 12962306a36Sopenharmony_ci/* Register 0x49 */ 13062306a36Sopenharmony_ci#define MAX9286_VIDEO_DETECT_MASK 0x0f 13162306a36Sopenharmony_ci/* Register 0x69 */ 13262306a36Sopenharmony_ci#define MAX9286_LFLTBMONMASKED BIT(7) 13362306a36Sopenharmony_ci#define MAX9286_LOCKMONMASKED BIT(6) 13462306a36Sopenharmony_ci#define MAX9286_AUTOCOMBACKEN BIT(5) 13562306a36Sopenharmony_ci#define MAX9286_AUTOMASKEN BIT(4) 13662306a36Sopenharmony_ci#define MAX9286_MASKLINK(n) ((n) << 0) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* 13962306a36Sopenharmony_ci * The sink and source pads are created to match the OF graph port numbers so 14062306a36Sopenharmony_ci * that their indexes can be used interchangeably. 14162306a36Sopenharmony_ci */ 14262306a36Sopenharmony_ci#define MAX9286_NUM_GMSL 4 14362306a36Sopenharmony_ci#define MAX9286_N_SINKS 4 14462306a36Sopenharmony_ci#define MAX9286_N_PADS 5 14562306a36Sopenharmony_ci#define MAX9286_SRC_PAD 4 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistruct max9286_format_info { 14862306a36Sopenharmony_ci u32 code; 14962306a36Sopenharmony_ci u8 datatype; 15062306a36Sopenharmony_ci}; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistruct max9286_i2c_speed { 15362306a36Sopenharmony_ci u32 rate; 15462306a36Sopenharmony_ci u8 mstbt; 15562306a36Sopenharmony_ci}; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_cistruct max9286_source { 15862306a36Sopenharmony_ci struct v4l2_subdev *sd; 15962306a36Sopenharmony_ci struct fwnode_handle *fwnode; 16062306a36Sopenharmony_ci struct regulator *regulator; 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct max9286_asd { 16462306a36Sopenharmony_ci struct v4l2_async_connection base; 16562306a36Sopenharmony_ci struct max9286_source *source; 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic inline struct max9286_asd * 16962306a36Sopenharmony_cito_max9286_asd(struct v4l2_async_connection *asd) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci return container_of(asd, struct max9286_asd, base); 17262306a36Sopenharmony_ci} 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_cistruct max9286_priv { 17562306a36Sopenharmony_ci struct i2c_client *client; 17662306a36Sopenharmony_ci struct gpio_desc *gpiod_pwdn; 17762306a36Sopenharmony_ci struct v4l2_subdev sd; 17862306a36Sopenharmony_ci struct media_pad pads[MAX9286_N_PADS]; 17962306a36Sopenharmony_ci struct regulator *regulator; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci struct gpio_chip gpio; 18262306a36Sopenharmony_ci u8 gpio_state; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci struct i2c_mux_core *mux; 18562306a36Sopenharmony_ci unsigned int mux_channel; 18662306a36Sopenharmony_ci bool mux_open; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* The initial reverse control channel amplitude. */ 18962306a36Sopenharmony_ci u32 init_rev_chan_mv; 19062306a36Sopenharmony_ci u32 rev_chan_mv; 19162306a36Sopenharmony_ci u8 i2c_mstbt; 19262306a36Sopenharmony_ci u32 bus_width; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci bool use_gpio_poc; 19562306a36Sopenharmony_ci u32 gpio_poc[2]; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci struct v4l2_ctrl_handler ctrls; 19862306a36Sopenharmony_ci struct v4l2_ctrl *pixelrate_ctrl; 19962306a36Sopenharmony_ci unsigned int pixelrate; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS]; 20262306a36Sopenharmony_ci struct v4l2_fract interval; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Protects controls and fmt structures */ 20562306a36Sopenharmony_ci struct mutex mutex; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci unsigned int nsources; 20862306a36Sopenharmony_ci unsigned int source_mask; 20962306a36Sopenharmony_ci unsigned int route_mask; 21062306a36Sopenharmony_ci unsigned int bound_sources; 21162306a36Sopenharmony_ci unsigned int csi2_data_lanes; 21262306a36Sopenharmony_ci struct max9286_source sources[MAX9286_NUM_GMSL]; 21362306a36Sopenharmony_ci struct v4l2_async_notifier notifier; 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistatic struct max9286_source *next_source(struct max9286_priv *priv, 21762306a36Sopenharmony_ci struct max9286_source *source) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci if (!source) 22062306a36Sopenharmony_ci source = &priv->sources[0]; 22162306a36Sopenharmony_ci else 22262306a36Sopenharmony_ci source++; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci for (; source < &priv->sources[MAX9286_NUM_GMSL]; source++) { 22562306a36Sopenharmony_ci if (source->fwnode) 22662306a36Sopenharmony_ci return source; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return NULL; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#define for_each_source(priv, source) \ 23362306a36Sopenharmony_ci for ((source) = NULL; ((source) = next_source((priv), (source))); ) 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci#define to_index(priv, source) ((source) - &(priv)->sources[0]) 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic inline struct max9286_priv *sd_to_max9286(struct v4l2_subdev *sd) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci return container_of(sd, struct max9286_priv, sd); 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic const struct max9286_format_info max9286_formats[] = { 24362306a36Sopenharmony_ci { 24462306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_1X16, 24562306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_YUV422_8BIT, 24662306a36Sopenharmony_ci }, { 24762306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_VYUY8_1X16, 24862306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_YUV422_8BIT, 24962306a36Sopenharmony_ci }, { 25062306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YUYV8_1X16, 25162306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_YUV422_8BIT, 25262306a36Sopenharmony_ci }, { 25362306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_YVYU8_1X16, 25462306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_YUV422_8BIT, 25562306a36Sopenharmony_ci }, { 25662306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SBGGR12_1X12, 25762306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_RAW12, 25862306a36Sopenharmony_ci }, { 25962306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGBRG12_1X12, 26062306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_RAW12, 26162306a36Sopenharmony_ci }, { 26262306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SGRBG12_1X12, 26362306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_RAW12, 26462306a36Sopenharmony_ci }, { 26562306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_SRGGB12_1X12, 26662306a36Sopenharmony_ci .datatype = MAX9286_DATATYPE_RAW12, 26762306a36Sopenharmony_ci }, 26862306a36Sopenharmony_ci}; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic const struct max9286_i2c_speed max9286_i2c_speeds[] = { 27162306a36Sopenharmony_ci { .rate = 8470, .mstbt = MAX9286_I2CMSTBT_8KBPS }, 27262306a36Sopenharmony_ci { .rate = 28300, .mstbt = MAX9286_I2CMSTBT_28KBPS }, 27362306a36Sopenharmony_ci { .rate = 84700, .mstbt = MAX9286_I2CMSTBT_84KBPS }, 27462306a36Sopenharmony_ci { .rate = 105000, .mstbt = MAX9286_I2CMSTBT_105KBPS }, 27562306a36Sopenharmony_ci { .rate = 173000, .mstbt = MAX9286_I2CMSTBT_173KBPS }, 27662306a36Sopenharmony_ci { .rate = 339000, .mstbt = MAX9286_I2CMSTBT_339KBPS }, 27762306a36Sopenharmony_ci { .rate = 533000, .mstbt = MAX9286_I2CMSTBT_533KBPS }, 27862306a36Sopenharmony_ci { .rate = 837000, .mstbt = MAX9286_I2CMSTBT_837KBPS }, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 28262306a36Sopenharmony_ci * I2C IO 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int max9286_read(struct max9286_priv *priv, u8 reg) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int ret; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci ret = i2c_smbus_read_byte_data(priv->client, reg); 29062306a36Sopenharmony_ci if (ret < 0) 29162306a36Sopenharmony_ci dev_err(&priv->client->dev, 29262306a36Sopenharmony_ci "%s: register 0x%02x read failed (%d)\n", 29362306a36Sopenharmony_ci __func__, reg, ret); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic int max9286_write(struct max9286_priv *priv, u8 reg, u8 val) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci int ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci ret = i2c_smbus_write_byte_data(priv->client, reg, val); 30362306a36Sopenharmony_ci if (ret < 0) 30462306a36Sopenharmony_ci dev_err(&priv->client->dev, 30562306a36Sopenharmony_ci "%s: register 0x%02x write failed (%d)\n", 30662306a36Sopenharmony_ci __func__, reg, ret); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 31262306a36Sopenharmony_ci * I2C Multiplexer 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void max9286_i2c_mux_configure(struct max9286_priv *priv, u8 conf) 31662306a36Sopenharmony_ci{ 31762306a36Sopenharmony_ci max9286_write(priv, 0x0a, conf); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * We must sleep after any change to the forward or reverse channel 32162306a36Sopenharmony_ci * configuration. 32262306a36Sopenharmony_ci */ 32362306a36Sopenharmony_ci usleep_range(3000, 5000); 32462306a36Sopenharmony_ci} 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_cistatic void max9286_i2c_mux_open(struct max9286_priv *priv) 32762306a36Sopenharmony_ci{ 32862306a36Sopenharmony_ci /* Open all channels on the MAX9286 */ 32962306a36Sopenharmony_ci max9286_i2c_mux_configure(priv, 0xff); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci priv->mux_open = true; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void max9286_i2c_mux_close(struct max9286_priv *priv) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci /* 33762306a36Sopenharmony_ci * Ensure that both the forward and reverse channel are disabled on the 33862306a36Sopenharmony_ci * mux, and that the channel ID is invalidated to ensure we reconfigure 33962306a36Sopenharmony_ci * on the next max9286_i2c_mux_select() call. 34062306a36Sopenharmony_ci */ 34162306a36Sopenharmony_ci max9286_i2c_mux_configure(priv, 0x00); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci priv->mux_open = false; 34462306a36Sopenharmony_ci priv->mux_channel = -1; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int max9286_i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct max9286_priv *priv = i2c_mux_priv(muxc); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci /* Channel select is disabled when configured in the opened state. */ 35262306a36Sopenharmony_ci if (priv->mux_open) 35362306a36Sopenharmony_ci return 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci if (priv->mux_channel == chan) 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci priv->mux_channel = chan; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci max9286_i2c_mux_configure(priv, MAX9286_FWDCCEN(chan) | 36162306a36Sopenharmony_ci MAX9286_REVCCEN(chan)); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci} 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic int max9286_i2c_mux_init(struct max9286_priv *priv) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci struct max9286_source *source; 36962306a36Sopenharmony_ci int ret; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci if (!i2c_check_functionality(priv->client->adapter, 37262306a36Sopenharmony_ci I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) 37362306a36Sopenharmony_ci return -ENODEV; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev, 37662306a36Sopenharmony_ci priv->nsources, 0, I2C_MUX_LOCKED, 37762306a36Sopenharmony_ci max9286_i2c_mux_select, NULL); 37862306a36Sopenharmony_ci if (!priv->mux) 37962306a36Sopenharmony_ci return -ENOMEM; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci priv->mux->priv = priv; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci for_each_source(priv, source) { 38462306a36Sopenharmony_ci unsigned int index = to_index(priv, source); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci ret = i2c_mux_add_adapter(priv->mux, 0, index, 0); 38762306a36Sopenharmony_ci if (ret < 0) 38862306a36Sopenharmony_ci goto error; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return 0; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_cierror: 39462306a36Sopenharmony_ci i2c_mux_del_adapters(priv->mux); 39562306a36Sopenharmony_ci return ret; 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic void max9286_configure_i2c(struct max9286_priv *priv, bool localack) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci u8 config = MAX9286_I2CSLVSH_469NS_234NS | MAX9286_I2CSLVTO_1024US | 40162306a36Sopenharmony_ci priv->i2c_mstbt; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (localack) 40462306a36Sopenharmony_ci config |= MAX9286_I2CLOCACK; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci max9286_write(priv, 0x34, config); 40762306a36Sopenharmony_ci usleep_range(3000, 5000); 40862306a36Sopenharmony_ci} 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic void max9286_reverse_channel_setup(struct max9286_priv *priv, 41162306a36Sopenharmony_ci unsigned int chan_amplitude) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci u8 chan_config; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (priv->rev_chan_mv == chan_amplitude) 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci priv->rev_chan_mv = chan_amplitude; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci /* Reverse channel transmission time: default to 1. */ 42162306a36Sopenharmony_ci chan_config = MAX9286_REV_TRF(1); 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* 42462306a36Sopenharmony_ci * Reverse channel setup. 42562306a36Sopenharmony_ci * 42662306a36Sopenharmony_ci * - Enable custom reverse channel configuration (through register 0x3f) 42762306a36Sopenharmony_ci * and set the first pulse length to 35 clock cycles. 42862306a36Sopenharmony_ci * - Adjust reverse channel amplitude: values > 130 are programmed 42962306a36Sopenharmony_ci * using the additional +100mV REV_AMP_X boost flag 43062306a36Sopenharmony_ci */ 43162306a36Sopenharmony_ci max9286_write(priv, 0x3f, MAX9286_EN_REV_CFG | MAX9286_REV_FLEN(35)); 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci if (chan_amplitude > 100) { 43462306a36Sopenharmony_ci /* It is not possible to express values (100 < x < 130) */ 43562306a36Sopenharmony_ci chan_amplitude = max(30U, chan_amplitude - 100); 43662306a36Sopenharmony_ci chan_config |= MAX9286_REV_AMP_X; 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci max9286_write(priv, 0x3b, chan_config | MAX9286_REV_AMP(chan_amplitude)); 43962306a36Sopenharmony_ci usleep_range(2000, 2500); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci/* 44362306a36Sopenharmony_ci * max9286_check_video_links() - Make sure video links are detected and locked 44462306a36Sopenharmony_ci * 44562306a36Sopenharmony_ci * Performs safety checks on video link status. Make sure they are detected 44662306a36Sopenharmony_ci * and all enabled links are locked. 44762306a36Sopenharmony_ci * 44862306a36Sopenharmony_ci * Returns 0 for success, -EIO for errors. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_cistatic int max9286_check_video_links(struct max9286_priv *priv) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci unsigned int i; 45362306a36Sopenharmony_ci int ret; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci /* 45662306a36Sopenharmony_ci * Make sure valid video links are detected. 45762306a36Sopenharmony_ci * The delay is not characterized in de-serializer manual, wait up 45862306a36Sopenharmony_ci * to 5 ms. 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 46162306a36Sopenharmony_ci ret = max9286_read(priv, 0x49); 46262306a36Sopenharmony_ci if (ret < 0) 46362306a36Sopenharmony_ci return -EIO; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if ((ret & MAX9286_VIDEO_DETECT_MASK) == priv->source_mask) 46662306a36Sopenharmony_ci break; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci usleep_range(350, 500); 46962306a36Sopenharmony_ci } 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci if (i == 10) { 47262306a36Sopenharmony_ci dev_err(&priv->client->dev, 47362306a36Sopenharmony_ci "Unable to detect video links: 0x%02x\n", ret); 47462306a36Sopenharmony_ci return -EIO; 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci /* Make sure all enabled links are locked (4ms max). */ 47862306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 47962306a36Sopenharmony_ci ret = max9286_read(priv, 0x27); 48062306a36Sopenharmony_ci if (ret < 0) 48162306a36Sopenharmony_ci return -EIO; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (ret & MAX9286_LOCKED) 48462306a36Sopenharmony_ci break; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci usleep_range(350, 450); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci if (i == 10) { 49062306a36Sopenharmony_ci dev_err(&priv->client->dev, "Not all enabled links locked\n"); 49162306a36Sopenharmony_ci return -EIO; 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci return 0; 49562306a36Sopenharmony_ci} 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci/* 49862306a36Sopenharmony_ci * max9286_check_config_link() - Detect and wait for configuration links 49962306a36Sopenharmony_ci * 50062306a36Sopenharmony_ci * Determine if the configuration channel is up and settled for a link. 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * Returns 0 for success, -EIO for errors. 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic int max9286_check_config_link(struct max9286_priv *priv, 50562306a36Sopenharmony_ci unsigned int source_mask) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci unsigned int conflink_mask = (source_mask & 0x0f) << 4; 50862306a36Sopenharmony_ci unsigned int i; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* 51262306a36Sopenharmony_ci * Make sure requested configuration links are detected. 51362306a36Sopenharmony_ci * The delay is not characterized in the chip manual: wait up 51462306a36Sopenharmony_ci * to 5 milliseconds. 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci for (i = 0; i < 10; i++) { 51762306a36Sopenharmony_ci ret = max9286_read(priv, 0x49); 51862306a36Sopenharmony_ci if (ret < 0) 51962306a36Sopenharmony_ci return -EIO; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ret &= 0xf0; 52262306a36Sopenharmony_ci if (ret == conflink_mask) 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci usleep_range(350, 500); 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci if (ret != conflink_mask) { 52962306a36Sopenharmony_ci dev_err(&priv->client->dev, 53062306a36Sopenharmony_ci "Unable to detect configuration links: 0x%02x expected 0x%02x\n", 53162306a36Sopenharmony_ci ret, conflink_mask); 53262306a36Sopenharmony_ci return -EIO; 53362306a36Sopenharmony_ci } 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci dev_info(&priv->client->dev, 53662306a36Sopenharmony_ci "Successfully detected configuration links after %u loops: 0x%02x\n", 53762306a36Sopenharmony_ci i, conflink_mask); 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return 0; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic void max9286_set_video_format(struct max9286_priv *priv, 54362306a36Sopenharmony_ci const struct v4l2_mbus_framefmt *format) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci const struct max9286_format_info *info = NULL; 54662306a36Sopenharmony_ci unsigned int i; 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { 54962306a36Sopenharmony_ci if (max9286_formats[i].code == format->code) { 55062306a36Sopenharmony_ci info = &max9286_formats[i]; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (WARN_ON(!info)) 55662306a36Sopenharmony_ci return; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* 55962306a36Sopenharmony_ci * Video format setup: disable CSI output, set VC according to Link 56062306a36Sopenharmony_ci * number, enable I2C clock stretching when CCBSY is low, enable CCBSY 56162306a36Sopenharmony_ci * in external GPI-to-GPO mode. 56262306a36Sopenharmony_ci */ 56362306a36Sopenharmony_ci max9286_write(priv, 0x15, MAX9286_VCTYPE | MAX9286_EN_CCBSYB_CLK_STR | 56462306a36Sopenharmony_ci MAX9286_EN_GPI_CCBSYB); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Enable CSI-2 Lane D0-D3 only, DBL mode. */ 56762306a36Sopenharmony_ci max9286_write(priv, 0x12, MAX9286_CSIDBL | MAX9286_DBL | 56862306a36Sopenharmony_ci MAX9286_CSILANECNT(priv->csi2_data_lanes) | 56962306a36Sopenharmony_ci info->datatype); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci /* 57262306a36Sopenharmony_ci * Enable HS/VS encoding, use HS as line valid source, use D14/15 for 57362306a36Sopenharmony_ci * HS/VS, invert VS. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_ci max9286_write(priv, 0x0c, MAX9286_HVEN | MAX9286_DESEL | 57662306a36Sopenharmony_ci MAX9286_INVVS | MAX9286_HVSRC_D14); 57762306a36Sopenharmony_ci} 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_cistatic void max9286_set_fsync_period(struct max9286_priv *priv) 58062306a36Sopenharmony_ci{ 58162306a36Sopenharmony_ci u32 fsync; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (!priv->interval.numerator || !priv->interval.denominator) { 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * Special case, a null interval enables automatic FRAMESYNC 58662306a36Sopenharmony_ci * mode. FRAMESYNC is taken from the slowest link. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_HIZ | 58962306a36Sopenharmony_ci MAX9286_FSYNCMETH_AUTO); 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci /* 59462306a36Sopenharmony_ci * Manual FRAMESYNC 59562306a36Sopenharmony_ci * 59662306a36Sopenharmony_ci * The FRAMESYNC generator is configured with a period expressed as a 59762306a36Sopenharmony_ci * number of PCLK periods. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator, 60062306a36Sopenharmony_ci priv->interval.denominator); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, 60362306a36Sopenharmony_ci priv->pixelrate); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci max9286_write(priv, 0x01, MAX9286_FSYNCMODE_INT_OUT | 60662306a36Sopenharmony_ci MAX9286_FSYNCMETH_MANUAL); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci max9286_write(priv, 0x06, (fsync >> 0) & 0xff); 60962306a36Sopenharmony_ci max9286_write(priv, 0x07, (fsync >> 8) & 0xff); 61062306a36Sopenharmony_ci max9286_write(priv, 0x08, (fsync >> 16) & 0xff); 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 61462306a36Sopenharmony_ci * V4L2 Subdev 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_cistatic int max9286_set_pixelrate(struct max9286_priv *priv) 61862306a36Sopenharmony_ci{ 61962306a36Sopenharmony_ci struct max9286_source *source = NULL; 62062306a36Sopenharmony_ci u64 pixelrate = 0; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci for_each_source(priv, source) { 62362306a36Sopenharmony_ci struct v4l2_ctrl *ctrl; 62462306a36Sopenharmony_ci u64 source_rate = 0; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* Pixel rate is mandatory to be reported by sources. */ 62762306a36Sopenharmony_ci ctrl = v4l2_ctrl_find(source->sd->ctrl_handler, 62862306a36Sopenharmony_ci V4L2_CID_PIXEL_RATE); 62962306a36Sopenharmony_ci if (!ctrl) { 63062306a36Sopenharmony_ci pixelrate = 0; 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci } 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci /* All source must report the same pixel rate. */ 63562306a36Sopenharmony_ci source_rate = v4l2_ctrl_g_ctrl_int64(ctrl); 63662306a36Sopenharmony_ci if (!pixelrate) { 63762306a36Sopenharmony_ci pixelrate = source_rate; 63862306a36Sopenharmony_ci } else if (pixelrate != source_rate) { 63962306a36Sopenharmony_ci dev_err(&priv->client->dev, 64062306a36Sopenharmony_ci "Unable to calculate pixel rate\n"); 64162306a36Sopenharmony_ci return -EINVAL; 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci if (!pixelrate) { 64662306a36Sopenharmony_ci dev_err(&priv->client->dev, 64762306a36Sopenharmony_ci "No pixel rate control available in sources\n"); 64862306a36Sopenharmony_ci return -EINVAL; 64962306a36Sopenharmony_ci } 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci priv->pixelrate = pixelrate; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci /* 65462306a36Sopenharmony_ci * The CSI-2 transmitter pixel rate is the single source rate multiplied 65562306a36Sopenharmony_ci * by the number of available sources. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci return v4l2_ctrl_s_ctrl_int64(priv->pixelrate_ctrl, 65862306a36Sopenharmony_ci pixelrate * priv->nsources); 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_cistatic int max9286_notify_bound(struct v4l2_async_notifier *notifier, 66262306a36Sopenharmony_ci struct v4l2_subdev *subdev, 66362306a36Sopenharmony_ci struct v4l2_async_connection *asd) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(notifier->sd); 66662306a36Sopenharmony_ci struct max9286_source *source = to_max9286_asd(asd)->source; 66762306a36Sopenharmony_ci unsigned int index = to_index(priv, source); 66862306a36Sopenharmony_ci unsigned int src_pad; 66962306a36Sopenharmony_ci int ret; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci ret = media_entity_get_fwnode_pad(&subdev->entity, 67262306a36Sopenharmony_ci source->fwnode, 67362306a36Sopenharmony_ci MEDIA_PAD_FL_SOURCE); 67462306a36Sopenharmony_ci if (ret < 0) { 67562306a36Sopenharmony_ci dev_err(&priv->client->dev, 67662306a36Sopenharmony_ci "Failed to find pad for %s\n", subdev->name); 67762306a36Sopenharmony_ci return ret; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci priv->bound_sources |= BIT(index); 68162306a36Sopenharmony_ci source->sd = subdev; 68262306a36Sopenharmony_ci src_pad = ret; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ret = media_create_pad_link(&source->sd->entity, src_pad, 68562306a36Sopenharmony_ci &priv->sd.entity, index, 68662306a36Sopenharmony_ci MEDIA_LNK_FL_ENABLED | 68762306a36Sopenharmony_ci MEDIA_LNK_FL_IMMUTABLE); 68862306a36Sopenharmony_ci if (ret) { 68962306a36Sopenharmony_ci dev_err(&priv->client->dev, 69062306a36Sopenharmony_ci "Unable to link %s:%u -> %s:%u\n", 69162306a36Sopenharmony_ci source->sd->name, src_pad, priv->sd.name, index); 69262306a36Sopenharmony_ci return ret; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "Bound %s pad: %u on index %u\n", 69662306a36Sopenharmony_ci subdev->name, src_pad, index); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* 69962306a36Sopenharmony_ci * As we register a subdev notifiers we won't get a .complete() callback 70062306a36Sopenharmony_ci * here, so we have to use bound_sources to identify when all remote 70162306a36Sopenharmony_ci * serializers have probed. 70262306a36Sopenharmony_ci */ 70362306a36Sopenharmony_ci if (priv->bound_sources != priv->source_mask) 70462306a36Sopenharmony_ci return 0; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci /* 70762306a36Sopenharmony_ci * All enabled sources have probed and enabled their reverse control 70862306a36Sopenharmony_ci * channels: 70962306a36Sopenharmony_ci * 71062306a36Sopenharmony_ci * - Increase the reverse channel amplitude to compensate for the 71162306a36Sopenharmony_ci * remote ends high threshold 71262306a36Sopenharmony_ci * - Verify all configuration links are properly detected 71362306a36Sopenharmony_ci * - Disable auto-ack as communication on the control channel are now 71462306a36Sopenharmony_ci * stable. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci max9286_reverse_channel_setup(priv, MAX9286_REV_AMP_HIGH); 71762306a36Sopenharmony_ci max9286_check_config_link(priv, priv->source_mask); 71862306a36Sopenharmony_ci max9286_configure_i2c(priv, false); 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci return max9286_set_pixelrate(priv); 72162306a36Sopenharmony_ci} 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cistatic void max9286_notify_unbind(struct v4l2_async_notifier *notifier, 72462306a36Sopenharmony_ci struct v4l2_subdev *subdev, 72562306a36Sopenharmony_ci struct v4l2_async_connection *asd) 72662306a36Sopenharmony_ci{ 72762306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(notifier->sd); 72862306a36Sopenharmony_ci struct max9286_source *source = to_max9286_asd(asd)->source; 72962306a36Sopenharmony_ci unsigned int index = to_index(priv, source); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci source->sd = NULL; 73262306a36Sopenharmony_ci priv->bound_sources &= ~BIT(index); 73362306a36Sopenharmony_ci} 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_cistatic const struct v4l2_async_notifier_operations max9286_notify_ops = { 73662306a36Sopenharmony_ci .bound = max9286_notify_bound, 73762306a36Sopenharmony_ci .unbind = max9286_notify_unbind, 73862306a36Sopenharmony_ci}; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int max9286_v4l2_notifier_register(struct max9286_priv *priv) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 74362306a36Sopenharmony_ci struct max9286_source *source = NULL; 74462306a36Sopenharmony_ci int ret; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (!priv->nsources) 74762306a36Sopenharmony_ci return 0; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci for_each_source(priv, source) { 75262306a36Sopenharmony_ci unsigned int i = to_index(priv, source); 75362306a36Sopenharmony_ci struct max9286_asd *mas; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci mas = v4l2_async_nf_add_fwnode(&priv->notifier, source->fwnode, 75662306a36Sopenharmony_ci struct max9286_asd); 75762306a36Sopenharmony_ci if (IS_ERR(mas)) { 75862306a36Sopenharmony_ci dev_err(dev, "Failed to add subdev for source %u: %ld", 75962306a36Sopenharmony_ci i, PTR_ERR(mas)); 76062306a36Sopenharmony_ci v4l2_async_nf_cleanup(&priv->notifier); 76162306a36Sopenharmony_ci return PTR_ERR(mas); 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci mas->source = source; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci priv->notifier.ops = &max9286_notify_ops; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci ret = v4l2_async_nf_register(&priv->notifier); 77062306a36Sopenharmony_ci if (ret) { 77162306a36Sopenharmony_ci dev_err(dev, "Failed to register subdev_notifier"); 77262306a36Sopenharmony_ci v4l2_async_nf_cleanup(&priv->notifier); 77362306a36Sopenharmony_ci return ret; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci return 0; 77762306a36Sopenharmony_ci} 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_cistatic void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) 78062306a36Sopenharmony_ci{ 78162306a36Sopenharmony_ci if (!priv->nsources) 78262306a36Sopenharmony_ci return; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci v4l2_async_nf_unregister(&priv->notifier); 78562306a36Sopenharmony_ci v4l2_async_nf_cleanup(&priv->notifier); 78662306a36Sopenharmony_ci} 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_cistatic int max9286_s_stream(struct v4l2_subdev *sd, int enable) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(sd); 79162306a36Sopenharmony_ci struct max9286_source *source; 79262306a36Sopenharmony_ci unsigned int i; 79362306a36Sopenharmony_ci bool sync = false; 79462306a36Sopenharmony_ci int ret; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (enable) { 79762306a36Sopenharmony_ci const struct v4l2_mbus_framefmt *format; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* 80062306a36Sopenharmony_ci * Get the format from the first used sink pad, as all sink 80162306a36Sopenharmony_ci * formats must be identical. 80262306a36Sopenharmony_ci */ 80362306a36Sopenharmony_ci format = &priv->fmt[__ffs(priv->bound_sources)]; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci max9286_set_video_format(priv, format); 80662306a36Sopenharmony_ci max9286_set_fsync_period(priv); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * The frame sync between cameras is transmitted across the 81062306a36Sopenharmony_ci * reverse channel as GPIO. We must open all channels while 81162306a36Sopenharmony_ci * streaming to allow this synchronisation signal to be shared. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci max9286_i2c_mux_open(priv); 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci /* Start all cameras. */ 81662306a36Sopenharmony_ci for_each_source(priv, source) { 81762306a36Sopenharmony_ci ret = v4l2_subdev_call(source->sd, video, s_stream, 1); 81862306a36Sopenharmony_ci if (ret) 81962306a36Sopenharmony_ci return ret; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci ret = max9286_check_video_links(priv); 82362306a36Sopenharmony_ci if (ret) 82462306a36Sopenharmony_ci return ret; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* 82762306a36Sopenharmony_ci * Wait until frame synchronization is locked. 82862306a36Sopenharmony_ci * 82962306a36Sopenharmony_ci * Manual says frame sync locking should take ~6 VTS. 83062306a36Sopenharmony_ci * From practical experience at least 8 are required. Give 83162306a36Sopenharmony_ci * 12 complete frames time (~400ms at 30 fps) to achieve frame 83262306a36Sopenharmony_ci * locking before returning error. 83362306a36Sopenharmony_ci */ 83462306a36Sopenharmony_ci for (i = 0; i < 40; i++) { 83562306a36Sopenharmony_ci if (max9286_read(priv, 0x31) & MAX9286_FSYNC_LOCKED) { 83662306a36Sopenharmony_ci sync = true; 83762306a36Sopenharmony_ci break; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci usleep_range(9000, 11000); 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (!sync) { 84362306a36Sopenharmony_ci dev_err(&priv->client->dev, 84462306a36Sopenharmony_ci "Failed to get frame synchronization\n"); 84562306a36Sopenharmony_ci return -EXDEV; /* Invalid cross-device link */ 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* 84962306a36Sopenharmony_ci * Configure the CSI-2 output to line interleaved mode (W x (N 85062306a36Sopenharmony_ci * x H), as opposed to the (N x W) x H mode that outputs the 85162306a36Sopenharmony_ci * images stitched side-by-side) and enable it. 85262306a36Sopenharmony_ci */ 85362306a36Sopenharmony_ci max9286_write(priv, 0x15, MAX9286_CSI_IMAGE_TYP | MAX9286_VCTYPE | 85462306a36Sopenharmony_ci MAX9286_CSIOUTEN | MAX9286_EN_CCBSYB_CLK_STR | 85562306a36Sopenharmony_ci MAX9286_EN_GPI_CCBSYB); 85662306a36Sopenharmony_ci } else { 85762306a36Sopenharmony_ci max9286_write(priv, 0x15, MAX9286_VCTYPE | 85862306a36Sopenharmony_ci MAX9286_EN_CCBSYB_CLK_STR | 85962306a36Sopenharmony_ci MAX9286_EN_GPI_CCBSYB); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci /* Stop all cameras. */ 86262306a36Sopenharmony_ci for_each_source(priv, source) 86362306a36Sopenharmony_ci v4l2_subdev_call(source->sd, video, s_stream, 0); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci max9286_i2c_mux_close(priv); 86662306a36Sopenharmony_ci } 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci return 0; 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic int max9286_g_frame_interval(struct v4l2_subdev *sd, 87262306a36Sopenharmony_ci struct v4l2_subdev_frame_interval *interval) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(sd); 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci if (interval->pad != MAX9286_SRC_PAD) 87762306a36Sopenharmony_ci return -EINVAL; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci interval->interval = priv->interval; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int max9286_s_frame_interval(struct v4l2_subdev *sd, 88562306a36Sopenharmony_ci struct v4l2_subdev_frame_interval *interval) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(sd); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (interval->pad != MAX9286_SRC_PAD) 89062306a36Sopenharmony_ci return -EINVAL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci priv->interval = interval->interval; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return 0; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int max9286_enum_mbus_code(struct v4l2_subdev *sd, 89862306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 89962306a36Sopenharmony_ci struct v4l2_subdev_mbus_code_enum *code) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci if (code->pad || code->index > 0) 90262306a36Sopenharmony_ci return -EINVAL; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci code->code = MEDIA_BUS_FMT_UYVY8_1X16; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic struct v4l2_mbus_framefmt * 91062306a36Sopenharmony_cimax9286_get_pad_format(struct max9286_priv *priv, 91162306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 91262306a36Sopenharmony_ci unsigned int pad, u32 which) 91362306a36Sopenharmony_ci{ 91462306a36Sopenharmony_ci switch (which) { 91562306a36Sopenharmony_ci case V4L2_SUBDEV_FORMAT_TRY: 91662306a36Sopenharmony_ci return v4l2_subdev_get_try_format(&priv->sd, sd_state, pad); 91762306a36Sopenharmony_ci case V4L2_SUBDEV_FORMAT_ACTIVE: 91862306a36Sopenharmony_ci return &priv->fmt[pad]; 91962306a36Sopenharmony_ci default: 92062306a36Sopenharmony_ci return NULL; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci} 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_cistatic int max9286_set_fmt(struct v4l2_subdev *sd, 92562306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 92662306a36Sopenharmony_ci struct v4l2_subdev_format *format) 92762306a36Sopenharmony_ci{ 92862306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(sd); 92962306a36Sopenharmony_ci struct v4l2_mbus_framefmt *cfg_fmt; 93062306a36Sopenharmony_ci unsigned int i; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (format->pad == MAX9286_SRC_PAD) 93362306a36Sopenharmony_ci return -EINVAL; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* Validate the format. */ 93662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { 93762306a36Sopenharmony_ci if (max9286_formats[i].code == format->format.code) 93862306a36Sopenharmony_ci break; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci if (i == ARRAY_SIZE(max9286_formats)) 94262306a36Sopenharmony_ci format->format.code = max9286_formats[0].code; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad, 94562306a36Sopenharmony_ci format->which); 94662306a36Sopenharmony_ci if (!cfg_fmt) 94762306a36Sopenharmony_ci return -EINVAL; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci mutex_lock(&priv->mutex); 95062306a36Sopenharmony_ci *cfg_fmt = format->format; 95162306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic int max9286_get_fmt(struct v4l2_subdev *sd, 95762306a36Sopenharmony_ci struct v4l2_subdev_state *sd_state, 95862306a36Sopenharmony_ci struct v4l2_subdev_format *format) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(sd); 96162306a36Sopenharmony_ci struct v4l2_mbus_framefmt *cfg_fmt; 96262306a36Sopenharmony_ci unsigned int pad = format->pad; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* 96562306a36Sopenharmony_ci * Multiplexed Stream Support: Support link validation by returning the 96662306a36Sopenharmony_ci * format of the first bound link. All links must have the same format, 96762306a36Sopenharmony_ci * as we do not support mixing and matching of cameras connected to the 96862306a36Sopenharmony_ci * max9286. 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_ci if (pad == MAX9286_SRC_PAD) 97162306a36Sopenharmony_ci pad = __ffs(priv->bound_sources); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which); 97462306a36Sopenharmony_ci if (!cfg_fmt) 97562306a36Sopenharmony_ci return -EINVAL; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci mutex_lock(&priv->mutex); 97862306a36Sopenharmony_ci format->format = *cfg_fmt; 97962306a36Sopenharmony_ci mutex_unlock(&priv->mutex); 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return 0; 98262306a36Sopenharmony_ci} 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_cistatic const struct v4l2_subdev_video_ops max9286_video_ops = { 98562306a36Sopenharmony_ci .s_stream = max9286_s_stream, 98662306a36Sopenharmony_ci .g_frame_interval = max9286_g_frame_interval, 98762306a36Sopenharmony_ci .s_frame_interval = max9286_s_frame_interval, 98862306a36Sopenharmony_ci}; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic const struct v4l2_subdev_pad_ops max9286_pad_ops = { 99162306a36Sopenharmony_ci .enum_mbus_code = max9286_enum_mbus_code, 99262306a36Sopenharmony_ci .get_fmt = max9286_get_fmt, 99362306a36Sopenharmony_ci .set_fmt = max9286_set_fmt, 99462306a36Sopenharmony_ci}; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_cistatic const struct v4l2_subdev_ops max9286_subdev_ops = { 99762306a36Sopenharmony_ci .video = &max9286_video_ops, 99862306a36Sopenharmony_ci .pad = &max9286_pad_ops, 99962306a36Sopenharmony_ci}; 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_cistatic const struct v4l2_mbus_framefmt max9286_default_format = { 100262306a36Sopenharmony_ci .width = 1280, 100362306a36Sopenharmony_ci .height = 800, 100462306a36Sopenharmony_ci .code = MEDIA_BUS_FMT_UYVY8_1X16, 100562306a36Sopenharmony_ci .colorspace = V4L2_COLORSPACE_SRGB, 100662306a36Sopenharmony_ci .field = V4L2_FIELD_NONE, 100762306a36Sopenharmony_ci .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, 100862306a36Sopenharmony_ci .quantization = V4L2_QUANTIZATION_DEFAULT, 100962306a36Sopenharmony_ci .xfer_func = V4L2_XFER_FUNC_DEFAULT, 101062306a36Sopenharmony_ci}; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_cistatic void max9286_init_format(struct v4l2_mbus_framefmt *fmt) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci *fmt = max9286_default_format; 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct v4l2_mbus_framefmt *format; 102062306a36Sopenharmony_ci unsigned int i; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci for (i = 0; i < MAX9286_N_SINKS; i++) { 102362306a36Sopenharmony_ci format = v4l2_subdev_get_try_format(subdev, fh->state, i); 102462306a36Sopenharmony_ci max9286_init_format(format); 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci return 0; 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = { 103162306a36Sopenharmony_ci .open = max9286_open, 103262306a36Sopenharmony_ci}; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_cistatic const struct media_entity_operations max9286_media_ops = { 103562306a36Sopenharmony_ci .link_validate = v4l2_subdev_link_validate 103662306a36Sopenharmony_ci}; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_cistatic int max9286_s_ctrl(struct v4l2_ctrl *ctrl) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci switch (ctrl->id) { 104162306a36Sopenharmony_ci case V4L2_CID_PIXEL_RATE: 104262306a36Sopenharmony_ci return 0; 104362306a36Sopenharmony_ci default: 104462306a36Sopenharmony_ci return -EINVAL; 104562306a36Sopenharmony_ci } 104662306a36Sopenharmony_ci} 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cistatic const struct v4l2_ctrl_ops max9286_ctrl_ops = { 104962306a36Sopenharmony_ci .s_ctrl = max9286_s_ctrl, 105062306a36Sopenharmony_ci}; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic int max9286_v4l2_register(struct max9286_priv *priv) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 105562306a36Sopenharmony_ci int ret; 105662306a36Sopenharmony_ci int i; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci /* Register v4l2 async notifiers for connected Camera subdevices */ 105962306a36Sopenharmony_ci ret = max9286_v4l2_notifier_register(priv); 106062306a36Sopenharmony_ci if (ret) { 106162306a36Sopenharmony_ci dev_err(dev, "Unable to register V4L2 async notifiers\n"); 106262306a36Sopenharmony_ci return ret; 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci /* Configure V4L2 for the MAX9286 itself */ 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci for (i = 0; i < MAX9286_N_SINKS; i++) 106862306a36Sopenharmony_ci max9286_init_format(&priv->fmt[i]); 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); 107162306a36Sopenharmony_ci priv->sd.internal_ops = &max9286_subdev_internal_ops; 107262306a36Sopenharmony_ci priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci v4l2_ctrl_handler_init(&priv->ctrls, 1); 107562306a36Sopenharmony_ci priv->pixelrate_ctrl = v4l2_ctrl_new_std(&priv->ctrls, 107662306a36Sopenharmony_ci &max9286_ctrl_ops, 107762306a36Sopenharmony_ci V4L2_CID_PIXEL_RATE, 107862306a36Sopenharmony_ci 1, INT_MAX, 1, 50000000); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci priv->sd.ctrl_handler = &priv->ctrls; 108162306a36Sopenharmony_ci ret = priv->ctrls.error; 108262306a36Sopenharmony_ci if (ret) 108362306a36Sopenharmony_ci goto err_async; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 108662306a36Sopenharmony_ci priv->sd.entity.ops = &max9286_media_ops; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci priv->pads[MAX9286_SRC_PAD].flags = MEDIA_PAD_FL_SOURCE; 108962306a36Sopenharmony_ci for (i = 0; i < MAX9286_SRC_PAD; i++) 109062306a36Sopenharmony_ci priv->pads[i].flags = MEDIA_PAD_FL_SINK; 109162306a36Sopenharmony_ci ret = media_entity_pads_init(&priv->sd.entity, MAX9286_N_PADS, 109262306a36Sopenharmony_ci priv->pads); 109362306a36Sopenharmony_ci if (ret) 109462306a36Sopenharmony_ci goto err_async; 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci ret = v4l2_async_register_subdev(&priv->sd); 109762306a36Sopenharmony_ci if (ret < 0) { 109862306a36Sopenharmony_ci dev_err(dev, "Unable to register subdevice\n"); 109962306a36Sopenharmony_ci goto err_async; 110062306a36Sopenharmony_ci } 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cierr_async: 110562306a36Sopenharmony_ci v4l2_ctrl_handler_free(&priv->ctrls); 110662306a36Sopenharmony_ci max9286_v4l2_notifier_unregister(priv); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci return ret; 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_cistatic void max9286_v4l2_unregister(struct max9286_priv *priv) 111262306a36Sopenharmony_ci{ 111362306a36Sopenharmony_ci v4l2_ctrl_handler_free(&priv->ctrls); 111462306a36Sopenharmony_ci v4l2_async_unregister_subdev(&priv->sd); 111562306a36Sopenharmony_ci max9286_v4l2_notifier_unregister(priv); 111662306a36Sopenharmony_ci} 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci/* ----------------------------------------------------------------------------- 111962306a36Sopenharmony_ci * Probe/Remove 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int max9286_setup(struct max9286_priv *priv) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci /* 112562306a36Sopenharmony_ci * Link ordering values for all enabled links combinations. Orders must 112662306a36Sopenharmony_ci * be assigned sequentially from 0 to the number of enabled links 112762306a36Sopenharmony_ci * without leaving any hole for disabled links. We thus assign orders to 112862306a36Sopenharmony_ci * enabled links first, and use the remaining order values for disabled 112962306a36Sopenharmony_ci * links are all links must have a different order value; 113062306a36Sopenharmony_ci */ 113162306a36Sopenharmony_ci static const u8 link_order[] = { 113262306a36Sopenharmony_ci (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxxx */ 113362306a36Sopenharmony_ci (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xxx0 */ 113462306a36Sopenharmony_ci (3 << 6) | (2 << 4) | (0 << 2) | (1 << 0), /* xx0x */ 113562306a36Sopenharmony_ci (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* xx10 */ 113662306a36Sopenharmony_ci (3 << 6) | (0 << 4) | (2 << 2) | (1 << 0), /* x0xx */ 113762306a36Sopenharmony_ci (3 << 6) | (1 << 4) | (2 << 2) | (0 << 0), /* x1x0 */ 113862306a36Sopenharmony_ci (3 << 6) | (1 << 4) | (0 << 2) | (2 << 0), /* x10x */ 113962306a36Sopenharmony_ci (3 << 6) | (1 << 4) | (1 << 2) | (0 << 0), /* x210 */ 114062306a36Sopenharmony_ci (0 << 6) | (3 << 4) | (2 << 2) | (1 << 0), /* 0xxx */ 114162306a36Sopenharmony_ci (1 << 6) | (3 << 4) | (2 << 2) | (0 << 0), /* 1xx0 */ 114262306a36Sopenharmony_ci (1 << 6) | (3 << 4) | (0 << 2) | (2 << 0), /* 1x0x */ 114362306a36Sopenharmony_ci (2 << 6) | (3 << 4) | (1 << 2) | (0 << 0), /* 2x10 */ 114462306a36Sopenharmony_ci (1 << 6) | (0 << 4) | (3 << 2) | (2 << 0), /* 10xx */ 114562306a36Sopenharmony_ci (2 << 6) | (1 << 4) | (3 << 2) | (0 << 0), /* 21x0 */ 114662306a36Sopenharmony_ci (2 << 6) | (1 << 4) | (0 << 2) | (3 << 0), /* 210x */ 114762306a36Sopenharmony_ci (3 << 6) | (2 << 4) | (1 << 2) | (0 << 0), /* 3210 */ 114862306a36Sopenharmony_ci }; 114962306a36Sopenharmony_ci int cfg; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* 115262306a36Sopenharmony_ci * Set the I2C bus speed. 115362306a36Sopenharmony_ci * 115462306a36Sopenharmony_ci * Enable I2C Local Acknowledge during the probe sequences of the camera 115562306a36Sopenharmony_ci * only. This should be disabled after the mux is initialised. 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci max9286_configure_i2c(priv, true); 115862306a36Sopenharmony_ci max9286_reverse_channel_setup(priv, priv->init_rev_chan_mv); 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci /* 116162306a36Sopenharmony_ci * Enable GMSL links, mask unused ones and autodetect link 116262306a36Sopenharmony_ci * used as CSI clock source. 116362306a36Sopenharmony_ci */ 116462306a36Sopenharmony_ci max9286_write(priv, 0x00, MAX9286_MSTLINKSEL_AUTO | priv->route_mask); 116562306a36Sopenharmony_ci max9286_write(priv, 0x0b, link_order[priv->route_mask]); 116662306a36Sopenharmony_ci max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci max9286_set_video_format(priv, &max9286_default_format); 116962306a36Sopenharmony_ci max9286_set_fsync_period(priv); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci cfg = max9286_read(priv, 0x1c); 117262306a36Sopenharmony_ci if (cfg < 0) 117362306a36Sopenharmony_ci return cfg; 117462306a36Sopenharmony_ci 117562306a36Sopenharmony_ci dev_dbg(&priv->client->dev, "power-up config: %s immunity, %u-bit bus\n", 117662306a36Sopenharmony_ci cfg & MAX9286_HIGHIMM(0) ? "high" : "legacy", 117762306a36Sopenharmony_ci cfg & MAX9286_BWS ? 32 : cfg & MAX9286_HIBW ? 27 : 24); 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci if (priv->bus_width) { 118062306a36Sopenharmony_ci cfg &= ~(MAX9286_HIBW | MAX9286_BWS); 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci if (priv->bus_width == 27) 118362306a36Sopenharmony_ci cfg |= MAX9286_HIBW; 118462306a36Sopenharmony_ci else if (priv->bus_width == 32) 118562306a36Sopenharmony_ci cfg |= MAX9286_BWS; 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci max9286_write(priv, 0x1c, cfg); 118862306a36Sopenharmony_ci } 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* 119162306a36Sopenharmony_ci * The overlap window seems to provide additional validation by tracking 119262306a36Sopenharmony_ci * the delay between vsync and frame sync, generating an error if the 119362306a36Sopenharmony_ci * delay is bigger than the programmed window, though it's not yet clear 119462306a36Sopenharmony_ci * what value should be set. 119562306a36Sopenharmony_ci * 119662306a36Sopenharmony_ci * As it's an optional value and can be disabled, we do so by setting 119762306a36Sopenharmony_ci * a 0 overlap value. 119862306a36Sopenharmony_ci */ 119962306a36Sopenharmony_ci max9286_write(priv, 0x63, 0); 120062306a36Sopenharmony_ci max9286_write(priv, 0x64, 0); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* 120362306a36Sopenharmony_ci * Wait for 2ms to allow the link to resynchronize after the 120462306a36Sopenharmony_ci * configuration change. 120562306a36Sopenharmony_ci */ 120662306a36Sopenharmony_ci usleep_range(2000, 5000); 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ci return 0; 120962306a36Sopenharmony_ci} 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_cistatic int max9286_gpio_set(struct max9286_priv *priv, unsigned int offset, 121262306a36Sopenharmony_ci int value) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci if (value) 121562306a36Sopenharmony_ci priv->gpio_state |= BIT(offset); 121662306a36Sopenharmony_ci else 121762306a36Sopenharmony_ci priv->gpio_state &= ~BIT(offset); 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci return max9286_write(priv, 0x0f, 122062306a36Sopenharmony_ci MAX9286_0X0F_RESERVED | priv->gpio_state); 122162306a36Sopenharmony_ci} 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_cistatic void max9286_gpiochip_set(struct gpio_chip *chip, 122462306a36Sopenharmony_ci unsigned int offset, int value) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct max9286_priv *priv = gpiochip_get_data(chip); 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci max9286_gpio_set(priv, offset, value); 122962306a36Sopenharmony_ci} 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_cistatic int max9286_gpiochip_get(struct gpio_chip *chip, unsigned int offset) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct max9286_priv *priv = gpiochip_get_data(chip); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return priv->gpio_state & BIT(offset); 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic int max9286_register_gpio(struct max9286_priv *priv) 123962306a36Sopenharmony_ci{ 124062306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 124162306a36Sopenharmony_ci struct gpio_chip *gpio = &priv->gpio; 124262306a36Sopenharmony_ci int ret; 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* Configure the GPIO */ 124562306a36Sopenharmony_ci gpio->label = dev_name(dev); 124662306a36Sopenharmony_ci gpio->parent = dev; 124762306a36Sopenharmony_ci gpio->owner = THIS_MODULE; 124862306a36Sopenharmony_ci gpio->ngpio = 2; 124962306a36Sopenharmony_ci gpio->base = -1; 125062306a36Sopenharmony_ci gpio->set = max9286_gpiochip_set; 125162306a36Sopenharmony_ci gpio->get = max9286_gpiochip_get; 125262306a36Sopenharmony_ci gpio->can_sleep = true; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, gpio, priv); 125562306a36Sopenharmony_ci if (ret) 125662306a36Sopenharmony_ci dev_err(dev, "Unable to create gpio_chip\n"); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci return ret; 125962306a36Sopenharmony_ci} 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_cistatic int max9286_parse_gpios(struct max9286_priv *priv) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 126462306a36Sopenharmony_ci int ret; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci /* 126762306a36Sopenharmony_ci * Parse the "gpio-poc" vendor property. If the property is not 126862306a36Sopenharmony_ci * specified the camera power is controlled by a regulator. 126962306a36Sopenharmony_ci */ 127062306a36Sopenharmony_ci ret = of_property_read_u32_array(dev->of_node, "maxim,gpio-poc", 127162306a36Sopenharmony_ci priv->gpio_poc, 2); 127262306a36Sopenharmony_ci if (ret == -EINVAL) { 127362306a36Sopenharmony_ci /* 127462306a36Sopenharmony_ci * If gpio lines are not used for the camera power, register 127562306a36Sopenharmony_ci * a gpio controller for consumers. 127662306a36Sopenharmony_ci */ 127762306a36Sopenharmony_ci return max9286_register_gpio(priv); 127862306a36Sopenharmony_ci } 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci /* If the property is specified make sure it is well formed. */ 128162306a36Sopenharmony_ci if (ret || priv->gpio_poc[0] > 1 || 128262306a36Sopenharmony_ci (priv->gpio_poc[1] != GPIO_ACTIVE_HIGH && 128362306a36Sopenharmony_ci priv->gpio_poc[1] != GPIO_ACTIVE_LOW)) { 128462306a36Sopenharmony_ci dev_err(dev, "Invalid 'gpio-poc' property\n"); 128562306a36Sopenharmony_ci return -EINVAL; 128662306a36Sopenharmony_ci } 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci priv->use_gpio_poc = true; 128962306a36Sopenharmony_ci return 0; 129062306a36Sopenharmony_ci} 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_cistatic int max9286_poc_power_on(struct max9286_priv *priv) 129362306a36Sopenharmony_ci{ 129462306a36Sopenharmony_ci struct max9286_source *source; 129562306a36Sopenharmony_ci unsigned int enabled = 0; 129662306a36Sopenharmony_ci int ret; 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci /* Enable the global regulator if available. */ 129962306a36Sopenharmony_ci if (priv->regulator) 130062306a36Sopenharmony_ci return regulator_enable(priv->regulator); 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci if (priv->use_gpio_poc) 130362306a36Sopenharmony_ci return max9286_gpio_set(priv, priv->gpio_poc[0], 130462306a36Sopenharmony_ci !priv->gpio_poc[1]); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci /* Otherwise use the per-port regulators. */ 130762306a36Sopenharmony_ci for_each_source(priv, source) { 130862306a36Sopenharmony_ci ret = regulator_enable(source->regulator); 130962306a36Sopenharmony_ci if (ret < 0) 131062306a36Sopenharmony_ci goto error; 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci enabled |= BIT(to_index(priv, source)); 131362306a36Sopenharmony_ci } 131462306a36Sopenharmony_ci 131562306a36Sopenharmony_ci return 0; 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_cierror: 131862306a36Sopenharmony_ci for_each_source(priv, source) { 131962306a36Sopenharmony_ci if (enabled & BIT(to_index(priv, source))) 132062306a36Sopenharmony_ci regulator_disable(source->regulator); 132162306a36Sopenharmony_ci } 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci return ret; 132462306a36Sopenharmony_ci} 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_cistatic int max9286_poc_power_off(struct max9286_priv *priv) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci struct max9286_source *source; 132962306a36Sopenharmony_ci int ret = 0; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci if (priv->regulator) 133262306a36Sopenharmony_ci return regulator_disable(priv->regulator); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci if (priv->use_gpio_poc) 133562306a36Sopenharmony_ci return max9286_gpio_set(priv, priv->gpio_poc[0], 133662306a36Sopenharmony_ci priv->gpio_poc[1]); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci for_each_source(priv, source) { 133962306a36Sopenharmony_ci int err; 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci err = regulator_disable(source->regulator); 134262306a36Sopenharmony_ci if (!ret) 134362306a36Sopenharmony_ci ret = err; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci return ret; 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic int max9286_poc_enable(struct max9286_priv *priv, bool enable) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci int ret; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci if (enable) 135462306a36Sopenharmony_ci ret = max9286_poc_power_on(priv); 135562306a36Sopenharmony_ci else 135662306a36Sopenharmony_ci ret = max9286_poc_power_off(priv); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci if (ret < 0) 135962306a36Sopenharmony_ci dev_err(&priv->client->dev, "Unable to turn power %s\n", 136062306a36Sopenharmony_ci enable ? "on" : "off"); 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci return ret; 136362306a36Sopenharmony_ci} 136462306a36Sopenharmony_ci 136562306a36Sopenharmony_cistatic int max9286_init(struct max9286_priv *priv) 136662306a36Sopenharmony_ci{ 136762306a36Sopenharmony_ci struct i2c_client *client = priv->client; 136862306a36Sopenharmony_ci int ret; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci ret = max9286_poc_enable(priv, true); 137162306a36Sopenharmony_ci if (ret) 137262306a36Sopenharmony_ci return ret; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci ret = max9286_setup(priv); 137562306a36Sopenharmony_ci if (ret) { 137662306a36Sopenharmony_ci dev_err(&client->dev, "Unable to setup max9286\n"); 137762306a36Sopenharmony_ci goto err_poc_disable; 137862306a36Sopenharmony_ci } 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci /* 138162306a36Sopenharmony_ci * Register all V4L2 interactions for the MAX9286 and notifiers for 138262306a36Sopenharmony_ci * any subdevices connected. 138362306a36Sopenharmony_ci */ 138462306a36Sopenharmony_ci ret = max9286_v4l2_register(priv); 138562306a36Sopenharmony_ci if (ret) { 138662306a36Sopenharmony_ci dev_err(&client->dev, "Failed to register with V4L2\n"); 138762306a36Sopenharmony_ci goto err_poc_disable; 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci ret = max9286_i2c_mux_init(priv); 139162306a36Sopenharmony_ci if (ret) { 139262306a36Sopenharmony_ci dev_err(&client->dev, "Unable to initialize I2C multiplexer\n"); 139362306a36Sopenharmony_ci goto err_v4l2_register; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci /* Leave the mux channels disabled until they are selected. */ 139762306a36Sopenharmony_ci max9286_i2c_mux_close(priv); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_cierr_v4l2_register: 140262306a36Sopenharmony_ci max9286_v4l2_unregister(priv); 140362306a36Sopenharmony_cierr_poc_disable: 140462306a36Sopenharmony_ci max9286_poc_enable(priv, false); 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci return ret; 140762306a36Sopenharmony_ci} 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_cistatic void max9286_cleanup_dt(struct max9286_priv *priv) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct max9286_source *source; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci for_each_source(priv, source) { 141462306a36Sopenharmony_ci fwnode_handle_put(source->fwnode); 141562306a36Sopenharmony_ci source->fwnode = NULL; 141662306a36Sopenharmony_ci } 141762306a36Sopenharmony_ci} 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_cistatic int max9286_parse_dt(struct max9286_priv *priv) 142062306a36Sopenharmony_ci{ 142162306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 142262306a36Sopenharmony_ci struct device_node *i2c_mux; 142362306a36Sopenharmony_ci struct device_node *node = NULL; 142462306a36Sopenharmony_ci unsigned int i2c_mux_mask = 0; 142562306a36Sopenharmony_ci u32 reverse_channel_microvolt; 142662306a36Sopenharmony_ci u32 i2c_clk_freq = 105000; 142762306a36Sopenharmony_ci unsigned int i; 142862306a36Sopenharmony_ci 142962306a36Sopenharmony_ci /* Balance the of_node_put() performed by of_find_node_by_name(). */ 143062306a36Sopenharmony_ci of_node_get(dev->of_node); 143162306a36Sopenharmony_ci i2c_mux = of_find_node_by_name(dev->of_node, "i2c-mux"); 143262306a36Sopenharmony_ci if (!i2c_mux) { 143362306a36Sopenharmony_ci dev_err(dev, "Failed to find i2c-mux node\n"); 143462306a36Sopenharmony_ci return -EINVAL; 143562306a36Sopenharmony_ci } 143662306a36Sopenharmony_ci 143762306a36Sopenharmony_ci /* Identify which i2c-mux channels are enabled */ 143862306a36Sopenharmony_ci for_each_child_of_node(i2c_mux, node) { 143962306a36Sopenharmony_ci u32 id = 0; 144062306a36Sopenharmony_ci 144162306a36Sopenharmony_ci of_property_read_u32(node, "reg", &id); 144262306a36Sopenharmony_ci if (id >= MAX9286_NUM_GMSL) 144362306a36Sopenharmony_ci continue; 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci if (!of_device_is_available(node)) { 144662306a36Sopenharmony_ci dev_dbg(dev, "Skipping disabled I2C bus port %u\n", id); 144762306a36Sopenharmony_ci continue; 144862306a36Sopenharmony_ci } 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci i2c_mux_mask |= BIT(id); 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci of_node_put(i2c_mux); 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci /* Parse the endpoints */ 145562306a36Sopenharmony_ci for_each_endpoint_of_node(dev->of_node, node) { 145662306a36Sopenharmony_ci struct max9286_source *source; 145762306a36Sopenharmony_ci struct of_endpoint ep; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci of_graph_parse_endpoint(node, &ep); 146062306a36Sopenharmony_ci dev_dbg(dev, "Endpoint %pOF on port %d", 146162306a36Sopenharmony_ci ep.local_node, ep.port); 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci if (ep.port > MAX9286_NUM_GMSL) { 146462306a36Sopenharmony_ci dev_err(dev, "Invalid endpoint %s on port %d", 146562306a36Sopenharmony_ci of_node_full_name(ep.local_node), ep.port); 146662306a36Sopenharmony_ci continue; 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci /* For the source endpoint just parse the bus configuration. */ 147062306a36Sopenharmony_ci if (ep.port == MAX9286_SRC_PAD) { 147162306a36Sopenharmony_ci struct v4l2_fwnode_endpoint vep = { 147262306a36Sopenharmony_ci .bus_type = V4L2_MBUS_CSI2_DPHY 147362306a36Sopenharmony_ci }; 147462306a36Sopenharmony_ci int ret; 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_ci ret = v4l2_fwnode_endpoint_parse( 147762306a36Sopenharmony_ci of_fwnode_handle(node), &vep); 147862306a36Sopenharmony_ci if (ret) { 147962306a36Sopenharmony_ci of_node_put(node); 148062306a36Sopenharmony_ci return ret; 148162306a36Sopenharmony_ci } 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci priv->csi2_data_lanes = 148462306a36Sopenharmony_ci vep.bus.mipi_csi2.num_data_lanes; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci continue; 148762306a36Sopenharmony_ci } 148862306a36Sopenharmony_ci 148962306a36Sopenharmony_ci /* Skip if the corresponding GMSL link is unavailable. */ 149062306a36Sopenharmony_ci if (!(i2c_mux_mask & BIT(ep.port))) 149162306a36Sopenharmony_ci continue; 149262306a36Sopenharmony_ci 149362306a36Sopenharmony_ci if (priv->sources[ep.port].fwnode) { 149462306a36Sopenharmony_ci dev_err(dev, 149562306a36Sopenharmony_ci "Multiple port endpoints are not supported: %d", 149662306a36Sopenharmony_ci ep.port); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci continue; 149962306a36Sopenharmony_ci } 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci source = &priv->sources[ep.port]; 150262306a36Sopenharmony_ci source->fwnode = fwnode_graph_get_remote_endpoint( 150362306a36Sopenharmony_ci of_fwnode_handle(node)); 150462306a36Sopenharmony_ci if (!source->fwnode) { 150562306a36Sopenharmony_ci dev_err(dev, 150662306a36Sopenharmony_ci "Endpoint %pOF has no remote endpoint connection\n", 150762306a36Sopenharmony_ci ep.local_node); 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci continue; 151062306a36Sopenharmony_ci } 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_ci priv->source_mask |= BIT(ep.port); 151362306a36Sopenharmony_ci priv->nsources++; 151462306a36Sopenharmony_ci } 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci of_property_read_u32(dev->of_node, "maxim,bus-width", &priv->bus_width); 151762306a36Sopenharmony_ci switch (priv->bus_width) { 151862306a36Sopenharmony_ci case 0: 151962306a36Sopenharmony_ci /* 152062306a36Sopenharmony_ci * The property isn't specified in the device tree, the driver 152162306a36Sopenharmony_ci * will keep the default value selected by the BWS pin. 152262306a36Sopenharmony_ci */ 152362306a36Sopenharmony_ci case 24: 152462306a36Sopenharmony_ci case 27: 152562306a36Sopenharmony_ci case 32: 152662306a36Sopenharmony_ci break; 152762306a36Sopenharmony_ci default: 152862306a36Sopenharmony_ci dev_err(dev, "Invalid %s value %u\n", "maxim,bus-width", 152962306a36Sopenharmony_ci priv->bus_width); 153062306a36Sopenharmony_ci return -EINVAL; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci 153362306a36Sopenharmony_ci of_property_read_u32(dev->of_node, "maxim,i2c-remote-bus-hz", 153462306a36Sopenharmony_ci &i2c_clk_freq); 153562306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(max9286_i2c_speeds); ++i) { 153662306a36Sopenharmony_ci const struct max9286_i2c_speed *speed = &max9286_i2c_speeds[i]; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci if (speed->rate == i2c_clk_freq) { 153962306a36Sopenharmony_ci priv->i2c_mstbt = speed->mstbt; 154062306a36Sopenharmony_ci break; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci } 154362306a36Sopenharmony_ci 154462306a36Sopenharmony_ci if (i == ARRAY_SIZE(max9286_i2c_speeds)) { 154562306a36Sopenharmony_ci dev_err(dev, "Invalid %s value %u\n", "maxim,i2c-remote-bus-hz", 154662306a36Sopenharmony_ci i2c_clk_freq); 154762306a36Sopenharmony_ci return -EINVAL; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci /* 155162306a36Sopenharmony_ci * Parse the initial value of the reverse channel amplitude from 155262306a36Sopenharmony_ci * the firmware interface and convert it to millivolts. 155362306a36Sopenharmony_ci * 155462306a36Sopenharmony_ci * Default it to 170mV for backward compatibility with DTBs that do not 155562306a36Sopenharmony_ci * provide the property. 155662306a36Sopenharmony_ci */ 155762306a36Sopenharmony_ci if (of_property_read_u32(dev->of_node, 155862306a36Sopenharmony_ci "maxim,reverse-channel-microvolt", 155962306a36Sopenharmony_ci &reverse_channel_microvolt)) 156062306a36Sopenharmony_ci priv->init_rev_chan_mv = 170; 156162306a36Sopenharmony_ci else 156262306a36Sopenharmony_ci priv->init_rev_chan_mv = reverse_channel_microvolt / 1000U; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_ci priv->route_mask = priv->source_mask; 156562306a36Sopenharmony_ci 156662306a36Sopenharmony_ci return 0; 156762306a36Sopenharmony_ci} 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_cistatic int max9286_get_poc_supplies(struct max9286_priv *priv) 157062306a36Sopenharmony_ci{ 157162306a36Sopenharmony_ci struct device *dev = &priv->client->dev; 157262306a36Sopenharmony_ci struct max9286_source *source; 157362306a36Sopenharmony_ci int ret; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci /* Start by getting the global regulator. */ 157662306a36Sopenharmony_ci priv->regulator = devm_regulator_get_optional(dev, "poc"); 157762306a36Sopenharmony_ci if (!IS_ERR(priv->regulator)) 157862306a36Sopenharmony_ci return 0; 157962306a36Sopenharmony_ci 158062306a36Sopenharmony_ci if (PTR_ERR(priv->regulator) != -ENODEV) 158162306a36Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->regulator), 158262306a36Sopenharmony_ci "Unable to get PoC regulator\n"); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci /* If there's no global regulator, get per-port regulators. */ 158562306a36Sopenharmony_ci dev_dbg(dev, 158662306a36Sopenharmony_ci "No global PoC regulator, looking for per-port regulators\n"); 158762306a36Sopenharmony_ci priv->regulator = NULL; 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci for_each_source(priv, source) { 159062306a36Sopenharmony_ci unsigned int index = to_index(priv, source); 159162306a36Sopenharmony_ci char name[10]; 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci snprintf(name, sizeof(name), "port%u-poc", index); 159462306a36Sopenharmony_ci source->regulator = devm_regulator_get(dev, name); 159562306a36Sopenharmony_ci if (IS_ERR(source->regulator)) { 159662306a36Sopenharmony_ci ret = PTR_ERR(source->regulator); 159762306a36Sopenharmony_ci dev_err_probe(dev, ret, 159862306a36Sopenharmony_ci "Unable to get port %u PoC regulator\n", 159962306a36Sopenharmony_ci index); 160062306a36Sopenharmony_ci return ret; 160162306a36Sopenharmony_ci } 160262306a36Sopenharmony_ci } 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci return 0; 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_cistatic int max9286_probe(struct i2c_client *client) 160862306a36Sopenharmony_ci{ 160962306a36Sopenharmony_ci struct max9286_priv *priv; 161062306a36Sopenharmony_ci int ret; 161162306a36Sopenharmony_ci 161262306a36Sopenharmony_ci priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 161362306a36Sopenharmony_ci if (!priv) 161462306a36Sopenharmony_ci return -ENOMEM; 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci mutex_init(&priv->mutex); 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci priv->client = client; 161962306a36Sopenharmony_ci 162062306a36Sopenharmony_ci /* GPIO values default to high */ 162162306a36Sopenharmony_ci priv->gpio_state = BIT(0) | BIT(1); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci ret = max9286_parse_dt(priv); 162462306a36Sopenharmony_ci if (ret) 162562306a36Sopenharmony_ci goto err_cleanup_dt; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", 162862306a36Sopenharmony_ci GPIOD_OUT_HIGH); 162962306a36Sopenharmony_ci if (IS_ERR(priv->gpiod_pwdn)) { 163062306a36Sopenharmony_ci ret = PTR_ERR(priv->gpiod_pwdn); 163162306a36Sopenharmony_ci goto err_cleanup_dt; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci 163462306a36Sopenharmony_ci gpiod_set_consumer_name(priv->gpiod_pwdn, "max9286-pwdn"); 163562306a36Sopenharmony_ci gpiod_set_value_cansleep(priv->gpiod_pwdn, 1); 163662306a36Sopenharmony_ci 163762306a36Sopenharmony_ci /* Wait at least 4ms before the I2C lines latch to the address */ 163862306a36Sopenharmony_ci if (priv->gpiod_pwdn) 163962306a36Sopenharmony_ci usleep_range(4000, 5000); 164062306a36Sopenharmony_ci 164162306a36Sopenharmony_ci /* 164262306a36Sopenharmony_ci * The MAX9286 starts by default with all ports enabled, we disable all 164362306a36Sopenharmony_ci * ports early to ensure that all channels are disabled if we error out 164462306a36Sopenharmony_ci * and keep the bus consistent. 164562306a36Sopenharmony_ci */ 164662306a36Sopenharmony_ci max9286_i2c_mux_close(priv); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* 164962306a36Sopenharmony_ci * The MAX9286 initialises with auto-acknowledge enabled by default. 165062306a36Sopenharmony_ci * This can be invasive to other transactions on the same bus, so 165162306a36Sopenharmony_ci * disable it early. It will be enabled only as and when needed. 165262306a36Sopenharmony_ci */ 165362306a36Sopenharmony_ci max9286_configure_i2c(priv, false); 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_ci ret = max9286_parse_gpios(priv); 165662306a36Sopenharmony_ci if (ret) 165762306a36Sopenharmony_ci goto err_powerdown; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci if (!priv->use_gpio_poc) { 166062306a36Sopenharmony_ci ret = max9286_get_poc_supplies(priv); 166162306a36Sopenharmony_ci if (ret) 166262306a36Sopenharmony_ci goto err_cleanup_dt; 166362306a36Sopenharmony_ci } 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_ci ret = max9286_init(priv); 166662306a36Sopenharmony_ci if (ret < 0) 166762306a36Sopenharmony_ci goto err_cleanup_dt; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci return 0; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cierr_powerdown: 167262306a36Sopenharmony_ci gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); 167362306a36Sopenharmony_cierr_cleanup_dt: 167462306a36Sopenharmony_ci max9286_cleanup_dt(priv); 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci return ret; 167762306a36Sopenharmony_ci} 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cistatic void max9286_remove(struct i2c_client *client) 168062306a36Sopenharmony_ci{ 168162306a36Sopenharmony_ci struct max9286_priv *priv = sd_to_max9286(i2c_get_clientdata(client)); 168262306a36Sopenharmony_ci 168362306a36Sopenharmony_ci i2c_mux_del_adapters(priv->mux); 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci max9286_v4l2_unregister(priv); 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci max9286_poc_enable(priv, false); 168862306a36Sopenharmony_ci 168962306a36Sopenharmony_ci gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci max9286_cleanup_dt(priv); 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic const struct of_device_id max9286_dt_ids[] = { 169562306a36Sopenharmony_ci { .compatible = "maxim,max9286" }, 169662306a36Sopenharmony_ci {}, 169762306a36Sopenharmony_ci}; 169862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, max9286_dt_ids); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_cistatic struct i2c_driver max9286_i2c_driver = { 170162306a36Sopenharmony_ci .driver = { 170262306a36Sopenharmony_ci .name = "max9286", 170362306a36Sopenharmony_ci .of_match_table = max9286_dt_ids, 170462306a36Sopenharmony_ci }, 170562306a36Sopenharmony_ci .probe = max9286_probe, 170662306a36Sopenharmony_ci .remove = max9286_remove, 170762306a36Sopenharmony_ci}; 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_cimodule_i2c_driver(max9286_i2c_driver); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ciMODULE_DESCRIPTION("Maxim MAX9286 GMSL Deserializer Driver"); 171262306a36Sopenharmony_ciMODULE_AUTHOR("Jacopo Mondi, Kieran Bingham, Laurent Pinchart, Niklas Söderlund, Vladimir Barinov"); 171362306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1714