/* * max9295.c - max9295 GMSL Serializer driver * * Copyright (c) 2018-2020, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include /* register specifics */ #define MAX9295_MIPI_RX0_ADDR 0x330 #define MAX9295_MIPI_RX1_ADDR 0x331 #define MAX9295_MIPI_RX2_ADDR 0x332 #define MAX9295_MIPI_RX3_ADDR 0x333 #define MAX9295_PIPE_X_DT_ADDR 0x314 #define MAX9295_PIPE_Y_DT_ADDR 0x316 #define MAX9295_PIPE_Z_DT_ADDR 0x318 #define MAX9295_PIPE_U_DT_ADDR 0x31A #define MAX9295_CTRL0_ADDR 0x10 #define MAX9295_SRC_CTRL_ADDR 0x2BF #define MAX9295_SRC_PWDN_ADDR 0x02BE #define MAX9295_SRC_OUT_RCLK_ADDR 0x3F1 #define MAX9295_START_PIPE_ADDR 0x311 #define MAX9295_PIPE_EN_ADDR 0x2 #define MAX9295_CSI_PORT_SEL_ADDR 0x308 #define MAX9295_I2C4_ADDR 0x44 #define MAX9295_I2C5_ADDR 0x45 #define MAX9295_DEV_ADDR 0x00 #define MAX9295_STREAM_PIPE_UNUSED 0x22 #define MAX9295_CSI_MODE_1X4 0x00 #define MAX9295_CSI_MODE_2X2 0x03 #define MAX9295_CSI_MODE_2X4 0x06 #define MAX9295_CSI_PORT_B(num_lanes) (((num_lanes) << 4) & 0xF0) #define MAX9295_CSI_PORT_A(num_lanes) ((num_lanes) & 0x0F) #define MAX9295_CSI_1X4_MODE_LANE_MAP1 0xE0 #define MAX9295_CSI_1X4_MODE_LANE_MAP2 0x04 #define MAX9295_CSI_2X4_MODE_LANE_MAP1 0xEE #define MAX9295_CSI_2X4_MODE_LANE_MAP2 0xE4 #define MAX9295_CSI_2X2_MODE_LANE_MAP1 MAX9295_CSI_2X4_MODE_LANE_MAP1 #define MAX9295_CSI_2X2_MODE_LANE_MAP2 MAX9295_CSI_2X4_MODE_LANE_MAP2 #define MAX9295_ST_ID_0 0x0 #define MAX9295_ST_ID_1 0x1 #define MAX9295_ST_ID_2 0x2 #define MAX9295_ST_ID_3 0x3 #define MAX9295_PIPE_X_START_B 0x80 #define MAX9295_PIPE_Y_START_B 0x40 #define MAX9295_PIPE_Z_START_B 0x20 #define MAX9295_PIPE_U_START_B 0x10 #define MAX9295_PIPE_X_START_A 0x1 #define MAX9295_PIPE_Y_START_A 0x2 #define MAX9295_PIPE_Z_START_A 0x4 #define MAX9295_PIPE_U_START_A 0x8 #define MAX9295_START_PORT_A 0x10 #define MAX9295_START_PORT_B 0x20 #define MAX9295_CSI_LN2 0x1 #define MAX9295_CSI_LN4 0x3 #define MAX9295_EN_LINE_INFO 0x40 #define MAX9295_VID_TX_EN_X 0x10 #define MAX9295_VID_TX_EN_Y 0x20 #define MAX9295_VID_TX_EN_Z 0x40 #define MAX9295_VID_TX_EN_U 0x80 #define MAX9295_VID_INIT 0x3 #define MAX9295_SRC_RCLK 0x89 #define MAX9295_RESET_ALL 0x80 #define MAX9295_RESET_SRC 0x60 #define MAX9295_PWDN_GPIO 0x90 #define MAX9295_MAX_PIPES 0x4 struct max9295_client_ctx { struct gmsl_link_ctx *g_ctx; bool st_done; }; struct max9295 { struct i2c_client *i2c_client; struct regmap *regmap; struct max9295_client_ctx g_client; struct mutex lock; /* primary serializer properties */ __u32 def_addr; __u32 pst2_ref; }; static struct max9295 *prim_priv__; struct map_ctx { u8 dt; u16 addr; u8 val; u8 st_id; }; static int max9295_write_reg(struct device *dev, u16 addr, u8 val) { struct max9295 *priv = dev_get_drvdata(dev); int err; err = regmap_write(priv->regmap, addr, val); if (err) dev_err(dev, "%s:i2c write failed, 0x%x = %x\n", __func__, addr, val); /* delay before next i2c command as required for SERDES link */ usleep_range(100, 110); return err; } int max9295_setup_streaming(struct device *dev) { struct max9295 *priv = dev_get_drvdata(dev); int err = 0; u32 csi_mode; u32 lane_map1; u32 lane_map2; u32 port; u32 rx1_lanes; u32 st_pipe; u32 pipe_en; u32 port_sel = 0; struct gmsl_link_ctx *g_ctx; u32 i; u32 j; u32 st_en; struct map_ctx map_pipe_dtype[] = { {GMSL_CSI_DT_RAW_12, MAX9295_PIPE_Z_DT_ADDR, 0x2C, MAX9295_ST_ID_2}, {GMSL_CSI_DT_UED_U1, MAX9295_PIPE_X_DT_ADDR, 0x30, MAX9295_ST_ID_0}, {GMSL_CSI_DT_EMBED, MAX9295_PIPE_Y_DT_ADDR, 0x12, MAX9295_ST_ID_1}, }; mutex_lock(&priv->lock); if (!priv->g_client.g_ctx) { dev_err(dev, "%s: no sdev client found\n", __func__); err = -EINVAL; goto error; } if (priv->g_client.st_done) { dev_dbg(dev, "%s: stream setup is already done\n", __func__); goto error; } g_ctx = priv->g_client.g_ctx; switch (g_ctx->csi_mode) { case GMSL_CSI_1X4_MODE: csi_mode = MAX9295_CSI_MODE_1X4; lane_map1 = MAX9295_CSI_1X4_MODE_LANE_MAP1; lane_map2 = MAX9295_CSI_1X4_MODE_LANE_MAP2; rx1_lanes = MAX9295_CSI_LN4; break; case GMSL_CSI_2X2_MODE: csi_mode = MAX9295_CSI_MODE_2X2; lane_map1 = MAX9295_CSI_2X2_MODE_LANE_MAP1; lane_map2 = MAX9295_CSI_2X2_MODE_LANE_MAP2; rx1_lanes = MAX9295_CSI_LN2; break; case GMSL_CSI_2X4_MODE: csi_mode = MAX9295_CSI_MODE_2X4; lane_map1 = MAX9295_CSI_2X4_MODE_LANE_MAP1; lane_map2 = MAX9295_CSI_2X4_MODE_LANE_MAP2; rx1_lanes = MAX9295_CSI_LN4; break; default: dev_err(dev, "%s: invalid csi mode\n", __func__); err = -EINVAL; goto error; } port = (g_ctx->src_csi_port == GMSL_CSI_PORT_B) ? MAX9295_CSI_PORT_B(rx1_lanes) : MAX9295_CSI_PORT_A(rx1_lanes); max9295_write_reg(dev, MAX9295_MIPI_RX0_ADDR, csi_mode); max9295_write_reg(dev, MAX9295_MIPI_RX1_ADDR, port); max9295_write_reg(dev, MAX9295_MIPI_RX2_ADDR, lane_map1); max9295_write_reg(dev, MAX9295_MIPI_RX3_ADDR, lane_map2); for (i = 0; i < g_ctx->num_streams; i++) { struct gmsl_stream *g_stream = &g_ctx->streams[i]; g_stream->st_id_sel = GMSL_ST_ID_UNUSED; for (j = 0; j < ARRAY_SIZE(map_pipe_dtype); j++) { if (map_pipe_dtype[j].dt == g_stream->st_data_type) { /* * TODO: * 1) Remove link specific overrides, depends * on #2. * 2) Add support for vc id based stream sel * overrides TX_SRC_SEL. would be useful in * using same mappings in all ser devs. */ if (g_ctx->serdes_csi_link == GMSL_SERDES_CSI_LINK_B) { map_pipe_dtype[j].addr += 2; map_pipe_dtype[j].st_id += 1; } g_stream->st_id_sel = map_pipe_dtype[j].st_id; st_en = (map_pipe_dtype[j].addr == MAX9295_PIPE_X_DT_ADDR) ? 0xC0 : 0x40; max9295_write_reg(dev, map_pipe_dtype[j].addr, (st_en | map_pipe_dtype[j].val)); } } } for (i = 0; i < g_ctx->num_streams; i++) if (g_ctx->streams[i].st_id_sel != GMSL_ST_ID_UNUSED) port_sel |= (1 << g_ctx->streams[i].st_id_sel); if (g_ctx->src_csi_port == GMSL_CSI_PORT_B) { st_pipe = (MAX9295_PIPE_X_START_B | MAX9295_PIPE_Y_START_B | MAX9295_PIPE_Z_START_B | MAX9295_PIPE_U_START_B); port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_B); } else { st_pipe = MAX9295_PIPE_X_START_A | MAX9295_PIPE_Y_START_A | MAX9295_PIPE_Z_START_A | MAX9295_PIPE_U_START_A; port_sel |= (MAX9295_EN_LINE_INFO | MAX9295_START_PORT_A); } pipe_en = (MAX9295_VID_TX_EN_X | MAX9295_VID_TX_EN_Y | MAX9295_VID_TX_EN_Z | MAX9295_VID_TX_EN_U | MAX9295_VID_INIT); max9295_write_reg(dev, MAX9295_START_PIPE_ADDR, st_pipe); max9295_write_reg(dev, MAX9295_CSI_PORT_SEL_ADDR, port_sel); max9295_write_reg(dev, MAX9295_PIPE_EN_ADDR, pipe_en); priv->g_client.st_done = true; error: mutex_unlock(&priv->lock); return err; } EXPORT_SYMBOL(max9295_setup_streaming); int max9295_setup_control(struct device *dev) { struct max9295 *priv = dev_get_drvdata(dev); int err = 0; struct gmsl_link_ctx *g_ctx; u32 offset1 = 0; u32 offset2 = 0; u32 i; u8 i2c_ovrd[] = { 0x6B, 0x10, 0x73, 0x11, 0x7B, 0x30, 0x83, 0x30, 0x93, 0x30, 0x9B, 0x30, 0xA3, 0x30, 0xAB, 0x30, 0x8B, 0x30, }; u8 addr_offset[] = { 0x80, 0x00, 0x00, 0x84, 0x00, 0x01, 0xC0, 0x02, 0x02, 0xC4, 0x02, 0x03, }; mutex_lock(&priv->lock); if (!priv->g_client.g_ctx) { dev_err(dev, "%s: no sensor dev client found\n", __func__); err = -EINVAL; goto error; } g_ctx = priv->g_client.g_ctx; if (prim_priv__) { /* update address reassingment */ max9295_write_reg(&prim_priv__->i2c_client->dev, MAX9295_DEV_ADDR, (g_ctx->ser_reg << 1)); } if (g_ctx->serdes_csi_link == GMSL_SERDES_CSI_LINK_A) err = max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x21); else err = max9295_write_reg(dev, MAX9295_CTRL0_ADDR, 0x22); /* check if serializer device exists */ if (err) { dev_err(dev, "%s: ERROR: ser device not found\n", __func__); goto error; } /* delay to settle link */ msleep(100); for (i = 0; i < ARRAY_SIZE(addr_offset); i += 3) { if ((g_ctx->ser_reg << 1) == addr_offset[i]) { offset1 = addr_offset[i+1]; offset2 = addr_offset[i+2]; break; } } if (i == ARRAY_SIZE(addr_offset)) { dev_err(dev, "%s: invalid ser slave address\n", __func__); err = -EINVAL; goto error; } for (i = 0; i < ARRAY_SIZE(i2c_ovrd); i += 2) { /* update address overrides */ i2c_ovrd[i+1] += (i < 4) ? offset1 : offset2; /* i2c passthrough2 must be configured once for all devices */ if ((i2c_ovrd[i] == 0x8B) && prim_priv__ && prim_priv__->pst2_ref) continue; max9295_write_reg(dev, i2c_ovrd[i], i2c_ovrd[i+1]); } /* dev addr pass-through2 ref */ if (prim_priv__) prim_priv__->pst2_ref++; max9295_write_reg(dev, MAX9295_I2C4_ADDR, (g_ctx->sdev_reg << 1)); max9295_write_reg(dev, MAX9295_I2C5_ADDR, (g_ctx->sdev_def << 1)); max9295_write_reg(dev, MAX9295_SRC_PWDN_ADDR, MAX9295_PWDN_GPIO); max9295_write_reg(dev, MAX9295_SRC_CTRL_ADDR, MAX9295_RESET_SRC); max9295_write_reg(dev, MAX9295_SRC_OUT_RCLK_ADDR, MAX9295_SRC_RCLK); g_ctx->serdev_found = true; error: mutex_unlock(&priv->lock); return err; } EXPORT_SYMBOL(max9295_setup_control); int max9295_reset_control(struct device *dev) { struct max9295 *priv = dev_get_drvdata(dev); int err = 0; mutex_lock(&priv->lock); if (!priv->g_client.g_ctx) { dev_err(dev, "%s: no sdev client found\n", __func__); err = -EINVAL; goto error; } priv->g_client.st_done = false; if (prim_priv__) { prim_priv__->pst2_ref--; max9295_write_reg(dev, MAX9295_DEV_ADDR, (prim_priv__->def_addr << 1)); max9295_write_reg(&prim_priv__->i2c_client->dev, MAX9295_CTRL0_ADDR, MAX9295_RESET_ALL); } error: mutex_unlock(&priv->lock); return err; } EXPORT_SYMBOL(max9295_reset_control); int max9295_sdev_pair(struct device *dev, struct gmsl_link_ctx *g_ctx) { struct max9295 *priv; int err = 0; if (!dev || !g_ctx || !g_ctx->s_dev) { dev_err(dev, "%s: invalid input params\n", __func__); return -EINVAL; } priv = dev_get_drvdata(dev); mutex_lock(&priv->lock); if (priv->g_client.g_ctx) { dev_err(dev, "%s: device already paired\n", __func__); err = -EINVAL; goto error; } priv->g_client.st_done = false; priv->g_client.g_ctx = g_ctx; error: mutex_unlock(&priv->lock); return 0; } EXPORT_SYMBOL(max9295_sdev_pair); int max9295_sdev_unpair(struct device *dev, struct device *s_dev) { struct max9295 *priv = NULL; int err = 0; if (!dev || !s_dev) { dev_err(dev, "%s: invalid input params\n", __func__); return -EINVAL; } priv = dev_get_drvdata(dev); mutex_lock(&priv->lock); if (!priv->g_client.g_ctx) { dev_err(dev, "%s: device is not paired\n", __func__); err = -ENOMEM; goto error; } if (priv->g_client.g_ctx->s_dev != s_dev) { dev_err(dev, "%s: invalid device\n", __func__); err = -EINVAL; goto error; } priv->g_client.g_ctx = NULL; priv->g_client.st_done = false; error: mutex_unlock(&priv->lock); return err; } EXPORT_SYMBOL(max9295_sdev_unpair); static struct regmap_config max9295_regmap_config = { .reg_bits = 16, .val_bits = 8, .cache_type = REGCACHE_RBTREE, }; static int max9295_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct max9295 *priv; int err = 0; struct device_node *node = client->dev.of_node; dev_info(&client->dev, "[MAX9295]: probing GMSL Serializer\n"); priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); priv->i2c_client = client; priv->regmap = devm_regmap_init_i2c(priv->i2c_client, &max9295_regmap_config); if (IS_ERR(priv->regmap)) { dev_err(&client->dev, "regmap init failed: %ld\n", PTR_ERR(priv->regmap)); return -ENODEV; } mutex_init(&priv->lock); if (of_get_property(node, "is-prim-ser", NULL)) { if (prim_priv__) { dev_err(&client->dev, "prim-ser already exists\n"); return -EEXIST; } err = of_property_read_u32(node, "reg", &priv->def_addr); if (err < 0) { dev_err(&client->dev, "reg not found\n"); return -EINVAL; } prim_priv__ = priv; } dev_set_drvdata(&client->dev, priv); /* dev communication gets validated when GMSL link setup is done */ dev_info(&client->dev, "%s: success\n", __func__); return err; } static int max9295_remove(struct i2c_client *client) { struct max9295 *priv; if (client != NULL) { priv = dev_get_drvdata(&client->dev); mutex_destroy(&priv->lock); i2c_unregister_device(client); client = NULL; } return 0; } static const struct i2c_device_id max9295_id[] = { { "max9295", 0 }, { }, }; const struct of_device_id max9295_of_match[] = { { .compatible = "nvidia,max9295", }, { }, }; MODULE_DEVICE_TABLE(of, max9295_of_match); MODULE_DEVICE_TABLE(i2c, max9295_id); static struct i2c_driver max9295_i2c_driver = { .driver = { .name = "max9295", .owner = THIS_MODULE, }, .probe = max9295_probe, .remove = max9295_remove, .id_table = max9295_id, }; static int __init max9295_init(void) { return i2c_add_driver(&max9295_i2c_driver); } static void __exit max9295_exit(void) { i2c_del_driver(&max9295_i2c_driver); } module_init(max9295_init); module_exit(max9295_exit); MODULE_DESCRIPTION("GMSL Serializer driver max9295"); MODULE_AUTHOR("Sudhir Vyas "); MODULE_LICENSE("GPL v2");