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