1/* 2 * Driver for the mt9m111 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#include "m5602_mt9m111.h" 20 21static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); 22static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); 23static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); 24static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val); 25static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val); 26static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val); 27static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, 28 __s32 val); 29static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, 30 __s32 *val); 31static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val); 32static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val); 33static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val); 34static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val); 35static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val); 36static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val); 37 38static struct v4l2_pix_format mt9m111_modes[] = { 39 { 40 640, 41 480, 42 V4L2_PIX_FMT_SBGGR8, 43 V4L2_FIELD_NONE, 44 .sizeimage = 640 * 480, 45 .bytesperline = 640, 46 .colorspace = V4L2_COLORSPACE_SRGB, 47 .priv = 0 48 } 49}; 50 51static const struct ctrl mt9m111_ctrls[] = { 52#define VFLIP_IDX 0 53 { 54 { 55 .id = V4L2_CID_VFLIP, 56 .type = V4L2_CTRL_TYPE_BOOLEAN, 57 .name = "vertical flip", 58 .minimum = 0, 59 .maximum = 1, 60 .step = 1, 61 .default_value = 0 62 }, 63 .set = mt9m111_set_vflip, 64 .get = mt9m111_get_vflip 65 }, 66#define HFLIP_IDX 1 67 { 68 { 69 .id = V4L2_CID_HFLIP, 70 .type = V4L2_CTRL_TYPE_BOOLEAN, 71 .name = "horizontal flip", 72 .minimum = 0, 73 .maximum = 1, 74 .step = 1, 75 .default_value = 0 76 }, 77 .set = mt9m111_set_hflip, 78 .get = mt9m111_get_hflip 79 }, 80#define GAIN_IDX 2 81 { 82 { 83 .id = V4L2_CID_GAIN, 84 .type = V4L2_CTRL_TYPE_INTEGER, 85 .name = "gain", 86 .minimum = 0, 87 .maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 88 .step = 1, 89 .default_value = MT9M111_DEFAULT_GAIN, 90 .flags = V4L2_CTRL_FLAG_SLIDER 91 }, 92 .set = mt9m111_set_gain, 93 .get = mt9m111_get_gain 94 }, 95#define AUTO_WHITE_BALANCE_IDX 3 96 { 97 { 98 .id = V4L2_CID_AUTO_WHITE_BALANCE, 99 .type = V4L2_CTRL_TYPE_BOOLEAN, 100 .name = "auto white balance", 101 .minimum = 0, 102 .maximum = 1, 103 .step = 1, 104 .default_value = 0, 105 }, 106 .set = mt9m111_set_auto_white_balance, 107 .get = mt9m111_get_auto_white_balance 108 }, 109#define GREEN_BALANCE_IDX 4 110 { 111 { 112 .id = M5602_V4L2_CID_GREEN_BALANCE, 113 .type = V4L2_CTRL_TYPE_INTEGER, 114 .name = "green balance", 115 .minimum = 0x00, 116 .maximum = 0x7ff, 117 .step = 0x1, 118 .default_value = MT9M111_GREEN_GAIN_DEFAULT, 119 .flags = V4L2_CTRL_FLAG_SLIDER 120 }, 121 .set = mt9m111_set_green_balance, 122 .get = mt9m111_get_green_balance 123 }, 124#define BLUE_BALANCE_IDX 5 125 { 126 { 127 .id = V4L2_CID_BLUE_BALANCE, 128 .type = V4L2_CTRL_TYPE_INTEGER, 129 .name = "blue balance", 130 .minimum = 0x00, 131 .maximum = 0x7ff, 132 .step = 0x1, 133 .default_value = MT9M111_BLUE_GAIN_DEFAULT, 134 .flags = V4L2_CTRL_FLAG_SLIDER 135 }, 136 .set = mt9m111_set_blue_balance, 137 .get = mt9m111_get_blue_balance 138 }, 139#define RED_BALANCE_IDX 5 140 { 141 { 142 .id = V4L2_CID_RED_BALANCE, 143 .type = V4L2_CTRL_TYPE_INTEGER, 144 .name = "red balance", 145 .minimum = 0x00, 146 .maximum = 0x7ff, 147 .step = 0x1, 148 .default_value = MT9M111_RED_GAIN_DEFAULT, 149 .flags = V4L2_CTRL_FLAG_SLIDER 150 }, 151 .set = mt9m111_set_red_balance, 152 .get = mt9m111_get_red_balance 153 }, 154}; 155 156static void mt9m111_dump_registers(struct sd *sd); 157 158int mt9m111_probe(struct sd *sd) 159{ 160 u8 data[2] = {0x00, 0x00}; 161 int i; 162 s32 *sensor_settings; 163 164 if (force_sensor) { 165 if (force_sensor == MT9M111_SENSOR) { 166 info("Forcing a %s sensor", mt9m111.name); 167 goto sensor_found; 168 } 169 /* If we want to force another sensor, don't try to probe this 170 * one */ 171 return -ENODEV; 172 } 173 174 PDEBUG(D_PROBE, "Probing for a mt9m111 sensor"); 175 176 /* Do the preinit */ 177 for (i = 0; i < ARRAY_SIZE(preinit_mt9m111); i++) { 178 if (preinit_mt9m111[i][0] == BRIDGE) { 179 m5602_write_bridge(sd, 180 preinit_mt9m111[i][1], 181 preinit_mt9m111[i][2]); 182 } else { 183 data[0] = preinit_mt9m111[i][2]; 184 data[1] = preinit_mt9m111[i][3]; 185 m5602_write_sensor(sd, 186 preinit_mt9m111[i][1], data, 2); 187 } 188 } 189 190 if (m5602_read_sensor(sd, MT9M111_SC_CHIPVER, data, 2)) 191 return -ENODEV; 192 193 if ((data[0] == 0x14) && (data[1] == 0x3a)) { 194 info("Detected a mt9m111 sensor"); 195 goto sensor_found; 196 } 197 198 return -ENODEV; 199 200sensor_found: 201 sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32), 202 GFP_KERNEL); 203 if (!sensor_settings) 204 return -ENOMEM; 205 206 sd->gspca_dev.cam.cam_mode = mt9m111_modes; 207 sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); 208 sd->desc->ctrls = mt9m111_ctrls; 209 sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls); 210 211 for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++) 212 sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value; 213 sd->sensor_priv = sensor_settings; 214 215 return 0; 216} 217 218int mt9m111_init(struct sd *sd) 219{ 220 int i, err = 0; 221 s32 *sensor_settings = sd->sensor_priv; 222 223 /* Init the sensor */ 224 for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { 225 u8 data[2]; 226 227 if (init_mt9m111[i][0] == BRIDGE) { 228 err = m5602_write_bridge(sd, 229 init_mt9m111[i][1], 230 init_mt9m111[i][2]); 231 } else { 232 data[0] = init_mt9m111[i][2]; 233 data[1] = init_mt9m111[i][3]; 234 err = m5602_write_sensor(sd, 235 init_mt9m111[i][1], data, 2); 236 } 237 } 238 239 if (dump_sensor) 240 mt9m111_dump_registers(sd); 241 242 err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); 243 if (err < 0) 244 return err; 245 246 err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); 247 if (err < 0) 248 return err; 249 250 err = mt9m111_set_green_balance(&sd->gspca_dev, 251 sensor_settings[GREEN_BALANCE_IDX]); 252 if (err < 0) 253 return err; 254 255 err = mt9m111_set_blue_balance(&sd->gspca_dev, 256 sensor_settings[BLUE_BALANCE_IDX]); 257 if (err < 0) 258 return err; 259 260 err = mt9m111_set_red_balance(&sd->gspca_dev, 261 sensor_settings[RED_BALANCE_IDX]); 262 if (err < 0) 263 return err; 264 265 return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); 266} 267 268int mt9m111_start(struct sd *sd) 269{ 270 int i, err = 0; 271 u8 data[2]; 272 struct cam *cam = &sd->gspca_dev.cam; 273 s32 *sensor_settings = sd->sensor_priv; 274 275 int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; 276 int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; 277 278 for (i = 0; i < ARRAY_SIZE(start_mt9m111) && !err; i++) { 279 if (start_mt9m111[i][0] == BRIDGE) { 280 err = m5602_write_bridge(sd, 281 start_mt9m111[i][1], 282 start_mt9m111[i][2]); 283 } else { 284 data[0] = start_mt9m111[i][2]; 285 data[1] = start_mt9m111[i][3]; 286 err = m5602_write_sensor(sd, 287 start_mt9m111[i][1], data, 2); 288 } 289 } 290 if (err < 0) 291 return err; 292 293 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height >> 8) & 0xff); 294 if (err < 0) 295 return err; 296 297 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, (height & 0xff)); 298 if (err < 0) 299 return err; 300 301 for (i = 0; i < 2 && !err; i++) 302 err = m5602_write_bridge(sd, M5602_XB_VSYNC_PARA, 0); 303 if (err < 0) 304 return err; 305 306 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 307 if (err < 0) 308 return err; 309 310 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 2); 311 if (err < 0) 312 return err; 313 314 for (i = 0; i < 2 && !err; i++) 315 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 0); 316 if (err < 0) 317 return err; 318 319 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, 320 (width >> 8) & 0xff); 321 if (err < 0) 322 return err; 323 324 err = m5602_write_bridge(sd, M5602_XB_HSYNC_PARA, width & 0xff); 325 if (err < 0) 326 return err; 327 328 err = m5602_write_bridge(sd, M5602_XB_SIG_INI, 0); 329 if (err < 0) 330 return err; 331 332 switch (width) { 333 case 640: 334 PDEBUG(D_V4L2, "Configuring camera for VGA mode"); 335 data[0] = MT9M111_RMB_OVER_SIZED; 336 data[1] = MT9M111_RMB_ROW_SKIP_2X | 337 MT9M111_RMB_COLUMN_SKIP_2X | 338 (sensor_settings[VFLIP_IDX] << 0) | 339 (sensor_settings[HFLIP_IDX] << 1); 340 341 err = m5602_write_sensor(sd, 342 MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 343 break; 344 345 case 320: 346 PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); 347 data[0] = MT9M111_RMB_OVER_SIZED; 348 data[1] = MT9M111_RMB_ROW_SKIP_4X | 349 MT9M111_RMB_COLUMN_SKIP_4X | 350 (sensor_settings[VFLIP_IDX] << 0) | 351 (sensor_settings[HFLIP_IDX] << 1); 352 err = m5602_write_sensor(sd, 353 MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 354 break; 355 } 356 return err; 357} 358 359void mt9m111_disconnect(struct sd *sd) 360{ 361 sd->sensor = NULL; 362 kfree(sd->sensor_priv); 363} 364 365static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) 366{ 367 struct sd *sd = (struct sd *) gspca_dev; 368 s32 *sensor_settings = sd->sensor_priv; 369 370 *val = sensor_settings[VFLIP_IDX]; 371 PDEBUG(D_V4L2, "Read vertical flip %d", *val); 372 373 return 0; 374} 375 376static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val) 377{ 378 int err; 379 u8 data[2] = {0x00, 0x00}; 380 struct sd *sd = (struct sd *) gspca_dev; 381 s32 *sensor_settings = sd->sensor_priv; 382 383 PDEBUG(D_V4L2, "Set vertical flip to %d", val); 384 385 sensor_settings[VFLIP_IDX] = val; 386 387 /* The mt9m111 is flipped by default */ 388 val = !val; 389 390 /* Set the correct page map */ 391 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 392 if (err < 0) 393 return err; 394 395 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 396 if (err < 0) 397 return err; 398 399 data[1] = (data[1] & 0xfe) | val; 400 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, 401 data, 2); 402 return err; 403} 404 405static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) 406{ 407 struct sd *sd = (struct sd *) gspca_dev; 408 s32 *sensor_settings = sd->sensor_priv; 409 410 *val = sensor_settings[HFLIP_IDX]; 411 PDEBUG(D_V4L2, "Read horizontal flip %d", *val); 412 413 return 0; 414} 415 416static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val) 417{ 418 int err; 419 u8 data[2] = {0x00, 0x00}; 420 struct sd *sd = (struct sd *) gspca_dev; 421 s32 *sensor_settings = sd->sensor_priv; 422 423 PDEBUG(D_V4L2, "Set horizontal flip to %d", val); 424 425 sensor_settings[HFLIP_IDX] = val; 426 427 /* The mt9m111 is flipped by default */ 428 val = !val; 429 430 /* Set the correct page map */ 431 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 432 if (err < 0) 433 return err; 434 435 err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); 436 if (err < 0) 437 return err; 438 439 data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02); 440 err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, 441 data, 2); 442 return err; 443} 444 445static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val) 446{ 447 struct sd *sd = (struct sd *) gspca_dev; 448 s32 *sensor_settings = sd->sensor_priv; 449 450 *val = sensor_settings[GAIN_IDX]; 451 PDEBUG(D_V4L2, "Read gain %d", *val); 452 453 return 0; 454} 455 456static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, 457 __s32 val) 458{ 459 struct sd *sd = (struct sd *) gspca_dev; 460 s32 *sensor_settings = sd->sensor_priv; 461 int err; 462 u8 data[2]; 463 464 err = m5602_read_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 465 if (err < 0) 466 return err; 467 468 sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01; 469 data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); 470 471 err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); 472 473 PDEBUG(D_V4L2, "Set auto white balance %d", val); 474 return err; 475} 476 477static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev, 478 __s32 *val) { 479 struct sd *sd = (struct sd *) gspca_dev; 480 s32 *sensor_settings = sd->sensor_priv; 481 482 *val = sensor_settings[AUTO_WHITE_BALANCE_IDX]; 483 PDEBUG(D_V4L2, "Read auto white balance %d", *val); 484 return 0; 485} 486 487static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) 488{ 489 int err, tmp; 490 u8 data[2] = {0x00, 0x00}; 491 struct sd *sd = (struct sd *) gspca_dev; 492 s32 *sensor_settings = sd->sensor_priv; 493 494 sensor_settings[GAIN_IDX] = val; 495 496 /* Set the correct page map */ 497 err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); 498 if (err < 0) 499 return err; 500 501 if (val >= INITIAL_MAX_GAIN * 2 * 2 * 2) 502 return -EINVAL; 503 504 if ((val >= INITIAL_MAX_GAIN * 2 * 2) && 505 (val < (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2)) 506 tmp = (1 << 10) | (val << 9) | 507 (val << 8) | (val / 8); 508 else if ((val >= INITIAL_MAX_GAIN * 2) && 509 (val < INITIAL_MAX_GAIN * 2 * 2)) 510 tmp = (1 << 9) | (1 << 8) | (val / 4); 511 else if ((val >= INITIAL_MAX_GAIN) && 512 (val < INITIAL_MAX_GAIN * 2)) 513 tmp = (1 << 8) | (val / 2); 514 else 515 tmp = val; 516 517 data[1] = (tmp & 0xff); 518 data[0] = (tmp & 0xff00) >> 8; 519 PDEBUG(D_V4L2, "tmp=%d, data[1]=%d, data[0]=%d", tmp, 520 data[1], data[0]); 521 522 err = m5602_write_sensor(sd, MT9M111_SC_GLOBAL_GAIN, 523 data, 2); 524 525 return err; 526} 527 528static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) 529{ 530 int err; 531 u8 data[2]; 532 struct sd *sd = (struct sd *) gspca_dev; 533 s32 *sensor_settings = sd->sensor_priv; 534 535 sensor_settings[GREEN_BALANCE_IDX] = val; 536 data[1] = (val & 0xff); 537 data[0] = (val & 0xff00) >> 8; 538 539 PDEBUG(D_V4L2, "Set green balance %d", val); 540 err = m5602_write_sensor(sd, MT9M111_SC_GREEN_1_GAIN, 541 data, 2); 542 if (err < 0) 543 return err; 544 545 return m5602_write_sensor(sd, MT9M111_SC_GREEN_2_GAIN, 546 data, 2); 547} 548 549static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val) 550{ 551 struct sd *sd = (struct sd *) gspca_dev; 552 s32 *sensor_settings = sd->sensor_priv; 553 554 *val = sensor_settings[GREEN_BALANCE_IDX]; 555 PDEBUG(D_V4L2, "Read green balance %d", *val); 556 return 0; 557} 558 559static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) 560{ 561 u8 data[2]; 562 struct sd *sd = (struct sd *) gspca_dev; 563 s32 *sensor_settings = sd->sensor_priv; 564 565 sensor_settings[BLUE_BALANCE_IDX] = val; 566 data[1] = (val & 0xff); 567 data[0] = (val & 0xff00) >> 8; 568 569 PDEBUG(D_V4L2, "Set blue balance %d", val); 570 571 return m5602_write_sensor(sd, MT9M111_SC_BLUE_GAIN, 572 data, 2); 573} 574 575static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val) 576{ 577 struct sd *sd = (struct sd *) gspca_dev; 578 s32 *sensor_settings = sd->sensor_priv; 579 580 *val = sensor_settings[BLUE_BALANCE_IDX]; 581 PDEBUG(D_V4L2, "Read blue balance %d", *val); 582 return 0; 583} 584 585static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) 586{ 587 u8 data[2]; 588 struct sd *sd = (struct sd *) gspca_dev; 589 s32 *sensor_settings = sd->sensor_priv; 590 591 sensor_settings[RED_BALANCE_IDX] = val; 592 data[1] = (val & 0xff); 593 data[0] = (val & 0xff00) >> 8; 594 595 PDEBUG(D_V4L2, "Set red balance %d", val); 596 597 return m5602_write_sensor(sd, MT9M111_SC_RED_GAIN, 598 data, 2); 599} 600 601static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) 602{ 603 struct sd *sd = (struct sd *) gspca_dev; 604 s32 *sensor_settings = sd->sensor_priv; 605 606 *val = sensor_settings[RED_BALANCE_IDX]; 607 PDEBUG(D_V4L2, "Read red balance %d", *val); 608 return 0; 609} 610 611static void mt9m111_dump_registers(struct sd *sd) 612{ 613 u8 address, value[2] = {0x00, 0x00}; 614 615 info("Dumping the mt9m111 register state"); 616 617 info("Dumping the mt9m111 sensor core registers"); 618 value[1] = MT9M111_SENSOR_CORE; 619 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 620 for (address = 0; address < 0xff; address++) { 621 m5602_read_sensor(sd, address, value, 2); 622 info("register 0x%x contains 0x%x%x", 623 address, value[0], value[1]); 624 } 625 626 info("Dumping the mt9m111 color pipeline registers"); 627 value[1] = MT9M111_COLORPIPE; 628 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 629 for (address = 0; address < 0xff; address++) { 630 m5602_read_sensor(sd, address, value, 2); 631 info("register 0x%x contains 0x%x%x", 632 address, value[0], value[1]); 633 } 634 635 info("Dumping the mt9m111 camera control registers"); 636 value[1] = MT9M111_CAMERA_CONTROL; 637 m5602_write_sensor(sd, MT9M111_PAGE_MAP, value, 2); 638 for (address = 0; address < 0xff; address++) { 639 m5602_read_sensor(sd, address, value, 2); 640 info("register 0x%x contains 0x%x%x", 641 address, value[0], value[1]); 642 } 643 644 info("mt9m111 register state dump complete"); 645} 646