root/arch/x86/platform/olpc/olpc-xo1-sci.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. battery_status_changed
  2. ac_status_changed
  3. send_ebook_state
  4. flip_lid_inverter
  5. detect_lid_state
  6. send_lid_state
  7. lid_wake_mode_show
  8. lid_wake_mode_set
  9. process_sci_queue
  10. process_sci_queue_work
  11. xo1_sci_intr
  12. xo1_sci_suspend
  13. xo1_sci_resume
  14. setup_sci_interrupt
  15. setup_ec_sci
  16. free_ec_sci
  17. setup_lid_events
  18. free_lid_events
  19. setup_power_button
  20. free_power_button
  21. setup_ebook_switch
  22. free_ebook_switch
  23. setup_lid_switch
  24. free_lid_switch
  25. xo1_sci_probe
  26. xo1_sci_remove
  27. xo1_sci_init

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Support for OLPC XO-1 System Control Interrupts (SCI)
   4  *
   5  * Copyright (C) 2010 One Laptop per Child
   6  * Copyright (C) 2006 Red Hat, Inc.
   7  * Copyright (C) 2006 Advanced Micro Devices, Inc.
   8  */
   9 
  10 #include <linux/cs5535.h>
  11 #include <linux/device.h>
  12 #include <linux/gpio.h>
  13 #include <linux/input.h>
  14 #include <linux/interrupt.h>
  15 #include <linux/platform_device.h>
  16 #include <linux/pm.h>
  17 #include <linux/pm_wakeup.h>
  18 #include <linux/mfd/core.h>
  19 #include <linux/power_supply.h>
  20 #include <linux/suspend.h>
  21 #include <linux/workqueue.h>
  22 #include <linux/olpc-ec.h>
  23 
  24 #include <asm/io.h>
  25 #include <asm/msr.h>
  26 #include <asm/olpc.h>
  27 
  28 #define DRV_NAME        "olpc-xo1-sci"
  29 #define PFX             DRV_NAME ": "
  30 
  31 static unsigned long acpi_base;
  32 static struct input_dev *power_button_idev;
  33 static struct input_dev *ebook_switch_idev;
  34 static struct input_dev *lid_switch_idev;
  35 
  36 static int sci_irq;
  37 
  38 static bool lid_open;
  39 static bool lid_inverted;
  40 static int lid_wake_mode;
  41 
  42 enum lid_wake_modes {
  43         LID_WAKE_ALWAYS,
  44         LID_WAKE_OPEN,
  45         LID_WAKE_CLOSE,
  46 };
  47 
  48 static const char * const lid_wake_mode_names[] = {
  49         [LID_WAKE_ALWAYS] = "always",
  50         [LID_WAKE_OPEN] = "open",
  51         [LID_WAKE_CLOSE] = "close",
  52 };
  53 
  54 static void battery_status_changed(void)
  55 {
  56         struct power_supply *psy = power_supply_get_by_name("olpc-battery");
  57 
  58         if (psy) {
  59                 power_supply_changed(psy);
  60                 power_supply_put(psy);
  61         }
  62 }
  63 
  64 static void ac_status_changed(void)
  65 {
  66         struct power_supply *psy = power_supply_get_by_name("olpc-ac");
  67 
  68         if (psy) {
  69                 power_supply_changed(psy);
  70                 power_supply_put(psy);
  71         }
  72 }
  73 
  74 /* Report current ebook switch state through input layer */
  75 static void send_ebook_state(void)
  76 {
  77         unsigned char state;
  78 
  79         if (olpc_ec_cmd(EC_READ_EB_MODE, NULL, 0, &state, 1)) {
  80                 pr_err(PFX "failed to get ebook state\n");
  81                 return;
  82         }
  83 
  84         if (!!test_bit(SW_TABLET_MODE, ebook_switch_idev->sw) == state)
  85                 return; /* Nothing new to report. */
  86 
  87         input_report_switch(ebook_switch_idev, SW_TABLET_MODE, state);
  88         input_sync(ebook_switch_idev);
  89         pm_wakeup_event(&ebook_switch_idev->dev, 0);
  90 }
  91 
  92 static void flip_lid_inverter(void)
  93 {
  94         /* gpio is high; invert so we'll get l->h event interrupt */
  95         if (lid_inverted)
  96                 cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_INPUT_INVERT);
  97         else
  98                 cs5535_gpio_set(OLPC_GPIO_LID, GPIO_INPUT_INVERT);
  99         lid_inverted = !lid_inverted;
 100 }
 101 
 102 static void detect_lid_state(void)
 103 {
 104         /*
 105          * the edge detector hookup on the gpio inputs on the geode is
 106          * odd, to say the least.  See http://dev.laptop.org/ticket/5703
 107          * for details, but in a nutshell:  we don't use the edge
 108          * detectors.  instead, we make use of an anomaly:  with the both
 109          * edge detectors turned off, we still get an edge event on a
 110          * positive edge transition.  to take advantage of this, we use the
 111          * front-end inverter to ensure that that's the edge we're always
 112          * going to see next.
 113          */
 114 
 115         int state;
 116 
 117         state = cs5535_gpio_isset(OLPC_GPIO_LID, GPIO_READ_BACK);
 118         lid_open = !state ^ !lid_inverted; /* x ^^ y */
 119         if (!state)
 120                 return;
 121 
 122         flip_lid_inverter();
 123 }
 124 
 125 /* Report current lid switch state through input layer */
 126 static void send_lid_state(void)
 127 {
 128         if (!!test_bit(SW_LID, lid_switch_idev->sw) == !lid_open)
 129                 return; /* Nothing new to report. */
 130 
 131         input_report_switch(lid_switch_idev, SW_LID, !lid_open);
 132         input_sync(lid_switch_idev);
 133         pm_wakeup_event(&lid_switch_idev->dev, 0);
 134 }
 135 
 136 static ssize_t lid_wake_mode_show(struct device *dev,
 137                                   struct device_attribute *attr, char *buf)
 138 {
 139         const char *mode = lid_wake_mode_names[lid_wake_mode];
 140         return sprintf(buf, "%s\n", mode);
 141 }
 142 static ssize_t lid_wake_mode_set(struct device *dev,
 143                                  struct device_attribute *attr,
 144                                  const char *buf, size_t count)
 145 {
 146         int i;
 147         for (i = 0; i < ARRAY_SIZE(lid_wake_mode_names); i++) {
 148                 const char *mode = lid_wake_mode_names[i];
 149                 if (strlen(mode) != count || strncasecmp(mode, buf, count))
 150                         continue;
 151 
 152                 lid_wake_mode = i;
 153                 return count;
 154         }
 155         return -EINVAL;
 156 }
 157 static DEVICE_ATTR(lid_wake_mode, S_IWUSR | S_IRUGO, lid_wake_mode_show,
 158                    lid_wake_mode_set);
 159 
 160 static struct attribute *lid_attrs[] = {
 161         &dev_attr_lid_wake_mode.attr,
 162         NULL,
 163 };
 164 ATTRIBUTE_GROUPS(lid);
 165 
 166 /*
 167  * Process all items in the EC's SCI queue.
 168  *
 169  * This is handled in a workqueue because olpc_ec_cmd can be slow (and
 170  * can even timeout).
 171  *
 172  * If propagate_events is false, the queue is drained without events being
 173  * generated for the interrupts.
 174  */
 175 static void process_sci_queue(bool propagate_events)
 176 {
 177         int r;
 178         u16 data;
 179 
 180         do {
 181                 r = olpc_ec_sci_query(&data);
 182                 if (r || !data)
 183                         break;
 184 
 185                 pr_debug(PFX "SCI 0x%x received\n", data);
 186 
 187                 switch (data) {
 188                 case EC_SCI_SRC_BATERR:
 189                 case EC_SCI_SRC_BATSOC:
 190                 case EC_SCI_SRC_BATTERY:
 191                 case EC_SCI_SRC_BATCRIT:
 192                         battery_status_changed();
 193                         break;
 194                 case EC_SCI_SRC_ACPWR:
 195                         ac_status_changed();
 196                         break;
 197                 }
 198 
 199                 if (data == EC_SCI_SRC_EBOOK && propagate_events)
 200                         send_ebook_state();
 201         } while (data);
 202 
 203         if (r)
 204                 pr_err(PFX "Failed to clear SCI queue");
 205 }
 206 
 207 static void process_sci_queue_work(struct work_struct *work)
 208 {
 209         process_sci_queue(true);
 210 }
 211 
 212 static DECLARE_WORK(sci_work, process_sci_queue_work);
 213 
 214 static irqreturn_t xo1_sci_intr(int irq, void *dev_id)
 215 {
 216         struct platform_device *pdev = dev_id;
 217         u32 sts;
 218         u32 gpe;
 219 
 220         sts = inl(acpi_base + CS5536_PM1_STS);
 221         outl(sts | 0xffff, acpi_base + CS5536_PM1_STS);
 222 
 223         gpe = inl(acpi_base + CS5536_PM_GPE0_STS);
 224         outl(0xffffffff, acpi_base + CS5536_PM_GPE0_STS);
 225 
 226         dev_dbg(&pdev->dev, "sts %x gpe %x\n", sts, gpe);
 227 
 228         if (sts & CS5536_PWRBTN_FLAG) {
 229                 if (!(sts & CS5536_WAK_FLAG)) {
 230                         /* Only report power button input when it was pressed
 231                          * during regular operation (as opposed to when it
 232                          * was used to wake the system). */
 233                         input_report_key(power_button_idev, KEY_POWER, 1);
 234                         input_sync(power_button_idev);
 235                         input_report_key(power_button_idev, KEY_POWER, 0);
 236                         input_sync(power_button_idev);
 237                 }
 238                 /* Report the wakeup event in all cases. */
 239                 pm_wakeup_event(&power_button_idev->dev, 0);
 240         }
 241 
 242         if ((sts & (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) ==
 243                         (CS5536_RTC_FLAG | CS5536_WAK_FLAG)) {
 244                 /* When the system is woken by the RTC alarm, report the
 245                  * event on the rtc device. */
 246                 struct device *rtc = bus_find_device_by_name(
 247                         &platform_bus_type, NULL, "rtc_cmos");
 248                 if (rtc) {
 249                         pm_wakeup_event(rtc, 0);
 250                         put_device(rtc);
 251                 }
 252         }
 253 
 254         if (gpe & CS5536_GPIOM7_PME_FLAG) { /* EC GPIO */
 255                 cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
 256                 schedule_work(&sci_work);
 257         }
 258 
 259         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
 260         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
 261         detect_lid_state();
 262         send_lid_state();
 263 
 264         return IRQ_HANDLED;
 265 }
 266 
 267 static int xo1_sci_suspend(struct platform_device *pdev, pm_message_t state)
 268 {
 269         if (device_may_wakeup(&power_button_idev->dev))
 270                 olpc_xo1_pm_wakeup_set(CS5536_PM_PWRBTN);
 271         else
 272                 olpc_xo1_pm_wakeup_clear(CS5536_PM_PWRBTN);
 273 
 274         if (device_may_wakeup(&ebook_switch_idev->dev))
 275                 olpc_ec_wakeup_set(EC_SCI_SRC_EBOOK);
 276         else
 277                 olpc_ec_wakeup_clear(EC_SCI_SRC_EBOOK);
 278 
 279         if (!device_may_wakeup(&lid_switch_idev->dev)) {
 280                 cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
 281         } else if ((lid_open && lid_wake_mode == LID_WAKE_OPEN) ||
 282                    (!lid_open && lid_wake_mode == LID_WAKE_CLOSE)) {
 283                 flip_lid_inverter();
 284 
 285                 /* we may have just caused an event */
 286                 cs5535_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
 287                 cs5535_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
 288 
 289                 cs5535_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
 290         }
 291 
 292         return 0;
 293 }
 294 
 295 static int xo1_sci_resume(struct platform_device *pdev)
 296 {
 297         /*
 298          * We don't know what may have happened while we were asleep.
 299          * Reestablish our lid setup so we're sure to catch all transitions.
 300          */
 301         detect_lid_state();
 302         send_lid_state();
 303         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
 304 
 305         /* Enable all EC events */
 306         olpc_ec_mask_write(EC_SCI_SRC_ALL);
 307 
 308         /* Power/battery status might have changed too */
 309         battery_status_changed();
 310         ac_status_changed();
 311         return 0;
 312 }
 313 
 314 static int setup_sci_interrupt(struct platform_device *pdev)
 315 {
 316         u32 lo, hi;
 317         u32 sts;
 318         int r;
 319 
 320         rdmsr(0x51400020, lo, hi);
 321         sci_irq = (lo >> 20) & 15;
 322 
 323         if (sci_irq) {
 324                 dev_info(&pdev->dev, "SCI is mapped to IRQ %d\n", sci_irq);
 325         } else {
 326                 /* Zero means masked */
 327                 dev_info(&pdev->dev, "SCI unmapped. Mapping to IRQ 3\n");
 328                 sci_irq = 3;
 329                 lo |= 0x00300000;
 330                 wrmsrl(0x51400020, lo);
 331         }
 332 
 333         /* Select level triggered in PIC */
 334         if (sci_irq < 8) {
 335                 lo = inb(CS5536_PIC_INT_SEL1);
 336                 lo |= 1 << sci_irq;
 337                 outb(lo, CS5536_PIC_INT_SEL1);
 338         } else {
 339                 lo = inb(CS5536_PIC_INT_SEL2);
 340                 lo |= 1 << (sci_irq - 8);
 341                 outb(lo, CS5536_PIC_INT_SEL2);
 342         }
 343 
 344         /* Enable interesting SCI events, and clear pending interrupts */
 345         sts = inl(acpi_base + CS5536_PM1_STS);
 346         outl(((CS5536_PM_PWRBTN | CS5536_PM_RTC) << 16) | 0xffff,
 347              acpi_base + CS5536_PM1_STS);
 348 
 349         r = request_irq(sci_irq, xo1_sci_intr, 0, DRV_NAME, pdev);
 350         if (r)
 351                 dev_err(&pdev->dev, "can't request interrupt\n");
 352 
 353         return r;
 354 }
 355 
 356 static int setup_ec_sci(void)
 357 {
 358         int r;
 359 
 360         r = gpio_request(OLPC_GPIO_ECSCI, "OLPC-ECSCI");
 361         if (r)
 362                 return r;
 363 
 364         gpio_direction_input(OLPC_GPIO_ECSCI);
 365 
 366         /* Clear pending EC SCI events */
 367         cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_NEGATIVE_EDGE_STS);
 368         cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_POSITIVE_EDGE_STS);
 369 
 370         /*
 371          * Enable EC SCI events, and map them to both a PME and the SCI
 372          * interrupt.
 373          *
 374          * Ordinarily, in addition to functioning as GPIOs, Geode GPIOs can
 375          * be mapped to regular interrupts *or* Geode-specific Power
 376          * Management Events (PMEs) - events that bring the system out of
 377          * suspend. In this case, we want both of those things - the system
 378          * wakeup, *and* the ability to get an interrupt when an event occurs.
 379          *
 380          * To achieve this, we map the GPIO to a PME, and then we use one
 381          * of the many generic knobs on the CS5535 PIC to additionally map the
 382          * PME to the regular SCI interrupt line.
 383          */
 384         cs5535_gpio_set(OLPC_GPIO_ECSCI, GPIO_EVENTS_ENABLE);
 385 
 386         /* Set the SCI to cause a PME event on group 7 */
 387         cs5535_gpio_setup_event(OLPC_GPIO_ECSCI, 7, 1);
 388 
 389         /* And have group 7 also fire the SCI interrupt */
 390         cs5535_pic_unreqz_select_high(7, sci_irq);
 391 
 392         return 0;
 393 }
 394 
 395 static void free_ec_sci(void)
 396 {
 397         gpio_free(OLPC_GPIO_ECSCI);
 398 }
 399 
 400 static int setup_lid_events(void)
 401 {
 402         int r;
 403 
 404         r = gpio_request(OLPC_GPIO_LID, "OLPC-LID");
 405         if (r)
 406                 return r;
 407 
 408         gpio_direction_input(OLPC_GPIO_LID);
 409 
 410         cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_INPUT_INVERT);
 411         lid_inverted = 0;
 412 
 413         /* Clear edge detection and event enable for now */
 414         cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
 415         cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_EN);
 416         cs5535_gpio_clear(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_EN);
 417         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_NEGATIVE_EDGE_STS);
 418         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_POSITIVE_EDGE_STS);
 419 
 420         /* Set the LID to cause an PME event on group 6 */
 421         cs5535_gpio_setup_event(OLPC_GPIO_LID, 6, 1);
 422 
 423         /* Set PME group 6 to fire the SCI interrupt */
 424         cs5535_gpio_set_irq(6, sci_irq);
 425 
 426         /* Enable the event */
 427         cs5535_gpio_set(OLPC_GPIO_LID, GPIO_EVENTS_ENABLE);
 428 
 429         return 0;
 430 }
 431 
 432 static void free_lid_events(void)
 433 {
 434         gpio_free(OLPC_GPIO_LID);
 435 }
 436 
 437 static int setup_power_button(struct platform_device *pdev)
 438 {
 439         int r;
 440 
 441         power_button_idev = input_allocate_device();
 442         if (!power_button_idev)
 443                 return -ENOMEM;
 444 
 445         power_button_idev->name = "Power Button";
 446         power_button_idev->phys = DRV_NAME "/input0";
 447         set_bit(EV_KEY, power_button_idev->evbit);
 448         set_bit(KEY_POWER, power_button_idev->keybit);
 449 
 450         power_button_idev->dev.parent = &pdev->dev;
 451         device_init_wakeup(&power_button_idev->dev, 1);
 452 
 453         r = input_register_device(power_button_idev);
 454         if (r) {
 455                 dev_err(&pdev->dev, "failed to register power button: %d\n", r);
 456                 input_free_device(power_button_idev);
 457         }
 458 
 459         return r;
 460 }
 461 
 462 static void free_power_button(void)
 463 {
 464         input_unregister_device(power_button_idev);
 465 }
 466 
 467 static int setup_ebook_switch(struct platform_device *pdev)
 468 {
 469         int r;
 470 
 471         ebook_switch_idev = input_allocate_device();
 472         if (!ebook_switch_idev)
 473                 return -ENOMEM;
 474 
 475         ebook_switch_idev->name = "EBook Switch";
 476         ebook_switch_idev->phys = DRV_NAME "/input1";
 477         set_bit(EV_SW, ebook_switch_idev->evbit);
 478         set_bit(SW_TABLET_MODE, ebook_switch_idev->swbit);
 479 
 480         ebook_switch_idev->dev.parent = &pdev->dev;
 481         device_set_wakeup_capable(&ebook_switch_idev->dev, true);
 482 
 483         r = input_register_device(ebook_switch_idev);
 484         if (r) {
 485                 dev_err(&pdev->dev, "failed to register ebook switch: %d\n", r);
 486                 input_free_device(ebook_switch_idev);
 487         }
 488 
 489         return r;
 490 }
 491 
 492 static void free_ebook_switch(void)
 493 {
 494         input_unregister_device(ebook_switch_idev);
 495 }
 496 
 497 static int setup_lid_switch(struct platform_device *pdev)
 498 {
 499         int r;
 500 
 501         lid_switch_idev = input_allocate_device();
 502         if (!lid_switch_idev)
 503                 return -ENOMEM;
 504 
 505         lid_switch_idev->name = "Lid Switch";
 506         lid_switch_idev->phys = DRV_NAME "/input2";
 507         set_bit(EV_SW, lid_switch_idev->evbit);
 508         set_bit(SW_LID, lid_switch_idev->swbit);
 509 
 510         lid_switch_idev->dev.parent = &pdev->dev;
 511         device_set_wakeup_capable(&lid_switch_idev->dev, true);
 512 
 513         r = input_register_device(lid_switch_idev);
 514         if (r) {
 515                 dev_err(&pdev->dev, "failed to register lid switch: %d\n", r);
 516                 goto err_register;
 517         }
 518 
 519         return 0;
 520 
 521 err_register:
 522         input_free_device(lid_switch_idev);
 523         return r;
 524 }
 525 
 526 static void free_lid_switch(void)
 527 {
 528         input_unregister_device(lid_switch_idev);
 529 }
 530 
 531 static int xo1_sci_probe(struct platform_device *pdev)
 532 {
 533         struct resource *res;
 534         int r;
 535 
 536         /* don't run on non-XOs */
 537         if (!machine_is_olpc())
 538                 return -ENODEV;
 539 
 540         r = mfd_cell_enable(pdev);
 541         if (r)
 542                 return r;
 543 
 544         res = platform_get_resource(pdev, IORESOURCE_IO, 0);
 545         if (!res) {
 546                 dev_err(&pdev->dev, "can't fetch device resource info\n");
 547                 return -EIO;
 548         }
 549         acpi_base = res->start;
 550 
 551         r = setup_power_button(pdev);
 552         if (r)
 553                 return r;
 554 
 555         r = setup_ebook_switch(pdev);
 556         if (r)
 557                 goto err_ebook;
 558 
 559         r = setup_lid_switch(pdev);
 560         if (r)
 561                 goto err_lid;
 562 
 563         r = setup_lid_events();
 564         if (r)
 565                 goto err_lidevt;
 566 
 567         r = setup_ec_sci();
 568         if (r)
 569                 goto err_ecsci;
 570 
 571         /* Enable PME generation for EC-generated events */
 572         outl(CS5536_GPIOM6_PME_EN | CS5536_GPIOM7_PME_EN,
 573                 acpi_base + CS5536_PM_GPE0_EN);
 574 
 575         /* Clear pending events */
 576         outl(0xffffffff, acpi_base + CS5536_PM_GPE0_STS);
 577         process_sci_queue(false);
 578 
 579         /* Initial sync */
 580         send_ebook_state();
 581         detect_lid_state();
 582         send_lid_state();
 583 
 584         r = setup_sci_interrupt(pdev);
 585         if (r)
 586                 goto err_sci;
 587 
 588         /* Enable all EC events */
 589         olpc_ec_mask_write(EC_SCI_SRC_ALL);
 590 
 591         return r;
 592 
 593 err_sci:
 594         free_ec_sci();
 595 err_ecsci:
 596         free_lid_events();
 597 err_lidevt:
 598         free_lid_switch();
 599 err_lid:
 600         free_ebook_switch();
 601 err_ebook:
 602         free_power_button();
 603         return r;
 604 }
 605 
 606 static int xo1_sci_remove(struct platform_device *pdev)
 607 {
 608         mfd_cell_disable(pdev);
 609         free_irq(sci_irq, pdev);
 610         cancel_work_sync(&sci_work);
 611         free_ec_sci();
 612         free_lid_events();
 613         free_lid_switch();
 614         free_ebook_switch();
 615         free_power_button();
 616         acpi_base = 0;
 617         return 0;
 618 }
 619 
 620 static struct platform_driver xo1_sci_driver = {
 621         .driver = {
 622                 .name = "olpc-xo1-sci-acpi",
 623                 .dev_groups = lid_groups,
 624         },
 625         .probe = xo1_sci_probe,
 626         .remove = xo1_sci_remove,
 627         .suspend = xo1_sci_suspend,
 628         .resume = xo1_sci_resume,
 629 };
 630 
 631 static int __init xo1_sci_init(void)
 632 {
 633         return platform_driver_register(&xo1_sci_driver);
 634 }
 635 arch_initcall(xo1_sci_init);

/* [<][>][^][v][top][bottom][index][help] */