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