aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Verkuil <hans.verkuil@cisco.com>2012-05-16 07:20:44 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-07-30 17:30:25 -0400
commit3fa24bf5e159d10d160015e08decb48cfa1663a8 (patch)
tree258b5ac9c9243b6b73f8ef506887f8796aef2c9f
parentfca2e678c161e963093269f8482bbe70593fc9cd (diff)
[media] spca561: convert to the control framework
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/gspca/spca561.c386
1 files changed, 103 insertions, 283 deletions
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 4a5f209ce719..168be551576e 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -31,39 +31,17 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
31MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver"); 31MODULE_DESCRIPTION("GSPCA/SPCA561 USB Camera Driver");
32MODULE_LICENSE("GPL"); 32MODULE_LICENSE("GPL");
33 33
34#define EXPOSURE_MAX (2047 + 325)
35
34/* specific webcam descriptor */ 36/* specific webcam descriptor */
35struct sd { 37struct sd {
36 struct gspca_dev gspca_dev; /* !! must be the first item */ 38 struct gspca_dev gspca_dev; /* !! must be the first item */
37 39
38 __u16 exposure; /* rev12a only */ 40 struct { /* hue/contrast control cluster */
39#define EXPOSURE_MIN 1 41 struct v4l2_ctrl *contrast;
40#define EXPOSURE_DEF 700 /* == 10 fps */ 42 struct v4l2_ctrl *hue;
41#define EXPOSURE_MAX (2047 + 325) /* see setexposure */ 43 };
42 44 struct v4l2_ctrl *autogain;
43 __u8 contrast; /* rev72a only */
44#define CONTRAST_MIN 0x00
45#define CONTRAST_DEF 0x20
46#define CONTRAST_MAX 0x3f
47
48 __u8 brightness; /* rev72a only */
49#define BRIGHTNESS_MIN 0
50#define BRIGHTNESS_DEF 0x20
51#define BRIGHTNESS_MAX 0x3f
52
53 __u8 white;
54#define HUE_MIN 1
55#define HUE_DEF 0x40
56#define HUE_MAX 0x7f
57
58 __u8 autogain;
59#define AUTOGAIN_MIN 0
60#define AUTOGAIN_DEF 1
61#define AUTOGAIN_MAX 1
62
63 __u8 gain; /* rev12a only */
64#define GAIN_MIN 0
65#define GAIN_DEF 63
66#define GAIN_MAX 255
67 45
68#define EXPO12A_DEF 3 46#define EXPO12A_DEF 3
69 __u8 expo12a; /* expo/gain? for rev 12a */ 47 __u8 expo12a; /* expo/gain? for rev 12a */
@@ -461,12 +439,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
461 cam->cam_mode = sif_072a_mode; 439 cam->cam_mode = sif_072a_mode;
462 cam->nmodes = ARRAY_SIZE(sif_072a_mode); 440 cam->nmodes = ARRAY_SIZE(sif_072a_mode);
463 } 441 }
464 sd->brightness = BRIGHTNESS_DEF;
465 sd->contrast = CONTRAST_DEF;
466 sd->white = HUE_DEF;
467 sd->exposure = EXPOSURE_DEF;
468 sd->autogain = AUTOGAIN_DEF;
469 sd->gain = GAIN_DEF;
470 sd->expo12a = EXPO12A_DEF; 442 sd->expo12a = EXPO12A_DEF;
471 return 0; 443 return 0;
472} 444}
@@ -492,65 +464,43 @@ static int sd_init_72a(struct gspca_dev *gspca_dev)
492} 464}
493 465
494/* rev 72a only */ 466/* rev 72a only */
495static void setbrightness(struct gspca_dev *gspca_dev) 467static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
496{ 468{
497 struct sd *sd = (struct sd *) gspca_dev;
498 struct usb_device *dev = gspca_dev->dev; 469 struct usb_device *dev = gspca_dev->dev;
499 __u8 value;
500
501 value = sd->brightness;
502 470
503 /* offsets for white balance */ 471 /* offsets for white balance */
504 reg_w_val(dev, 0x8611, value); /* R */ 472 reg_w_val(dev, 0x8611, val); /* R */
505 reg_w_val(dev, 0x8612, value); /* Gr */ 473 reg_w_val(dev, 0x8612, val); /* Gr */
506 reg_w_val(dev, 0x8613, value); /* B */ 474 reg_w_val(dev, 0x8613, val); /* B */
507 reg_w_val(dev, 0x8614, value); /* Gb */ 475 reg_w_val(dev, 0x8614, val); /* Gb */
508} 476}
509 477
510static void setwhite(struct gspca_dev *gspca_dev) 478static void setwhite(struct gspca_dev *gspca_dev, s32 white, s32 contrast)
511{ 479{
512 struct sd *sd = (struct sd *) gspca_dev; 480 struct sd *sd = (struct sd *) gspca_dev;
513 __u16 white; 481 struct usb_device *dev = gspca_dev->dev;
514 __u8 blue, red; 482 __u8 blue, red;
515 __u16 reg; 483 __u16 reg;
516 484
517 /* try to emulate MS-win as possible */ 485 /* try to emulate MS-win as possible */
518 white = sd->white;
519 red = 0x20 + white * 3 / 8; 486 red = 0x20 + white * 3 / 8;
520 blue = 0x90 - white * 5 / 8; 487 blue = 0x90 - white * 5 / 8;
521 if (sd->chip_revision == Rev012A) { 488 if (sd->chip_revision == Rev012A) {
522 reg = 0x8614; 489 reg = 0x8614;
523 } else { 490 } else {
524 reg = 0x8651; 491 reg = 0x8651;
525 red += sd->contrast - 0x20; 492 red += contrast - 0x20;
526 blue += sd->contrast - 0x20; 493 blue += contrast - 0x20;
494 reg_w_val(dev, 0x8652, contrast + 0x20); /* Gr */
495 reg_w_val(dev, 0x8654, contrast + 0x20); /* Gb */
527 } 496 }
528 reg_w_val(gspca_dev->dev, reg, red); 497 reg_w_val(dev, reg, red);
529 reg_w_val(gspca_dev->dev, reg + 2, blue); 498 reg_w_val(dev, reg + 2, blue);
530}
531
532static void setcontrast(struct gspca_dev *gspca_dev)
533{
534 struct sd *sd = (struct sd *) gspca_dev;
535 struct usb_device *dev = gspca_dev->dev;
536 __u8 value;
537
538 if (sd->chip_revision != Rev072A)
539 return;
540 value = sd->contrast + 0x20;
541
542 /* gains for white balance */
543 setwhite(gspca_dev);
544/* reg_w_val(dev, 0x8651, value); * R - done by setwhite */
545 reg_w_val(dev, 0x8652, value); /* Gr */
546/* reg_w_val(dev, 0x8653, value); * B - done by setwhite */
547 reg_w_val(dev, 0x8654, value); /* Gb */
548} 499}
549 500
550/* rev 12a only */ 501/* rev 12a only */
551static void setexposure(struct gspca_dev *gspca_dev) 502static void setexposure(struct gspca_dev *gspca_dev, s32 val)
552{ 503{
553 struct sd *sd = (struct sd *) gspca_dev;
554 int i, expo = 0; 504 int i, expo = 0;
555 505
556 /* Register 0x8309 controls exposure for the spca561, 506 /* Register 0x8309 controls exposure for the spca561,
@@ -572,8 +522,8 @@ static void setexposure(struct gspca_dev *gspca_dev)
572 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX }; 522 int table[] = { 0, 450, 550, 625, EXPOSURE_MAX };
573 523
574 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) { 524 for (i = 0; i < ARRAY_SIZE(table) - 1; i++) {
575 if (sd->exposure <= table[i + 1]) { 525 if (val <= table[i + 1]) {
576 expo = sd->exposure - table[i]; 526 expo = val - table[i];
577 if (i) 527 if (i)
578 expo += 300; 528 expo += 300;
579 expo |= i << 11; 529 expo |= i << 11;
@@ -587,29 +537,27 @@ static void setexposure(struct gspca_dev *gspca_dev)
587} 537}
588 538
589/* rev 12a only */ 539/* rev 12a only */
590static void setgain(struct gspca_dev *gspca_dev) 540static void setgain(struct gspca_dev *gspca_dev, s32 val)
591{ 541{
592 struct sd *sd = (struct sd *) gspca_dev;
593
594 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the 542 /* gain reg low 6 bits 0-63 gain, bit 6 and 7, both double the
595 sensitivity when set, so 31 + one of them set == 63, and 15 543 sensitivity when set, so 31 + one of them set == 63, and 15
596 with both of them set == 63 */ 544 with both of them set == 63 */
597 if (sd->gain < 64) 545 if (val < 64)
598 gspca_dev->usb_buf[0] = sd->gain; 546 gspca_dev->usb_buf[0] = val;
599 else if (sd->gain < 128) 547 else if (val < 128)
600 gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40; 548 gspca_dev->usb_buf[0] = (val / 2) | 0x40;
601 else 549 else
602 gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0; 550 gspca_dev->usb_buf[0] = (val / 4) | 0xc0;
603 551
604 gspca_dev->usb_buf[1] = 0; 552 gspca_dev->usb_buf[1] = 0;
605 reg_w_buf(gspca_dev, 0x8335, 2); 553 reg_w_buf(gspca_dev, 0x8335, 2);
606} 554}
607 555
608static void setautogain(struct gspca_dev *gspca_dev) 556static void setautogain(struct gspca_dev *gspca_dev, s32 val)
609{ 557{
610 struct sd *sd = (struct sd *) gspca_dev; 558 struct sd *sd = (struct sd *) gspca_dev;
611 559
612 if (sd->autogain) 560 if (val)
613 sd->ag_cnt = AG_CNT_START; 561 sd->ag_cnt = AG_CNT_START;
614 else 562 else
615 sd->ag_cnt = -1; 563 sd->ag_cnt = -1;
@@ -644,9 +592,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
644 memcpy(gspca_dev->usb_buf, Reg8391, 8); 592 memcpy(gspca_dev->usb_buf, Reg8391, 8);
645 reg_w_buf(gspca_dev, 0x8391, 8); 593 reg_w_buf(gspca_dev, 0x8391, 8);
646 reg_w_buf(gspca_dev, 0x8390, 8); 594 reg_w_buf(gspca_dev, 0x8390, 8);
647 setwhite(gspca_dev); 595 v4l2_ctrl_handler_setup(&gspca_dev->ctrl_handler);
648 setgain(gspca_dev);
649 setexposure(gspca_dev);
650 596
651 /* Led ON (bit 3 -> 0 */ 597 /* Led ON (bit 3 -> 0 */
652 reg_w_val(gspca_dev->dev, 0x8114, 0x00); 598 reg_w_val(gspca_dev->dev, 0x8114, 0x00);
@@ -654,6 +600,7 @@ static int sd_start_12a(struct gspca_dev *gspca_dev)
654} 600}
655static int sd_start_72a(struct gspca_dev *gspca_dev) 601static int sd_start_72a(struct gspca_dev *gspca_dev)
656{ 602{
603 struct sd *sd = (struct sd *) gspca_dev;
657 struct usb_device *dev = gspca_dev->dev; 604 struct usb_device *dev = gspca_dev->dev;
658 int Clck; 605 int Clck;
659 int mode; 606 int mode;
@@ -683,9 +630,10 @@ static int sd_start_72a(struct gspca_dev *gspca_dev)
683 reg_w_val(dev, 0x8702, 0x81); 630 reg_w_val(dev, 0x8702, 0x81);
684 reg_w_val(dev, 0x8500, mode); /* mode */ 631 reg_w_val(dev, 0x8500, mode); /* mode */
685 write_sensor_72a(gspca_dev, rev72a_init_sensor2); 632 write_sensor_72a(gspca_dev, rev72a_init_sensor2);
686 setcontrast(gspca_dev); 633 setwhite(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue),
634 v4l2_ctrl_g_ctrl(sd->contrast));
687/* setbrightness(gspca_dev); * fixme: bad values */ 635/* setbrightness(gspca_dev); * fixme: bad values */
688 setautogain(gspca_dev); 636 setautogain(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain));
689 reg_w_val(dev, 0x8112, 0x10 | 0x20); 637 reg_w_val(dev, 0x8112, 0x10 | 0x20);
690 return 0; 638 return 0;
691} 639}
@@ -819,221 +767,94 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
819 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 767 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
820} 768}
821 769
822/* rev 72a only */ 770static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
823static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
824{
825 struct sd *sd = (struct sd *) gspca_dev;
826
827 sd->brightness = val;
828 if (gspca_dev->streaming)
829 setbrightness(gspca_dev);
830 return 0;
831}
832
833static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
834{ 771{
835 struct sd *sd = (struct sd *) gspca_dev; 772 struct gspca_dev *gspca_dev =
773 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
774 struct sd *sd = (struct sd *)gspca_dev;
836 775
837 *val = sd->brightness; 776 gspca_dev->usb_err = 0;
838 return 0;
839}
840 777
841/* rev 72a only */ 778 if (!gspca_dev->streaming)
842static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) 779 return 0;
843{
844 struct sd *sd = (struct sd *) gspca_dev;
845 780
846 sd->contrast = val; 781 switch (ctrl->id) {
847 if (gspca_dev->streaming) 782 case V4L2_CID_BRIGHTNESS:
848 setcontrast(gspca_dev); 783 setbrightness(gspca_dev, ctrl->val);
849 return 0; 784 break;
850} 785 case V4L2_CID_CONTRAST:
851 786 /* hue/contrast control cluster for 72a */
852static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) 787 setwhite(gspca_dev, sd->hue->val, ctrl->val);
853{ 788 break;
854 struct sd *sd = (struct sd *) gspca_dev; 789 case V4L2_CID_HUE:
855 790 /* just plain hue control for 12a */
856 *val = sd->contrast; 791 setwhite(gspca_dev, ctrl->val, 0);
857 return 0; 792 break;
858} 793 case V4L2_CID_EXPOSURE:
859 794 setexposure(gspca_dev, ctrl->val);
860static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) 795 break;
861{ 796 case V4L2_CID_GAIN:
862 struct sd *sd = (struct sd *) gspca_dev; 797 setgain(gspca_dev, ctrl->val);
863 798 break;
864 sd->autogain = val; 799 case V4L2_CID_AUTOGAIN:
865 if (gspca_dev->streaming) 800 setautogain(gspca_dev, ctrl->val);
866 setautogain(gspca_dev); 801 break;
867 return 0; 802 }
868} 803 return gspca_dev->usb_err;
869
870static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
871{
872 struct sd *sd = (struct sd *) gspca_dev;
873
874 *val = sd->autogain;
875 return 0;
876}
877
878static int sd_setwhite(struct gspca_dev *gspca_dev, __s32 val)
879{
880 struct sd *sd = (struct sd *) gspca_dev;
881
882 sd->white = val;
883 if (gspca_dev->streaming)
884 setwhite(gspca_dev);
885 return 0;
886} 804}
887 805
888static int sd_getwhite(struct gspca_dev *gspca_dev, __s32 *val) 806static const struct v4l2_ctrl_ops sd_ctrl_ops = {
889{ 807 .s_ctrl = sd_s_ctrl,
890 struct sd *sd = (struct sd *) gspca_dev; 808};
891
892 *val = sd->white;
893 return 0;
894}
895 809
896/* rev12a only */ 810static int sd_init_controls_12a(struct gspca_dev *gspca_dev)
897static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
898{ 811{
899 struct sd *sd = (struct sd *) gspca_dev; 812 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
900 813
901 sd->exposure = val; 814 gspca_dev->vdev.ctrl_handler = hdl;
902 if (gspca_dev->streaming) 815 v4l2_ctrl_handler_init(hdl, 3);
903 setexposure(gspca_dev); 816 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
904 return 0; 817 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
905} 818 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
819 V4L2_CID_EXPOSURE, 1, EXPOSURE_MAX, 1, 700);
820 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
821 V4L2_CID_GAIN, 0, 255, 1, 63);
906 822
907static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) 823 if (hdl->error) {
908{ 824 pr_err("Could not initialize controls\n");
909 struct sd *sd = (struct sd *) gspca_dev; 825 return hdl->error;
910 826 }
911 *val = sd->exposure;
912 return 0; 827 return 0;
913} 828}
914 829
915/* rev12a only */ 830static int sd_init_controls_72a(struct gspca_dev *gspca_dev)
916static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
917{ 831{
918 struct sd *sd = (struct sd *) gspca_dev; 832 struct sd *sd = (struct sd *)gspca_dev;
919 833 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
920 sd->gain = val;
921 if (gspca_dev->streaming)
922 setgain(gspca_dev);
923 return 0;
924}
925 834
926static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) 835 gspca_dev->vdev.ctrl_handler = hdl;
927{ 836 v4l2_ctrl_handler_init(hdl, 4);
928 struct sd *sd = (struct sd *) gspca_dev; 837 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
838 V4L2_CID_CONTRAST, 0, 0x3f, 1, 0x20);
839 sd->hue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
840 V4L2_CID_HUE, 1, 0x7f, 1, 0x40);
841 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
842 V4L2_CID_BRIGHTNESS, 0, 0x3f, 1, 0x20);
843 sd->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
844 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
929 845
930 *val = sd->gain; 846 if (hdl->error) {
847 pr_err("Could not initialize controls\n");
848 return hdl->error;
849 }
850 v4l2_ctrl_cluster(2, &sd->contrast);
931 return 0; 851 return 0;
932} 852}
933 853
934/* control tables */
935static const struct ctrl sd_ctrls_12a[] = {
936 {
937 {
938 .id = V4L2_CID_HUE,
939 .type = V4L2_CTRL_TYPE_INTEGER,
940 .name = "Hue",
941 .minimum = HUE_MIN,
942 .maximum = HUE_MAX,
943 .step = 1,
944 .default_value = HUE_DEF,
945 },
946 .set = sd_setwhite,
947 .get = sd_getwhite,
948 },
949 {
950 {
951 .id = V4L2_CID_EXPOSURE,
952 .type = V4L2_CTRL_TYPE_INTEGER,
953 .name = "Exposure",
954 .minimum = EXPOSURE_MIN,
955 .maximum = EXPOSURE_MAX,
956 .step = 1,
957 .default_value = EXPOSURE_DEF,
958 },
959 .set = sd_setexposure,
960 .get = sd_getexposure,
961 },
962 {
963 {
964 .id = V4L2_CID_GAIN,
965 .type = V4L2_CTRL_TYPE_INTEGER,
966 .name = "Gain",
967 .minimum = GAIN_MIN,
968 .maximum = GAIN_MAX,
969 .step = 1,
970 .default_value = GAIN_DEF,
971 },
972 .set = sd_setgain,
973 .get = sd_getgain,
974 },
975};
976
977static const struct ctrl sd_ctrls_72a[] = {
978 {
979 {
980 .id = V4L2_CID_HUE,
981 .type = V4L2_CTRL_TYPE_INTEGER,
982 .name = "Hue",
983 .minimum = HUE_MIN,
984 .maximum = HUE_MAX,
985 .step = 1,
986 .default_value = HUE_DEF,
987 },
988 .set = sd_setwhite,
989 .get = sd_getwhite,
990 },
991 {
992 {
993 .id = V4L2_CID_BRIGHTNESS,
994 .type = V4L2_CTRL_TYPE_INTEGER,
995 .name = "Brightness",
996 .minimum = BRIGHTNESS_MIN,
997 .maximum = BRIGHTNESS_MAX,
998 .step = 1,
999 .default_value = BRIGHTNESS_DEF,
1000 },
1001 .set = sd_setbrightness,
1002 .get = sd_getbrightness,
1003 },
1004 {
1005 {
1006 .id = V4L2_CID_CONTRAST,
1007 .type = V4L2_CTRL_TYPE_INTEGER,
1008 .name = "Contrast",
1009 .minimum = CONTRAST_MIN,
1010 .maximum = CONTRAST_MAX,
1011 .step = 1,
1012 .default_value = CONTRAST_DEF,
1013 },
1014 .set = sd_setcontrast,
1015 .get = sd_getcontrast,
1016 },
1017 {
1018 {
1019 .id = V4L2_CID_AUTOGAIN,
1020 .type = V4L2_CTRL_TYPE_BOOLEAN,
1021 .name = "Auto Gain",
1022 .minimum = AUTOGAIN_MIN,
1023 .maximum = AUTOGAIN_MAX,
1024 .step = 1,
1025 .default_value = AUTOGAIN_DEF,
1026 },
1027 .set = sd_setautogain,
1028 .get = sd_getautogain,
1029 },
1030};
1031
1032/* sub-driver description */ 854/* sub-driver description */
1033static const struct sd_desc sd_desc_12a = { 855static const struct sd_desc sd_desc_12a = {
1034 .name = MODULE_NAME, 856 .name = MODULE_NAME,
1035 .ctrls = sd_ctrls_12a, 857 .init_controls = sd_init_controls_12a,
1036 .nctrls = ARRAY_SIZE(sd_ctrls_12a),
1037 .config = sd_config, 858 .config = sd_config,
1038 .init = sd_init_12a, 859 .init = sd_init_12a,
1039 .start = sd_start_12a, 860 .start = sd_start_12a,
@@ -1045,8 +866,7 @@ static const struct sd_desc sd_desc_12a = {
1045}; 866};
1046static const struct sd_desc sd_desc_72a = { 867static const struct sd_desc sd_desc_72a = {
1047 .name = MODULE_NAME, 868 .name = MODULE_NAME,
1048 .ctrls = sd_ctrls_72a, 869 .init_controls = sd_init_controls_72a,
1049 .nctrls = ARRAY_SIZE(sd_ctrls_72a),
1050 .config = sd_config, 870 .config = sd_config,
1051 .init = sd_init_72a, 871 .init = sd_init_72a,
1052 .start = sd_start_72a, 872 .start = sd_start_72a,