1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Driver for the s5k83a sensor 4 * 5 * Copyright (C) 2008 Erik Andrén 6 * Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project. 7 * Copyright (C) 2005 m5603x Linux Driver Project <m5602@x3ng.com.br> 8 * 9 * Portions of code to USB interface and ALi driver software, 10 * Copyright (c) 2006 Willem Duinker 11 * v4l2 interface modeled after the V4L2 driver 12 * for SN9C10x PC Camera Controllers 13 */ 14 15 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 17 #include <linux/kthread.h> 18 #include "m5602_s5k83a.h" 19 20 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl); 21 22 static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = { 23 .s_ctrl = s5k83a_s_ctrl, 24 }; 25 26 static struct v4l2_pix_format s5k83a_modes[] = { 27 { 28 640, 29 480, 30 V4L2_PIX_FMT_SBGGR8, 31 V4L2_FIELD_NONE, 32 .sizeimage = 33 640 * 480, 34 .bytesperline = 640, 35 .colorspace = V4L2_COLORSPACE_SRGB, 36 .priv = 0 37 } 38 }; 39 40 static const unsigned char preinit_s5k83a[][4] = { 41 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 42 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 43 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 44 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 45 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 46 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x0d, 0x00}, 47 {BRIDGE, M5602_XB_SENSOR_CTRL, 0x00, 0x00}, 48 49 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 50 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 51 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 52 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 53 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 54 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 55 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 56 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 57 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 58 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 59 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 60 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 61 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 62 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 63 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 64 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 65 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 66 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 67 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 68 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 69 {BRIDGE, M5602_XB_GPIO_DAT, 0x1c, 0x00}, 70 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 71 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 72 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 73 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 74 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 75 }; 76 77 /* This could probably be considerably shortened. 78 I don't have the hardware to experiment with it, patches welcome 79 */ 80 static const unsigned char init_s5k83a[][4] = { 81 /* The following sequence is useless after a clean boot 82 but is necessary after resume from suspend */ 83 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 84 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 85 {BRIDGE, M5602_XB_GPIO_EN_H, 0x3f, 0x00}, 86 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x3f, 0x00}, 87 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 88 {BRIDGE, M5602_XB_GPIO_EN_L, 0xff, 0x00}, 89 {BRIDGE, M5602_XB_GPIO_DIR_L, 0xff, 0x00}, 90 {BRIDGE, M5602_XB_GPIO_DAT_L, 0x00, 0x00}, 91 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0xb0, 0x00}, 92 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0x80, 0x00}, 93 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 94 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 95 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 96 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 97 {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, 98 {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, 99 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 100 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xf0, 0x00}, 101 {BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00}, 102 {BRIDGE, M5602_XB_GPIO_DAT, 0x08, 0x00}, 103 {BRIDGE, M5602_XB_GPIO_EN_H, 0x06, 0x00}, 104 {BRIDGE, M5602_XB_GPIO_DIR_H, 0x06, 0x00}, 105 {BRIDGE, M5602_XB_GPIO_DAT_H, 0x00, 0x00}, 106 {BRIDGE, M5602_XB_GPIO_EN_L, 0x00, 0x00}, 107 {BRIDGE, M5602_XB_I2C_CLK_DIV, 0x20, 0x00}, 108 109 {SENSOR, S5K83A_PAGE_MAP, 0x04, 0x00}, 110 {SENSOR, 0xaf, 0x01, 0x00}, 111 {SENSOR, S5K83A_PAGE_MAP, 0x00, 0x00}, 112 {SENSOR, 0x7b, 0xff, 0x00}, 113 {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, 114 {SENSOR, 0x01, 0x50, 0x00}, 115 {SENSOR, 0x12, 0x20, 0x00}, 116 {SENSOR, 0x17, 0x40, 0x00}, 117 {SENSOR, 0x1c, 0x00, 0x00}, 118 {SENSOR, 0x02, 0x70, 0x00}, 119 {SENSOR, 0x03, 0x0b, 0x00}, 120 {SENSOR, 0x04, 0xf0, 0x00}, 121 {SENSOR, 0x05, 0x0b, 0x00}, 122 {SENSOR, 0x06, 0x71, 0x00}, 123 {SENSOR, 0x07, 0xe8, 0x00}, /* 488 */ 124 {SENSOR, 0x08, 0x02, 0x00}, 125 {SENSOR, 0x09, 0x88, 0x00}, /* 648 */ 126 {SENSOR, 0x14, 0x00, 0x00}, 127 {SENSOR, 0x15, 0x20, 0x00}, /* 32 */ 128 {SENSOR, 0x19, 0x00, 0x00}, 129 {SENSOR, 0x1a, 0x98, 0x00}, /* 152 */ 130 {SENSOR, 0x0f, 0x02, 0x00}, 131 {SENSOR, 0x10, 0xe5, 0x00}, /* 741 */ 132 /* normal colors 133 (this is value after boot, but after tries can be different) */ 134 {SENSOR, 0x00, 0x06, 0x00}, 135 }; 136 137 static const unsigned char start_s5k83a[][4] = { 138 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00}, 139 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 140 {BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00}, 141 {BRIDGE, M5602_XB_SENSOR_TYPE, 0x09, 0x00}, 142 {BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x81, 0x00}, 143 {BRIDGE, M5602_XB_PIX_OF_LINE_H, 0x82, 0x00}, 144 {BRIDGE, M5602_XB_SIG_INI, 0x01, 0x00}, 145 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 146 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 147 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 148 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 149 {BRIDGE, M5602_XB_VSYNC_PARA, 0x01, 0x00}, 150 {BRIDGE, M5602_XB_VSYNC_PARA, 0xe4, 0x00}, /* 484 */ 151 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 152 {BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00}, 153 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 154 {BRIDGE, M5602_XB_SIG_INI, 0x02, 0x00}, 155 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 156 {BRIDGE, M5602_XB_HSYNC_PARA, 0x00, 0x00}, 157 {BRIDGE, M5602_XB_HSYNC_PARA, 0x02, 0x00}, 158 {BRIDGE, M5602_XB_HSYNC_PARA, 0x7f, 0x00}, /* 639 */ 159 {BRIDGE, M5602_XB_SIG_INI, 0x00, 0x00}, 160 {BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00}, 161 {BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00}, 162 }; 163 164 static void s5k83a_dump_registers(struct sd *sd); 165 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); 166 static int s5k83a_set_led_indication(struct sd *sd, u8 val); 167 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, 168 __s32 vflip, __s32 hflip); 169 170 int s5k83a_probe(struct sd *sd) 171 { 172 u8 prod_id = 0, ver_id = 0; 173 int i, err = 0; 174 struct gspca_dev *gspca_dev = (struct gspca_dev *)sd; 175 176 if (force_sensor) { 177 if (force_sensor == S5K83A_SENSOR) { 178 pr_info("Forcing a %s sensor\n", s5k83a.name); 179 goto sensor_found; 180 } 181 /* If we want to force another sensor, don't try to probe this 182 * one */ 183 return -ENODEV; 184 } 185 186 gspca_dbg(gspca_dev, D_PROBE, "Probing for a s5k83a sensor\n"); 187 188 /* Preinit the sensor */ 189 for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) { 190 u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]}; 191 if (preinit_s5k83a[i][0] == SENSOR) 192 err = m5602_write_sensor(sd, preinit_s5k83a[i][1], 193 data, 2); 194 else 195 err = m5602_write_bridge(sd, preinit_s5k83a[i][1], 196 data[0]); 197 } 198 199 /* We don't know what register (if any) that contain the product id 200 * Just pick the first addresses that seem to produce the same results 201 * on multiple machines */ 202 if (m5602_read_sensor(sd, 0x00, &prod_id, 1)) 203 return -ENODEV; 204 205 if (m5602_read_sensor(sd, 0x01, &ver_id, 1)) 206 return -ENODEV; 207 208 if ((prod_id == 0xff) || (ver_id == 0xff)) 209 return -ENODEV; 210 else 211 pr_info("Detected a s5k83a sensor\n"); 212 213 sensor_found: 214 sd->gspca_dev.cam.cam_mode = s5k83a_modes; 215 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); 216 217 /* null the pointer! thread is't running now */ 218 sd->rotation_thread = NULL; 219 220 return 0; 221 } 222 223 int s5k83a_init(struct sd *sd) 224 { 225 int i, err = 0; 226 227 for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { 228 u8 data[2] = {0x00, 0x00}; 229 230 switch (init_s5k83a[i][0]) { 231 case BRIDGE: 232 err = m5602_write_bridge(sd, 233 init_s5k83a[i][1], 234 init_s5k83a[i][2]); 235 break; 236 237 case SENSOR: 238 data[0] = init_s5k83a[i][2]; 239 err = m5602_write_sensor(sd, 240 init_s5k83a[i][1], data, 1); 241 break; 242 243 case SENSOR_LONG: 244 data[0] = init_s5k83a[i][2]; 245 data[1] = init_s5k83a[i][3]; 246 err = m5602_write_sensor(sd, 247 init_s5k83a[i][1], data, 2); 248 break; 249 default: 250 pr_info("Invalid stream command, exiting init\n"); 251 return -EINVAL; 252 } 253 } 254 255 if (dump_sensor) 256 s5k83a_dump_registers(sd); 257 258 return err; 259 } 260 261 int s5k83a_init_controls(struct sd *sd) 262 { 263 struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler; 264 265 sd->gspca_dev.vdev.ctrl_handler = hdl; 266 v4l2_ctrl_handler_init(hdl, 6); 267 268 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS, 269 0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS); 270 271 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE, 272 0, S5K83A_MAXIMUM_EXPOSURE, 1, 273 S5K83A_DEFAULT_EXPOSURE); 274 275 v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN, 276 0, 255, 1, S5K83A_DEFAULT_GAIN); 277 278 sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP, 279 0, 1, 1, 0); 280 sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP, 281 0, 1, 1, 0); 282 283 if (hdl->error) { 284 pr_err("Could not initialize controls\n"); 285 return hdl->error; 286 } 287 288 v4l2_ctrl_cluster(2, &sd->hflip); 289 290 return 0; 291 } 292 293 static int rotation_thread_function(void *data) 294 { 295 struct sd *sd = (struct sd *) data; 296 u8 reg, previous_rotation = 0; 297 __s32 vflip, hflip; 298 299 set_current_state(TASK_INTERRUPTIBLE); 300 while (!schedule_timeout(msecs_to_jiffies(100))) { 301 if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock)) 302 break; 303 304 s5k83a_get_rotation(sd, ®); 305 if (previous_rotation != reg) { 306 previous_rotation = reg; 307 pr_info("Camera was flipped\n"); 308 309 hflip = sd->hflip->val; 310 vflip = sd->vflip->val; 311 312 if (reg) { 313 vflip = !vflip; 314 hflip = !hflip; 315 } 316 s5k83a_set_flip_real((struct gspca_dev *) sd, 317 vflip, hflip); 318 } 319 320 mutex_unlock(&sd->gspca_dev.usb_lock); 321 set_current_state(TASK_INTERRUPTIBLE); 322 } 323 324 /* return to "front" flip */ 325 if (previous_rotation) { 326 hflip = sd->hflip->val; 327 vflip = sd->vflip->val; 328 s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); 329 } 330 331 sd->rotation_thread = NULL; 332 return 0; 333 } 334 335 int s5k83a_start(struct sd *sd) 336 { 337 int i, err = 0; 338 339 /* Create another thread, polling the GPIO ports of the camera to check 340 if it got rotated. This is how the windows driver does it so we have 341 to assume that there is no better way of accomplishing this */ 342 sd->rotation_thread = kthread_run(rotation_thread_function, 343 sd, "rotation thread"); 344 if (IS_ERR(sd->rotation_thread)) { 345 err = PTR_ERR(sd->rotation_thread); 346 sd->rotation_thread = NULL; 347 return err; 348 } 349 350 /* Preinit the sensor */ 351 for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { 352 u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]}; 353 if (start_s5k83a[i][0] == SENSOR) 354 err = m5602_write_sensor(sd, start_s5k83a[i][1], 355 data, 2); 356 else 357 err = m5602_write_bridge(sd, start_s5k83a[i][1], 358 data[0]); 359 } 360 if (err < 0) 361 return err; 362 363 return s5k83a_set_led_indication(sd, 1); 364 } 365 366 int s5k83a_stop(struct sd *sd) 367 { 368 if (sd->rotation_thread) 369 kthread_stop(sd->rotation_thread); 370 371 return s5k83a_set_led_indication(sd, 0); 372 } 373 374 void s5k83a_disconnect(struct sd *sd) 375 { 376 s5k83a_stop(sd); 377 378 sd->sensor = NULL; 379 } 380 381 static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) 382 { 383 int err; 384 u8 data[2]; 385 struct sd *sd = (struct sd *) gspca_dev; 386 387 data[0] = 0x00; 388 data[1] = 0x20; 389 err = m5602_write_sensor(sd, 0x14, data, 2); 390 if (err < 0) 391 return err; 392 393 data[0] = 0x01; 394 data[1] = 0x00; 395 err = m5602_write_sensor(sd, 0x0d, data, 2); 396 if (err < 0) 397 return err; 398 399 /* FIXME: This is not sane, we need to figure out the composition 400 of these registers */ 401 data[0] = val >> 3; /* gain, high 5 bits */ 402 data[1] = val >> 1; /* gain, high 7 bits */ 403 err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2); 404 405 return err; 406 } 407 408 static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) 409 { 410 int err; 411 u8 data[1]; 412 struct sd *sd = (struct sd *) gspca_dev; 413 414 data[0] = val; 415 err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); 416 return err; 417 } 418 419 static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) 420 { 421 int err; 422 u8 data[2]; 423 struct sd *sd = (struct sd *) gspca_dev; 424 425 data[0] = 0; 426 data[1] = val; 427 err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); 428 return err; 429 } 430 431 static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, 432 __s32 vflip, __s32 hflip) 433 { 434 int err; 435 u8 data[1]; 436 struct sd *sd = (struct sd *) gspca_dev; 437 438 data[0] = 0x05; 439 err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1); 440 if (err < 0) 441 return err; 442 443 /* six bit is vflip, seven is hflip */ 444 data[0] = S5K83A_FLIP_MASK; 445 data[0] = (vflip) ? data[0] | 0x40 : data[0]; 446 data[0] = (hflip) ? data[0] | 0x80 : data[0]; 447 448 err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1); 449 if (err < 0) 450 return err; 451 452 data[0] = (vflip) ? 0x0b : 0x0a; 453 err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1); 454 if (err < 0) 455 return err; 456 457 data[0] = (hflip) ? 0x0a : 0x0b; 458 err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1); 459 return err; 460 } 461 462 static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev) 463 { 464 int err; 465 u8 reg; 466 struct sd *sd = (struct sd *) gspca_dev; 467 int hflip = sd->hflip->val; 468 int vflip = sd->vflip->val; 469 470 err = s5k83a_get_rotation(sd, ®); 471 if (err < 0) 472 return err; 473 if (reg) { 474 hflip = !hflip; 475 vflip = !vflip; 476 } 477 478 err = s5k83a_set_flip_real(gspca_dev, vflip, hflip); 479 return err; 480 } 481 482 static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl) 483 { 484 struct gspca_dev *gspca_dev = 485 container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 486 int err; 487 488 if (!gspca_dev->streaming) 489 return 0; 490 491 switch (ctrl->id) { 492 case V4L2_CID_BRIGHTNESS: 493 err = s5k83a_set_brightness(gspca_dev, ctrl->val); 494 break; 495 case V4L2_CID_EXPOSURE: 496 err = s5k83a_set_exposure(gspca_dev, ctrl->val); 497 break; 498 case V4L2_CID_GAIN: 499 err = s5k83a_set_gain(gspca_dev, ctrl->val); 500 break; 501 case V4L2_CID_HFLIP: 502 err = s5k83a_set_hvflip(gspca_dev); 503 break; 504 default: 505 return -EINVAL; 506 } 507 508 return err; 509 } 510 511 static int s5k83a_set_led_indication(struct sd *sd, u8 val) 512 { 513 int err = 0; 514 u8 data[1]; 515 516 err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data); 517 if (err < 0) 518 return err; 519 520 if (val) 521 data[0] = data[0] | S5K83A_GPIO_LED_MASK; 522 else 523 data[0] = data[0] & ~S5K83A_GPIO_LED_MASK; 524 525 err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]); 526 527 return err; 528 } 529 530 /* Get camera rotation on Acer notebooks */ 531 static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data) 532 { 533 int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data); 534 *reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1; 535 return err; 536 } 537 538 static void s5k83a_dump_registers(struct sd *sd) 539 { 540 int address; 541 u8 page, old_page; 542 m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); 543 544 for (page = 0; page < 16; page++) { 545 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); 546 pr_info("Dumping the s5k83a register state for page 0x%x\n", 547 page); 548 for (address = 0; address <= 0xff; address++) { 549 u8 val = 0; 550 m5602_read_sensor(sd, address, &val, 1); 551 pr_info("register 0x%x contains 0x%x\n", address, val); 552 } 553 } 554 pr_info("s5k83a register state dump complete\n"); 555 556 for (page = 0; page < 16; page++) { 557 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1); 558 pr_info("Probing for which registers that are read/write for page 0x%x\n", 559 page); 560 for (address = 0; address <= 0xff; address++) { 561 u8 old_val, ctrl_val, test_val = 0xff; 562 563 m5602_read_sensor(sd, address, &old_val, 1); 564 m5602_write_sensor(sd, address, &test_val, 1); 565 m5602_read_sensor(sd, address, &ctrl_val, 1); 566 567 if (ctrl_val == test_val) 568 pr_info("register 0x%x is writeable\n", 569 address); 570 else 571 pr_info("register 0x%x is read only\n", 572 address); 573 574 /* Restore original val */ 575 m5602_write_sensor(sd, address, &old_val, 1); 576 } 577 } 578 pr_info("Read/write register probing complete\n"); 579 m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1); 580 } 581