max96712.c (11011B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Maxim MAX9286 Quad GMSL2 Deserializer Driver 4 * 5 * Copyright (C) 2021 Renesas Electronics Corporation 6 * Copyright (C) 2021 Niklas Söderlund 7 */ 8 9#include <linux/delay.h> 10#include <linux/i2c.h> 11#include <linux/module.h> 12#include <linux/of_graph.h> 13#include <linux/regmap.h> 14 15#include <media/v4l2-ctrls.h> 16#include <media/v4l2-fwnode.h> 17#include <media/v4l2-subdev.h> 18 19#define MAX96712_ID 0x20 20 21#define MAX96712_DPLL_FREQ 1000 22 23enum max96712_pattern { 24 MAX96712_PATTERN_CHECKERBOARD = 0, 25 MAX96712_PATTERN_GRADIENT, 26}; 27 28struct max96712_priv { 29 struct i2c_client *client; 30 struct regmap *regmap; 31 struct gpio_desc *gpiod_pwdn; 32 33 struct v4l2_mbus_config_mipi_csi2 mipi; 34 35 struct v4l2_subdev sd; 36 struct v4l2_ctrl_handler ctrl_handler; 37 struct media_pad pads[1]; 38 39 enum max96712_pattern pattern; 40}; 41 42static int max96712_read(struct max96712_priv *priv, int reg) 43{ 44 int ret, val; 45 46 ret = regmap_read(priv->regmap, reg, &val); 47 if (ret) { 48 dev_err(&priv->client->dev, "read 0x%04x failed\n", reg); 49 return ret; 50 } 51 52 return val; 53} 54 55static int max96712_write(struct max96712_priv *priv, unsigned int reg, u8 val) 56{ 57 int ret; 58 59 ret = regmap_write(priv->regmap, reg, val); 60 if (ret) 61 dev_err(&priv->client->dev, "write 0x%04x failed\n", reg); 62 63 return ret; 64} 65 66static int max96712_update_bits(struct max96712_priv *priv, unsigned int reg, 67 u8 mask, u8 val) 68{ 69 int ret; 70 71 ret = regmap_update_bits(priv->regmap, reg, mask, val); 72 if (ret) 73 dev_err(&priv->client->dev, "update 0x%04x failed\n", reg); 74 75 return ret; 76} 77 78static int max96712_write_bulk(struct max96712_priv *priv, unsigned int reg, 79 const void *val, size_t val_count) 80{ 81 int ret; 82 83 ret = regmap_bulk_write(priv->regmap, reg, val, val_count); 84 if (ret) 85 dev_err(&priv->client->dev, "bulk write 0x%04x failed\n", reg); 86 87 return ret; 88} 89 90static int max96712_write_bulk_value(struct max96712_priv *priv, 91 unsigned int reg, unsigned int val, 92 size_t val_count) 93{ 94 unsigned int i; 95 u8 values[4]; 96 97 for (i = 1; i <= val_count; i++) 98 values[i - 1] = (val >> ((val_count - i) * 8)) & 0xff; 99 100 return max96712_write_bulk(priv, reg, &values, val_count); 101} 102 103static void max96712_reset(struct max96712_priv *priv) 104{ 105 max96712_update_bits(priv, 0x13, 0x40, 0x40); 106 msleep(20); 107} 108 109static void max96712_mipi_enable(struct max96712_priv *priv, bool enable) 110{ 111 if (enable) { 112 max96712_update_bits(priv, 0x40b, 0x02, 0x02); 113 max96712_update_bits(priv, 0x8a0, 0x80, 0x80); 114 } else { 115 max96712_update_bits(priv, 0x8a0, 0x80, 0x00); 116 max96712_update_bits(priv, 0x40b, 0x02, 0x00); 117 } 118} 119 120static void max96712_mipi_configure(struct max96712_priv *priv) 121{ 122 unsigned int i; 123 u8 phy5 = 0; 124 125 max96712_mipi_enable(priv, false); 126 127 /* Select 2x4 mode. */ 128 max96712_write(priv, 0x8a0, 0x04); 129 130 /* Configure a 4-lane DPHY using PHY0 and PHY1. */ 131 /* TODO: Add support for 2-lane and 1-lane configurations. */ 132 /* TODO: Add support CPHY mode. */ 133 max96712_write(priv, 0x94a, 0xc0); 134 135 /* Configure lane mapping for PHY0 and PHY1. */ 136 /* TODO: Add support for lane swapping. */ 137 max96712_write(priv, 0x8a3, 0xe4); 138 139 /* Configure lane polarity for PHY0 and PHY1. */ 140 for (i = 0; i < priv->mipi.num_data_lanes + 1; i++) 141 if (priv->mipi.lane_polarities[i]) 142 phy5 |= BIT(i == 0 ? 5 : i < 3 ? i - 1 : i); 143 max96712_write(priv, 0x8a5, phy5); 144 145 /* Set link frequency for PHY0 and PHY1. */ 146 max96712_update_bits(priv, 0x415, 0x3f, 147 ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5)); 148 max96712_update_bits(priv, 0x418, 0x3f, 149 ((MAX96712_DPLL_FREQ / 100) & 0x1f) | BIT(5)); 150 151 /* Enable PHY0 and PHY1 */ 152 max96712_update_bits(priv, 0x8a2, 0xf0, 0x30); 153} 154 155static void max96712_pattern_enable(struct max96712_priv *priv, bool enable) 156{ 157 const u32 h_active = 1920; 158 const u32 h_fp = 88; 159 const u32 h_sw = 44; 160 const u32 h_bp = 148; 161 const u32 h_tot = h_active + h_fp + h_sw + h_bp; 162 163 const u32 v_active = 1080; 164 const u32 v_fp = 4; 165 const u32 v_sw = 5; 166 const u32 v_bp = 36; 167 const u32 v_tot = v_active + v_fp + v_sw + v_bp; 168 169 if (!enable) { 170 max96712_write(priv, 0x1051, 0x00); 171 return; 172 } 173 174 /* PCLK 75MHz. */ 175 max96712_write(priv, 0x0009, 0x01); 176 177 /* Configure Video Timing Generator for 1920x1080 @ 30 fps. */ 178 max96712_write_bulk_value(priv, 0x1052, 0, 3); 179 max96712_write_bulk_value(priv, 0x1055, v_sw * h_tot, 3); 180 max96712_write_bulk_value(priv, 0x1058, 181 (v_active + v_fp + + v_bp) * h_tot, 3); 182 max96712_write_bulk_value(priv, 0x105b, 0, 3); 183 max96712_write_bulk_value(priv, 0x105e, h_sw, 2); 184 max96712_write_bulk_value(priv, 0x1060, h_active + h_fp + h_bp, 2); 185 max96712_write_bulk_value(priv, 0x1062, v_tot, 2); 186 max96712_write_bulk_value(priv, 0x1064, 187 h_tot * (v_sw + v_bp) + (h_sw + h_bp), 3); 188 max96712_write_bulk_value(priv, 0x1067, h_active, 2); 189 max96712_write_bulk_value(priv, 0x1069, h_fp + h_sw + h_bp, 2); 190 max96712_write_bulk_value(priv, 0x106b, v_active, 2); 191 192 /* Generate VS, HS and DE in free-running mode. */ 193 max96712_write(priv, 0x1050, 0xfb); 194 195 /* Configure Video Pattern Generator. */ 196 if (priv->pattern == MAX96712_PATTERN_CHECKERBOARD) { 197 /* Set checkerboard pattern size. */ 198 max96712_write(priv, 0x1074, 0x3c); 199 max96712_write(priv, 0x1075, 0x3c); 200 max96712_write(priv, 0x1076, 0x3c); 201 202 /* Set checkerboard pattern colors. */ 203 max96712_write_bulk_value(priv, 0x106e, 0xfecc00, 3); 204 max96712_write_bulk_value(priv, 0x1071, 0x006aa7, 3); 205 206 /* Generate checkerboard pattern. */ 207 max96712_write(priv, 0x1051, 0x10); 208 } else { 209 /* Set gradient increment. */ 210 max96712_write(priv, 0x106d, 0x10); 211 212 /* Generate gradient pattern. */ 213 max96712_write(priv, 0x1051, 0x20); 214 } 215} 216 217static int max96712_s_stream(struct v4l2_subdev *sd, int enable) 218{ 219 struct max96712_priv *priv = v4l2_get_subdevdata(sd); 220 221 if (enable) { 222 max96712_pattern_enable(priv, true); 223 max96712_mipi_enable(priv, true); 224 } else { 225 max96712_mipi_enable(priv, false); 226 max96712_pattern_enable(priv, false); 227 } 228 229 return 0; 230} 231 232static const struct v4l2_subdev_video_ops max96712_video_ops = { 233 .s_stream = max96712_s_stream, 234}; 235 236static int max96712_get_pad_format(struct v4l2_subdev *sd, 237 struct v4l2_subdev_state *sd_state, 238 struct v4l2_subdev_format *format) 239{ 240 format->format.width = 1920; 241 format->format.height = 1080; 242 format->format.code = MEDIA_BUS_FMT_RGB888_1X24; 243 format->format.field = V4L2_FIELD_NONE; 244 245 return 0; 246} 247 248static const struct v4l2_subdev_pad_ops max96712_pad_ops = { 249 .get_fmt = max96712_get_pad_format, 250 .set_fmt = max96712_get_pad_format, 251}; 252 253static const struct v4l2_subdev_ops max96712_subdev_ops = { 254 .video = &max96712_video_ops, 255 .pad = &max96712_pad_ops, 256}; 257 258static const char * const max96712_test_pattern[] = { 259 "Checkerboard", 260 "Gradient", 261}; 262 263static int max96712_s_ctrl(struct v4l2_ctrl *ctrl) 264{ 265 struct max96712_priv *priv = 266 container_of(ctrl->handler, struct max96712_priv, ctrl_handler); 267 268 switch (ctrl->id) { 269 case V4L2_CID_TEST_PATTERN: 270 priv->pattern = ctrl->val ? 271 MAX96712_PATTERN_GRADIENT : 272 MAX96712_PATTERN_CHECKERBOARD; 273 break; 274 } 275 return 0; 276} 277 278static const struct v4l2_ctrl_ops max96712_ctrl_ops = { 279 .s_ctrl = max96712_s_ctrl, 280}; 281 282static int max96712_v4l2_register(struct max96712_priv *priv) 283{ 284 long pixel_rate; 285 int ret; 286 287 v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96712_subdev_ops); 288 priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; 289 priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; 290 291 v4l2_ctrl_handler_init(&priv->ctrl_handler, 2); 292 293 /* 294 * TODO: Once V4L2_CID_LINK_FREQ is changed from a menu control to an 295 * INT64 control it should be used here instead of V4L2_CID_PIXEL_RATE. 296 */ 297 pixel_rate = MAX96712_DPLL_FREQ / priv->mipi.num_data_lanes * 1000000; 298 v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE, 299 pixel_rate, pixel_rate, 1, pixel_rate); 300 301 v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &max96712_ctrl_ops, 302 V4L2_CID_TEST_PATTERN, 303 ARRAY_SIZE(max96712_test_pattern) - 1, 304 0, 0, max96712_test_pattern); 305 306 priv->sd.ctrl_handler = &priv->ctrl_handler; 307 ret = priv->ctrl_handler.error; 308 if (ret) 309 goto error; 310 311 priv->pads[0].flags = MEDIA_PAD_FL_SOURCE; 312 ret = media_entity_pads_init(&priv->sd.entity, 1, priv->pads); 313 if (ret) 314 goto error; 315 316 v4l2_set_subdevdata(&priv->sd, priv); 317 318 ret = v4l2_async_register_subdev(&priv->sd); 319 if (ret < 0) { 320 dev_err(&priv->client->dev, "Unable to register subdevice\n"); 321 goto error; 322 } 323 324 return 0; 325error: 326 v4l2_ctrl_handler_free(&priv->ctrl_handler); 327 328 return ret; 329} 330 331static int max96712_parse_dt(struct max96712_priv *priv) 332{ 333 struct fwnode_handle *ep; 334 struct v4l2_fwnode_endpoint v4l2_ep = { 335 .bus_type = V4L2_MBUS_CSI2_DPHY 336 }; 337 int ret; 338 339 ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(&priv->client->dev), 4, 340 0, 0); 341 if (!ep) { 342 dev_err(&priv->client->dev, "Not connected to subdevice\n"); 343 return -EINVAL; 344 } 345 346 ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); 347 fwnode_handle_put(ep); 348 if (ret) { 349 dev_err(&priv->client->dev, "Could not parse v4l2 endpoint\n"); 350 return -EINVAL; 351 } 352 353 if (v4l2_ep.bus.mipi_csi2.num_data_lanes != 4) { 354 dev_err(&priv->client->dev, "Only 4 data lanes supported\n"); 355 return -EINVAL; 356 } 357 358 priv->mipi = v4l2_ep.bus.mipi_csi2; 359 360 return 0; 361} 362 363static const struct regmap_config max96712_i2c_regmap = { 364 .reg_bits = 16, 365 .val_bits = 8, 366 .max_register = 0x1f00, 367}; 368 369static int max96712_probe(struct i2c_client *client) 370{ 371 struct max96712_priv *priv; 372 int ret; 373 374 priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL); 375 if (!priv) 376 return -ENOMEM; 377 378 priv->client = client; 379 i2c_set_clientdata(client, priv); 380 381 priv->regmap = devm_regmap_init_i2c(client, &max96712_i2c_regmap); 382 if (IS_ERR(priv->regmap)) 383 return PTR_ERR(priv->regmap); 384 385 priv->gpiod_pwdn = devm_gpiod_get_optional(&client->dev, "enable", 386 GPIOD_OUT_HIGH); 387 if (IS_ERR(priv->gpiod_pwdn)) 388 return PTR_ERR(priv->gpiod_pwdn); 389 390 gpiod_set_consumer_name(priv->gpiod_pwdn, "max96712-pwdn"); 391 gpiod_set_value_cansleep(priv->gpiod_pwdn, 1); 392 393 if (priv->gpiod_pwdn) 394 usleep_range(4000, 5000); 395 396 if (max96712_read(priv, 0x4a) != MAX96712_ID) 397 return -ENODEV; 398 399 max96712_reset(priv); 400 401 ret = max96712_parse_dt(priv); 402 if (ret) 403 return ret; 404 405 max96712_mipi_configure(priv); 406 407 return max96712_v4l2_register(priv); 408} 409 410static int max96712_remove(struct i2c_client *client) 411{ 412 struct max96712_priv *priv = i2c_get_clientdata(client); 413 414 v4l2_async_unregister_subdev(&priv->sd); 415 416 gpiod_set_value_cansleep(priv->gpiod_pwdn, 0); 417 418 return 0; 419} 420 421static const struct of_device_id max96712_of_table[] = { 422 { .compatible = "maxim,max96712" }, 423 { /* sentinel */ }, 424}; 425MODULE_DEVICE_TABLE(of, max96712_of_table); 426 427static struct i2c_driver max96712_i2c_driver = { 428 .driver = { 429 .name = "max96712", 430 .of_match_table = of_match_ptr(max96712_of_table), 431 }, 432 .probe_new = max96712_probe, 433 .remove = max96712_remove, 434}; 435 436module_i2c_driver(max96712_i2c_driver); 437 438MODULE_DESCRIPTION("Maxim MAX96712 Quad GMSL2 Deserializer Driver"); 439MODULE_AUTHOR("Niklas Söderlund <niklas.soderlund@ragnatech.se>"); 440MODULE_LICENSE("GPL");