b24413180f560 (Greg Kroah-Hartman 2017-11-01 15:07:57 +0100 1) // SPDX-License-Identifier: GPL-2.0
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2) /*
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 3) * Device driver for the PMU in Apple PowerBooks and PowerMacs.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 4) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 5) * The VIA (versatile interface adapter) interfaces to the PMU,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 6) * a 6805 microprocessor core whose primary function is to control
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 7) * battery charging and system power on the PowerBook 3400 and 2400.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 8) * The PMU also controls the ADB (Apple Desktop Bus) which connects
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 9) * to the keyboard and mouse, as well as the non-volatile RAM
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 10) * and the RTC (real time clock) chip.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 11) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 12) * Copyright (C) 1998 Paul Mackerras and Fabio Riccardi.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 13) * Copyright (C) 2001-2002 Benjamin Herrenschmidt
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 14) * Copyright (C) 2006-2007 Johannes Berg
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 15) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 16) * THIS DRIVER IS BECOMING A TOTAL MESS !
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 17) * - Cleanup atomically disabling reply to PMU events after
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 18) * a sleep or a freq. switch
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 19) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 20) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 21) #include <stdarg.h>
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 22) #include <linux/mutex.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 23) #include <linux/types.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 24) #include <linux/errno.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 25) #include <linux/kernel.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 26) #include <linux/delay.h>
174cd4b1e5fbd (Ingo Molnar 2017-02-02 19:15:33 +0100 27) #include <linux/sched/signal.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 28) #include <linux/miscdevice.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 29) #include <linux/blkdev.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 30) #include <linux/pci.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 31) #include <linux/slab.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 32) #include <linux/poll.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 33) #include <linux/adb.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 34) #include <linux/pmu.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 35) #include <linux/cuda.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 36) #include <linux/module.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 37) #include <linux/spinlock.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 38) #include <linux/pm.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 39) #include <linux/proc_fs.h>
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 40) #include <linux/seq_file.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 41) #include <linux/init.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 42) #include <linux/interrupt.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 43) #include <linux/device.h>
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 44) #include <linux/syscore_ops.h>
7dfb71030f763 (Nigel Cunningham 2006-12-06 20:34:23 -0800 45) #include <linux/freezer.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 46) #include <linux/syscalls.h>
6002f544c9f72 (Dave Jones 2007-01-05 16:36:18 -0800 47) #include <linux/suspend.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 48) #include <linux/cpu.h>
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 49) #include <linux/compat.h>
5af5073004071 (Rob Herring 2013-09-17 14:28:33 -0500 50) #include <linux/of_address.h>
5af5073004071 (Rob Herring 2013-09-17 14:28:33 -0500 51) #include <linux/of_irq.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 52) #include <linux/uaccess.h>
65fddcfca8ad1 (Mike Rapoport 2020-06-08 21:32:42 -0700 53) #include <linux/pgtable.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 54) #include <asm/machdep.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 55) #include <asm/io.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 56) #include <asm/sections.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 57) #include <asm/irq.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 58) #ifdef CONFIG_PPC_PMAC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 59) #include <asm/pmac_feature.h>
5b9ca526917b7 (Benjamin Herrenschmidt 2006-01-07 11:41:02 +1100 60) #include <asm/pmac_pfunc.h>
5b9ca526917b7 (Benjamin Herrenschmidt 2006-01-07 11:41:02 +1100 61) #include <asm/pmac_low_i2c.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 62) #include <asm/prom.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 63) #include <asm/mmu_context.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 64) #include <asm/cputable.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 65) #include <asm/time.h>
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 66) #include <asm/backlight.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 67) #else
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 68) #include <asm/macintosh.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 69) #include <asm/macints.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 70) #include <asm/mac_via.h>
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 71) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 72)
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 73) #include "via-pmu-event.h"
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 74)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 75) /* Some compile options */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 76) #undef DEBUG_SLEEP
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 77)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 78) /* How many iterations between battery polls */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 79) #define BATTERY_POLLING_COUNT 2
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 80)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 81) static DEFINE_MUTEX(pmu_info_proc_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 82)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 83) /* VIA registers - spaced 0x200 bytes apart */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 84) #define RS 0x200 /* skip between registers */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 85) #define B 0 /* B-side data */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 86) #define A RS /* A-side data */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 87) #define DIRB (2*RS) /* B-side direction (1=output) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 88) #define DIRA (3*RS) /* A-side direction (1=output) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 89) #define T1CL (4*RS) /* Timer 1 ctr/latch (low 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 90) #define T1CH (5*RS) /* Timer 1 counter (high 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 91) #define T1LL (6*RS) /* Timer 1 latch (low 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 92) #define T1LH (7*RS) /* Timer 1 latch (high 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 93) #define T2CL (8*RS) /* Timer 2 ctr/latch (low 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 94) #define T2CH (9*RS) /* Timer 2 counter (high 8 bits) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 95) #define SR (10*RS) /* Shift register */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 96) #define ACR (11*RS) /* Auxiliary control register */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 97) #define PCR (12*RS) /* Peripheral control register */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 98) #define IFR (13*RS) /* Interrupt flag register */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 99) #define IER (14*RS) /* Interrupt enable register */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 100) #define ANH (15*RS) /* A-side data, no handshake */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 101)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 102) /* Bits in B data register: both active low */
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 103) #ifdef CONFIG_PPC_PMAC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 104) #define TACK 0x08 /* Transfer acknowledge (input) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 105) #define TREQ 0x10 /* Transfer request (output) */
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 106) #else
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 107) #define TACK 0x02
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 108) #define TREQ 0x04
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 109) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 110)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 111) /* Bits in ACR */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 112) #define SR_CTRL 0x1c /* Shift register control bits */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 113) #define SR_EXT 0x0c /* Shift on external clock */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 114) #define SR_OUT 0x10 /* Shift out if 1 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 115)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 116) /* Bits in IFR and IER */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 117) #define IER_SET 0x80 /* set bits in IER */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 118) #define IER_CLR 0 /* clear bits in IER */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 119) #define SR_INT 0x04 /* Shift register full/empty */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 120) #define CB2_INT 0x08
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 121) #define CB1_INT 0x10 /* transition on CB1 input */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 122)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 123) static volatile enum pmu_state {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 124) uninitialized = 0,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 125) idle,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 126) sending,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 127) intack,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 128) reading,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 129) reading_intr,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 130) locked,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 131) } pmu_state;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 132)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 133) static volatile enum int_data_state {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 134) int_data_empty,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 135) int_data_fill,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 136) int_data_ready,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 137) int_data_flush
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 138) } int_data_state[2] = { int_data_empty, int_data_empty };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 139)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 140) static struct adb_request *current_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 141) static struct adb_request *last_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 142) static struct adb_request *req_awaiting_reply;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 143) static unsigned char interrupt_data[2][32];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 144) static int interrupt_data_len[2];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 145) static int int_data_last;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 146) static unsigned char *reply_ptr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 147) static int data_index;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 148) static int data_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 149) static volatile int adb_int_pending;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 150) static volatile int disable_poll;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 151) static int pmu_kind = PMU_UNKNOWN;
872758563d7f1 (Olaf Hering 2007-02-10 21:35:12 +0100 152) static int pmu_fully_inited;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 153) static int pmu_has_adb;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 154) #ifdef CONFIG_PPC_PMAC
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 155) static volatile unsigned char __iomem *via1;
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 156) static volatile unsigned char __iomem *via2;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 157) static struct device_node *vias;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 158) static struct device_node *gpio_node;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 159) #endif
872758563d7f1 (Olaf Hering 2007-02-10 21:35:12 +0100 160) static unsigned char __iomem *gpio_reg;
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 161) static int gpio_irq = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 162) static int gpio_irq_enabled = -1;
872758563d7f1 (Olaf Hering 2007-02-10 21:35:12 +0100 163) static volatile int pmu_suspended;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 164) static spinlock_t pmu_lock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 165) static u8 pmu_intr_mask;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 166) static int pmu_version;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 167) static int drop_interrupts;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 168) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 169) static int option_lid_wakeup = 1;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 170) #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 171) static unsigned long async_req_locks;
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 172)
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 173) #define NUM_IRQ_STATS 13
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 174) static unsigned int pmu_irq_stats[NUM_IRQ_STATS];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 175)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 176) static struct proc_dir_entry *proc_pmu_root;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 177) static struct proc_dir_entry *proc_pmu_info;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 178) static struct proc_dir_entry *proc_pmu_irqstats;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 179) static struct proc_dir_entry *proc_pmu_options;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 180) static int option_server_mode;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 181)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 182) int pmu_battery_count;
95d143923379f (Yu Kuai 2021-04-07 20:58:03 +0800 183) static int pmu_cur_battery;
a334bdbdda965 (Olaf Hering 2007-02-10 21:40:00 +0100 184) unsigned int pmu_power_flags = PMU_PWR_AC_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 185) struct pmu_battery_info pmu_batteries[PMU_MAX_BATTERIES];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 186) static int query_batt_timer = BATTERY_POLLING_COUNT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 187) static struct adb_request batt_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 188) static struct proc_dir_entry *proc_pmu_batt[PMU_MAX_BATTERIES];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 189)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 190) int asleep;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 191)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 192) #ifdef CONFIG_ADB
872758563d7f1 (Olaf Hering 2007-02-10 21:35:12 +0100 193) static int adb_dev_map;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 194) static int pmu_adb_flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 195)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 196) static int pmu_probe(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 197) static int pmu_init(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 198) static int pmu_send_request(struct adb_request *req, int sync);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 199) static int pmu_adb_autopoll(int devs);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 200) static int pmu_adb_reset_bus(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 201) #endif /* CONFIG_ADB */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 202)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 203) static int init_pmu(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 204) static void pmu_start(void);
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 205) static irqreturn_t via_pmu_interrupt(int irq, void *arg);
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 206) static irqreturn_t gpio1_interrupt(int irq, void *arg);
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 207) static int pmu_info_proc_show(struct seq_file *m, void *v);
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 208) static int pmu_irqstats_proc_show(struct seq_file *m, void *v);
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 209) static int pmu_battery_proc_show(struct seq_file *m, void *v);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 210) static void pmu_pass_intr(unsigned char *data, int len);
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 211) static const struct proc_ops pmu_options_proc_ops;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 212)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 213) #ifdef CONFIG_ADB
58935176ad179 (Mathieu Malaterre 2018-02-14 22:15:18 +0100 214) const struct adb_driver via_pmu_driver = {
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 215) .name = "PMU",
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 216) .probe = pmu_probe,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 217) .init = pmu_init,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 218) .send_request = pmu_send_request,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 219) .autopoll = pmu_adb_autopoll,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 220) .poll = pmu_poll_adb,
3a52f6f980c45 (Finn Thain 2018-03-29 11:36:04 +1100 221) .reset_bus = pmu_adb_reset_bus,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 222) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 223) #endif /* CONFIG_ADB */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 224)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 225) extern void low_sleep_handler(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 226) extern void enable_kernel_altivec(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 227) extern void enable_kernel_fp(void);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 228)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 229) #ifdef DEBUG_SLEEP
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 230) int pmu_polled_request(struct adb_request *req);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 231) void pmu_blink(int n);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 232) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 233)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 234) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 235) * This table indicates for each PMU opcode:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 236) * - the number of data bytes to be sent with the command, or -1
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 237) * if a length byte should be sent,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 238) * - the number of response bytes which the PMU will return, or
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 239) * -1 if it will send a length byte.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 240) */
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 241) static const s8 pmu_data_len[256][2] = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 242) /* 0 1 2 3 4 5 6 7 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 243) /*00*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 244) /*08*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 245) /*10*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 246) /*18*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 247) /*20*/ {-1, 0},{ 0, 0},{ 2, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 248) /*28*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{ 0,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 249) /*30*/ { 4, 0},{20, 0},{-1, 0},{ 3, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 250) /*38*/ { 0, 4},{ 0,20},{ 2,-1},{ 2, 1},{ 3,-1},{-1,-1},{-1,-1},{ 4, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 251) /*40*/ { 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 252) /*48*/ { 0, 1},{ 0, 1},{-1,-1},{ 1, 0},{ 1, 0},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 253) /*50*/ { 1, 0},{ 0, 0},{ 2, 0},{ 2, 0},{-1, 0},{ 1, 0},{ 3, 0},{ 1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 254) /*58*/ { 0, 1},{ 1, 0},{ 0, 2},{ 0, 2},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 255) /*60*/ { 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 256) /*68*/ { 0, 3},{ 0, 3},{ 0, 2},{ 0, 8},{ 0,-1},{ 0,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 257) /*70*/ { 1, 0},{ 1, 0},{ 1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 258) /*78*/ { 0,-1},{ 0,-1},{-1,-1},{-1,-1},{-1,-1},{ 5, 1},{ 4, 1},{ 4, 1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 259) /*80*/ { 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 260) /*88*/ { 0, 5},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 261) /*90*/ { 1, 0},{ 2, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 262) /*98*/ { 0, 1},{ 0, 1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 263) /*a0*/ { 2, 0},{ 2, 0},{ 2, 0},{ 4, 0},{-1, 0},{ 0, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 264) /*a8*/ { 1, 1},{ 1, 0},{ 3, 0},{ 2, 0},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 265) /*b0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 266) /*b8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 267) /*c0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 268) /*c8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 269) /*d0*/ { 0, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 270) /*d8*/ { 1, 1},{ 1, 1},{-1,-1},{-1,-1},{ 0, 1},{ 0,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 271) /*e0*/ {-1, 0},{ 4, 0},{ 0, 1},{-1, 0},{-1, 0},{ 4, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 272) /*e8*/ { 3,-1},{-1,-1},{ 0, 1},{-1,-1},{ 0,-1},{-1,-1},{-1,-1},{ 0, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 273) /*f0*/ {-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},{-1, 0},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 274) /*f8*/ {-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},{-1,-1},
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 275) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 276)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 277) static char *pbook_type[] = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 278) "Unknown PowerBook",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 279) "PowerBook 2400/3400/3500(G3)",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 280) "PowerBook G3 Series",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 281) "1999 PowerBook G3",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 282) "Core99"
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 283) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 284)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 285) int __init find_via_pmu(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 286) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 287) #ifdef CONFIG_PPC_PMAC
cc5d0189b9ba9 (Benjamin Herrenschmidt 2005-12-13 18:01:21 +1100 288) u64 taddr;
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 289) const u32 *reg;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 290)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 291) if (pmu_state != uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 292) return 1;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 293) vias = of_find_node_by_name(NULL, "via-pmu");
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 294) if (vias == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 295) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 296)
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 297) reg = of_get_property(vias, "reg", NULL);
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 298) if (reg == NULL) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 299) printk(KERN_ERR "via-pmu: No \"reg\" property !\n");
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 300) goto fail;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 301) }
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 302) taddr = of_translate_address(vias, reg);
bb6b9b28d6847 (Benjamin Herrenschmidt 2005-11-30 16:54:12 +1100 303) if (taddr == OF_BAD_ADDR) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 304) printk(KERN_ERR "via-pmu: Can't translate address !\n");
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 305) goto fail;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 306) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 307)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 308) spin_lock_init(&pmu_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 309)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 310) pmu_has_adb = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 311)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 312) pmu_intr_mask = PMU_INT_PCEJECT |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 313) PMU_INT_SNDBRT |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 314) PMU_INT_ADB |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 315) PMU_INT_TICK;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 316)
f1e0addca8bd7 (Rob Herring 2018-12-05 13:50:28 -0600 317) if (of_node_name_eq(vias->parent, "ohare") ||
f1e0addca8bd7 (Rob Herring 2018-12-05 13:50:28 -0600 318) of_device_is_compatible(vias->parent, "ohare"))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 319) pmu_kind = PMU_OHARE_BASED;
55b61fec22caa (Stephen Rothwell 2007-05-03 17:26:52 +1000 320) else if (of_device_is_compatible(vias->parent, "paddington"))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 321) pmu_kind = PMU_PADDINGTON_BASED;
55b61fec22caa (Stephen Rothwell 2007-05-03 17:26:52 +1000 322) else if (of_device_is_compatible(vias->parent, "heathrow"))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 323) pmu_kind = PMU_HEATHROW_BASED;
55b61fec22caa (Stephen Rothwell 2007-05-03 17:26:52 +1000 324) else if (of_device_is_compatible(vias->parent, "Keylargo")
55b61fec22caa (Stephen Rothwell 2007-05-03 17:26:52 +1000 325) || of_device_is_compatible(vias->parent, "K2-Keylargo")) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 326) struct device_node *gpiop;
1658ab66781d9 (Stephen Rothwell 2007-04-24 13:51:59 +1000 327) struct device_node *adbp;
cc5d0189b9ba9 (Benjamin Herrenschmidt 2005-12-13 18:01:21 +1100 328) u64 gaddr = OF_BAD_ADDR;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 329)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 330) pmu_kind = PMU_KEYLARGO_BASED;
1658ab66781d9 (Stephen Rothwell 2007-04-24 13:51:59 +1000 331) adbp = of_find_node_by_type(NULL, "adb");
1658ab66781d9 (Stephen Rothwell 2007-04-24 13:51:59 +1000 332) pmu_has_adb = (adbp != NULL);
1658ab66781d9 (Stephen Rothwell 2007-04-24 13:51:59 +1000 333) of_node_put(adbp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 334) pmu_intr_mask = PMU_INT_PCEJECT |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 335) PMU_INT_SNDBRT |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 336) PMU_INT_ADB |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 337) PMU_INT_TICK |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 338) PMU_INT_ENVIRONMENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 339)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 340) gpiop = of_find_node_by_name(NULL, "gpio");
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 341) if (gpiop) {
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 342) reg = of_get_property(gpiop, "reg", NULL);
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 343) if (reg)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 344) gaddr = of_translate_address(gpiop, reg);
cc5d0189b9ba9 (Benjamin Herrenschmidt 2005-12-13 18:01:21 +1100 345) if (gaddr != OF_BAD_ADDR)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 346) gpio_reg = ioremap(gaddr, 0x10);
e702240e83649 (Phil Carmody 2014-09-17 01:00:54 +0300 347) of_node_put(gpiop);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 348) }
61e37ca22b717 (Olaf Hering 2006-09-26 22:28:36 +0200 349) if (gpio_reg == NULL) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 350) printk(KERN_ERR "via-pmu: Can't find GPIO reg !\n");
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 351) goto fail;
61e37ca22b717 (Olaf Hering 2006-09-26 22:28:36 +0200 352) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 353) } else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 354) pmu_kind = PMU_UNKNOWN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 355)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 356) via1 = via2 = ioremap(taddr, 0x2000);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 357) if (via1 == NULL) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 358) printk(KERN_ERR "via-pmu: Can't map address !\n");
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 359) goto fail_via_remap;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 360) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 361)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 362) out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 363) out_8(&via1[IFR], 0x7f); /* clear IFR */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 364)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 365) pmu_state = idle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 366)
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 367) if (!init_pmu())
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 368) goto fail_init;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 369)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 370) sys_ctrler = SYS_CTRLER_PMU;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 371)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 372) return 1;
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 373)
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 374) fail_init:
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 375) iounmap(via1);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 376) via1 = via2 = NULL;
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 377) fail_via_remap:
61e37ca22b717 (Olaf Hering 2006-09-26 22:28:36 +0200 378) iounmap(gpio_reg);
61e37ca22b717 (Olaf Hering 2006-09-26 22:28:36 +0200 379) gpio_reg = NULL;
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 380) fail:
ffa3eb010dd8e (Phil Carmody 2014-09-17 01:00:53 +0300 381) of_node_put(vias);
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 382) vias = NULL;
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 383) pmu_state = uninitialized;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 384) return 0;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 385) #else
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 386) if (macintosh_config->adb_type != MAC_ADB_PB2)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 387) return 0;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 388)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 389) pmu_kind = PMU_UNKNOWN;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 390)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 391) spin_lock_init(&pmu_lock);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 392)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 393) pmu_has_adb = 1;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 394)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 395) pmu_intr_mask = PMU_INT_PCEJECT |
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 396) PMU_INT_SNDBRT |
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 397) PMU_INT_ADB |
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 398) PMU_INT_TICK;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 399)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 400) pmu_state = idle;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 401)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 402) if (!init_pmu()) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 403) pmu_state = uninitialized;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 404) return 0;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 405) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 406)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 407) return 1;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 408) #endif /* !CONFIG_PPC_PMAC */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 409) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 410)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 411) #ifdef CONFIG_ADB
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 412) static int pmu_probe(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 413) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 414) return pmu_state == uninitialized ? -ENODEV : 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 415) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 416)
73f4447d43484 (Finn Thain 2018-07-02 04:21:18 -0400 417) static int pmu_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 418) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 419) return pmu_state == uninitialized ? -ENODEV : 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 420) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 421) #endif /* CONFIG_ADB */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 422)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 423) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 424) * We can't wait until pmu_init gets called, that happens too late.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 425) * It happens after IDE and SCSI initialization, which can take a few
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 426) * seconds, and by that time the PMU could have given up on us and
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 427) * turned us off.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 428) * Thus this is called with arch_initcall rather than device_initcall.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 429) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 430) static int __init via_pmu_start(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 431) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 432) unsigned int __maybe_unused irq;
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 433)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 434) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 435) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 436)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 437) batt_req.complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 438)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 439) #ifdef CONFIG_PPC_PMAC
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 440) irq = irq_of_parse_and_map(vias, 0);
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 441) if (!irq) {
7b52b440d37d6 (Michael Buesch 2007-08-13 06:38:34 +1000 442) printk(KERN_ERR "via-pmu: can't map interrupt\n");
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 443) return -ENODEV;
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 444) }
ba461f094bab2 (Ian Campbell 2010-07-29 11:16:34 +0100 445) /* We set IRQF_NO_SUSPEND because we don't want the interrupt
ba461f094bab2 (Ian Campbell 2010-07-29 11:16:34 +0100 446) * to be disabled between the 2 passes of driver suspend, we
ba461f094bab2 (Ian Campbell 2010-07-29 11:16:34 +0100 447) * control our own disabling for that one
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 448) */
ba461f094bab2 (Ian Campbell 2010-07-29 11:16:34 +0100 449) if (request_irq(irq, via_pmu_interrupt, IRQF_NO_SUSPEND,
ba461f094bab2 (Ian Campbell 2010-07-29 11:16:34 +0100 450) "VIA-PMU", (void *)0)) {
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 451) printk(KERN_ERR "via-pmu: can't request irq %d\n", irq);
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 452) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 453) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 454)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 455) if (pmu_kind == PMU_KEYLARGO_BASED) {
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 456) gpio_node = of_find_node_by_name(NULL, "extint-gpio1");
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 457) if (gpio_node == NULL)
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 458) gpio_node = of_find_node_by_name(NULL,
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 459) "pmu-interrupt");
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 460) if (gpio_node)
0ebfff1491ef8 (Benjamin Herrenschmidt 2006-07-03 21:36:01 +1000 461) gpio_irq = irq_of_parse_and_map(gpio_node, 0);
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 462)
ef24ba7091517 (Michael Ellerman 2016-09-06 21:53:24 +1000 463) if (gpio_irq) {
6c3082151e138 (John Ogness 2015-11-11 15:15:03 +0100 464) if (request_irq(gpio_irq, gpio1_interrupt,
6c3082151e138 (John Ogness 2015-11-11 15:15:03 +0100 465) IRQF_NO_SUSPEND, "GPIO1 ADB",
6c3082151e138 (John Ogness 2015-11-11 15:15:03 +0100 466) (void *)0))
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 467) printk(KERN_ERR "pmu: can't get irq %d"
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 468) " (GPIO1)\n", gpio_irq);
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 469) else
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 470) gpio_irq_enabled = 1;
51d3082fe6e55 (Benjamin Herrenschmidt 2005-11-23 17:57:25 +1100 471) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 472) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 473)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 474) /* Enable interrupts */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 475) out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 476) #else
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 477) if (request_irq(IRQ_MAC_ADB_SR, via_pmu_interrupt, IRQF_NO_SUSPEND,
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 478) "VIA-PMU-SR", NULL)) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 479) pr_err("%s: couldn't get SR irq\n", __func__);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 480) return -ENODEV;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 481) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 482) if (request_irq(IRQ_MAC_ADB_CL, via_pmu_interrupt, IRQF_NO_SUSPEND,
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 483) "VIA-PMU-CL", NULL)) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 484) pr_err("%s: couldn't get CL irq\n", __func__);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 485) free_irq(IRQ_MAC_ADB_SR, NULL);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 486) return -ENODEV;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 487) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 488) #endif /* !CONFIG_PPC_PMAC */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 489)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 490) pmu_fully_inited = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 491)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 492) /* Make sure PMU settle down before continuing. This is _very_ important
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 493) * since the IDE probe may shut interrupts down for quite a bit of time. If
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 494) * a PMU communication is pending while this happens, the PMU may timeout
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 495) * Not that on Core99 machines, the PMU keeps sending us environement
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 496) * messages, we should find a way to either fix IDE or make it call
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 497) * pmu_suspend() before masking interrupts. This can also happens while
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 498) * scolling with some fbdevs.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 499) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 500) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 501) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 502) } while (pmu_state != idle);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 503)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 504) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 505) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 506)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 507) arch_initcall(via_pmu_start);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 508)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 509) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 510) * This has to be done after pci_init, which is a subsys_initcall.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 511) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 512) static int __init via_pmu_dev_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 513) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 514) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 515) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 516)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 517) #ifdef CONFIG_PMAC_BACKLIGHT
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 518) /* Initialize backlight */
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 519) pmu_backlight_init();
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 520) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 521)
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 522) #ifdef CONFIG_PPC32
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 523) if (of_machine_is_compatible("AAPL,3400/2400") ||
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 524) of_machine_is_compatible("AAPL,3500")) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 525) int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 526) NULL, PMAC_MB_INFO_MODEL, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 527) pmu_battery_count = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 528) if (mb == PMAC_TYPE_COMET)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 529) pmu_batteries[0].flags |= PMU_BATT_TYPE_COMET;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 530) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 531) pmu_batteries[0].flags |= PMU_BATT_TYPE_HOOPER;
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 532) } else if (of_machine_is_compatible("AAPL,PowerBook1998") ||
71a157e8edca5 (Grant Likely 2010-02-01 21:34:14 -0700 533) of_machine_is_compatible("PowerBook1,1")) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 534) pmu_battery_count = 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 535) pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 536) pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 537) } else {
30686ba6d5685 (Stephen Rothwell 2007-04-24 13:53:04 +1000 538) struct device_node* prim =
30686ba6d5685 (Stephen Rothwell 2007-04-24 13:53:04 +1000 539) of_find_node_by_name(NULL, "power-mgt");
018a3d1db7cdb (Jeremy Kerr 2006-07-12 15:40:29 +1000 540) const u32 *prim_info = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 541) if (prim)
01b2726dd11ef (Stephen Rothwell 2007-04-27 13:41:15 +1000 542) prim_info = of_get_property(prim, "prim-info", NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 543) if (prim_info) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 544) /* Other stuffs here yet unknown */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 545) pmu_battery_count = (prim_info[6] >> 16) & 0xff;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 546) pmu_batteries[0].flags |= PMU_BATT_TYPE_SMART;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 547) if (pmu_battery_count > 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 548) pmu_batteries[1].flags |= PMU_BATT_TYPE_SMART;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 549) }
30686ba6d5685 (Stephen Rothwell 2007-04-24 13:53:04 +1000 550) of_node_put(prim);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 551) }
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 552) #endif /* CONFIG_PPC32 */
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 553)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 554) /* Create /proc/pmu */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 555) proc_pmu_root = proc_mkdir("pmu", NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 556) if (proc_pmu_root) {
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 557) long i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 558)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 559) for (i=0; i<pmu_battery_count; i++) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 560) char title[16];
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 561) sprintf(title, "battery_%ld", i);
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 562) proc_pmu_batt[i] = proc_create_single_data(title, 0,
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 563) proc_pmu_root, pmu_battery_proc_show,
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 564) (void *)i);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 565) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 566)
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 567) proc_pmu_info = proc_create_single("info", 0, proc_pmu_root,
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 568) pmu_info_proc_show);
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 569) proc_pmu_irqstats = proc_create_single("interrupts", 0,
3f3942aca6da3 (Christoph Hellwig 2018-05-15 15:57:23 +0200 570) proc_pmu_root, pmu_irqstats_proc_show);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 571) proc_pmu_options = proc_create("options", 0600, proc_pmu_root,
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 572) &pmu_options_proc_ops);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 573) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 574) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 575) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 576)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 577) device_initcall(via_pmu_dev_init);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 578)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 579) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 580) init_pmu(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 581) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 582) int timeout;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 583) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 584)
576d5290d678a (Finn Thain 2018-07-02 04:21:18 -0400 585) /* Negate TREQ. Set TACK to input and TREQ to output. */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 586) out_8(&via2[B], in_8(&via2[B]) | TREQ);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 587) out_8(&via2[DIRB], (in_8(&via2[DIRB]) | TREQ) & ~TACK);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 588)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 589) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 590) timeout = 100000;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 591) while (!req.complete) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 592) if (--timeout < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 593) printk(KERN_ERR "init_pmu: no response from PMU\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 594) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 595) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 596) udelay(10);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 597) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 598) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 599)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 600) /* ack all pending interrupts */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 601) timeout = 100000;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 602) interrupt_data[0][0] = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 603) while (interrupt_data[0][0] || pmu_state != idle) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 604) if (--timeout < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 605) printk(KERN_ERR "init_pmu: timed out acking intrs\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 606) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 607) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 608) if (pmu_state == idle)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 609) adb_int_pending = 1;
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 610) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 611) udelay(10);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 612) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 613)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 614) /* Tell PMU we are ready. */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 615) if (pmu_kind == PMU_KEYLARGO_BASED) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 616) pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 617) while (!req.complete)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 618) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 619) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 620)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 621) /* Read PMU version */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 622) pmu_request(&req, NULL, 1, PMU_GET_VERSION);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 623) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 624) if (req.reply_len > 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 625) pmu_version = req.reply[0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 626)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 627) /* Read server mode setting */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 628) if (pmu_kind == PMU_KEYLARGO_BASED) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 629) pmu_request(&req, NULL, 2, PMU_POWER_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 630) PMU_PWR_GET_POWERUP_EVENTS);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 631) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 632) if (req.reply_len == 2) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 633) if (req.reply[1] & PMU_PWR_WAKEUP_AC_INSERT)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 634) option_server_mode = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 635) printk(KERN_INFO "via-pmu: Server Mode is %s\n",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 636) option_server_mode ? "enabled" : "disabled");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 637) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 638) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 639)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 640) printk(KERN_INFO "PMU driver v%d initialized for %s, firmware: %02x\n",
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 641) PMU_DRIVER_VERSION, pbook_type[pmu_kind], pmu_version);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 642)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 643) return 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 644) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 645)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 646) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 647) pmu_get_model(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 648) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 649) return pmu_kind;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 650) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 651)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 652) static void pmu_set_server_mode(int server_mode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 653) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 654) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 655)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 656) if (pmu_kind != PMU_KEYLARGO_BASED)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 657) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 658)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 659) option_server_mode = server_mode;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 660) pmu_request(&req, NULL, 2, PMU_POWER_EVENTS, PMU_PWR_GET_POWERUP_EVENTS);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 661) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 662) if (req.reply_len < 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 663) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 664) if (server_mode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 665) pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 666) PMU_PWR_SET_POWERUP_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 667) req.reply[0], PMU_PWR_WAKEUP_AC_INSERT);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 668) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 669) pmu_request(&req, NULL, 4, PMU_POWER_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 670) PMU_PWR_CLR_POWERUP_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 671) req.reply[0], PMU_PWR_WAKEUP_AC_INSERT);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 672) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 673) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 674)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 675) /* This new version of the code for 2400/3400/3500 powerbooks
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 676) * is inspired from the implementation in gkrellm-pmu
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 677) */
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 678) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 679) done_battery_state_ohare(struct adb_request* req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 680) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 681) #ifdef CONFIG_PPC_PMAC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 682) /* format:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 683) * [0] : flags
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 684) * 0x01 : AC indicator
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 685) * 0x02 : charging
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 686) * 0x04 : battery exist
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 687) * 0x08 :
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 688) * 0x10 :
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 689) * 0x20 : full charged
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 690) * 0x40 : pcharge reset
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 691) * 0x80 : battery exist
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 692) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 693) * [1][2] : battery voltage
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 694) * [3] : CPU temperature
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 695) * [4] : battery temperature
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 696) * [5] : current
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 697) * [6][7] : pcharge
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 698) * --tkoba
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 699) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 700) unsigned int bat_flags = PMU_BATT_TYPE_HOOPER;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 701) long pcharge, charge, vb, vmax, lmax;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 702) long vmax_charging, vmax_charged;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 703) long amperage, voltage, time, max;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 704) int mb = pmac_call_feature(PMAC_FTR_GET_MB_INFO,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 705) NULL, PMAC_MB_INFO_MODEL, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 706)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 707) if (req->reply[0] & 0x01)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 708) pmu_power_flags |= PMU_PWR_AC_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 709) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 710) pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 711)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 712) if (mb == PMAC_TYPE_COMET) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 713) vmax_charged = 189;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 714) vmax_charging = 213;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 715) lmax = 6500;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 716) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 717) vmax_charged = 330;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 718) vmax_charging = 330;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 719) lmax = 6500;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 720) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 721) vmax = vmax_charged;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 722)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 723) /* If battery installed */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 724) if (req->reply[0] & 0x04) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 725) bat_flags |= PMU_BATT_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 726) if (req->reply[0] & 0x02)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 727) bat_flags |= PMU_BATT_CHARGING;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 728) vb = (req->reply[1] << 8) | req->reply[2];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 729) voltage = (vb * 265 + 72665) / 10;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 730) amperage = req->reply[5];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 731) if ((req->reply[0] & 0x01) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 732) if (amperage > 200)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 733) vb += ((amperage - 200) * 15)/100;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 734) } else if (req->reply[0] & 0x02) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 735) vb = (vb * 97) / 100;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 736) vmax = vmax_charging;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 737) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 738) charge = (100 * vb) / vmax;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 739) if (req->reply[0] & 0x40) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 740) pcharge = (req->reply[6] << 8) + req->reply[7];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 741) if (pcharge > lmax)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 742) pcharge = lmax;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 743) pcharge *= 100;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 744) pcharge = 100 - pcharge / lmax;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 745) if (pcharge < charge)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 746) charge = pcharge;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 747) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 748) if (amperage > 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 749) time = (charge * 16440) / amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 750) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 751) time = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 752) max = 100;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 753) amperage = -amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 754) } else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 755) charge = max = amperage = voltage = time = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 756)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 757) pmu_batteries[pmu_cur_battery].flags = bat_flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 758) pmu_batteries[pmu_cur_battery].charge = charge;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 759) pmu_batteries[pmu_cur_battery].max_charge = max;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 760) pmu_batteries[pmu_cur_battery].amperage = amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 761) pmu_batteries[pmu_cur_battery].voltage = voltage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 762) pmu_batteries[pmu_cur_battery].time_remaining = time;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 763) #endif /* CONFIG_PPC_PMAC */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 764)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 765) clear_bit(0, &async_req_locks);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 766) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 767)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 768) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 769) done_battery_state_smart(struct adb_request* req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 770) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 771) /* format:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 772) * [0] : format of this structure (known: 3,4,5)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 773) * [1] : flags
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 774) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 775) * format 3 & 4:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 776) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 777) * [2] : charge
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 778) * [3] : max charge
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 779) * [4] : current
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 780) * [5] : voltage
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 781) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 782) * format 5:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 783) *
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 784) * [2][3] : charge
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 785) * [4][5] : max charge
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 786) * [6][7] : current
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 787) * [8][9] : voltage
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 788) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 789)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 790) unsigned int bat_flags = PMU_BATT_TYPE_SMART;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 791) int amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 792) unsigned int capa, max, voltage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 793)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 794) if (req->reply[1] & 0x01)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 795) pmu_power_flags |= PMU_PWR_AC_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 796) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 797) pmu_power_flags &= ~PMU_PWR_AC_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 798)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 799)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 800) capa = max = amperage = voltage = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 801)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 802) if (req->reply[1] & 0x04) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 803) bat_flags |= PMU_BATT_PRESENT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 804) switch(req->reply[0]) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 805) case 3:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 806) case 4: capa = req->reply[2];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 807) max = req->reply[3];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 808) amperage = *((signed char *)&req->reply[4]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 809) voltage = req->reply[5];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 810) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 811) case 5: capa = (req->reply[2] << 8) | req->reply[3];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 812) max = (req->reply[4] << 8) | req->reply[5];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 813) amperage = *((signed short *)&req->reply[6]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 814) voltage = (req->reply[8] << 8) | req->reply[9];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 815) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 816) default:
ebd004e4edd56 (Andy Shevchenko 2013-04-22 03:02:19 +0000 817) pr_warn("pmu.c: unrecognized battery info, "
ebd004e4edd56 (Andy Shevchenko 2013-04-22 03:02:19 +0000 818) "len: %d, %4ph\n", req->reply_len,
ebd004e4edd56 (Andy Shevchenko 2013-04-22 03:02:19 +0000 819) req->reply);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 820) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 821) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 822) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 823)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 824) if ((req->reply[1] & 0x01) && (amperage > 0))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 825) bat_flags |= PMU_BATT_CHARGING;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 826)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 827) pmu_batteries[pmu_cur_battery].flags = bat_flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 828) pmu_batteries[pmu_cur_battery].charge = capa;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 829) pmu_batteries[pmu_cur_battery].max_charge = max;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 830) pmu_batteries[pmu_cur_battery].amperage = amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 831) pmu_batteries[pmu_cur_battery].voltage = voltage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 832) if (amperage) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 833) if ((req->reply[1] & 0x01) && (amperage > 0))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 834) pmu_batteries[pmu_cur_battery].time_remaining
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 835) = ((max-capa) * 3600) / amperage;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 836) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 837) pmu_batteries[pmu_cur_battery].time_remaining
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 838) = (capa * 3600) / (-amperage);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 839) } else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 840) pmu_batteries[pmu_cur_battery].time_remaining = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 841)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 842) pmu_cur_battery = (pmu_cur_battery + 1) % pmu_battery_count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 843)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 844) clear_bit(0, &async_req_locks);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 845) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 846)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 847) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 848) query_battery_state(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 849) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 850) if (test_and_set_bit(0, &async_req_locks))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 851) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 852) if (pmu_kind == PMU_OHARE_BASED)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 853) pmu_request(&batt_req, done_battery_state_ohare,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 854) 1, PMU_BATTERY_STATE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 855) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 856) pmu_request(&batt_req, done_battery_state_smart,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 857) 2, PMU_SMART_BATTERY_STATE, pmu_cur_battery+1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 858) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 859)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 860) static int pmu_info_proc_show(struct seq_file *m, void *v)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 861) {
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 862) seq_printf(m, "PMU driver version : %d\n", PMU_DRIVER_VERSION);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 863) seq_printf(m, "PMU firmware version : %02x\n", pmu_version);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 864) seq_printf(m, "AC Power : %d\n",
63e1fd41c7127 (Benjamin Herrenschmidt 2006-03-13 21:20:42 -0800 865) ((pmu_power_flags & PMU_PWR_AC_PRESENT) != 0) || pmu_battery_count == 0);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 866) seq_printf(m, "Battery count : %d\n", pmu_battery_count);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 867)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 868) return 0;
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 869) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 870)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 871) static int pmu_irqstats_proc_show(struct seq_file *m, void *v)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 872) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 873) int i;
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 874) static const char *irq_names[NUM_IRQ_STATS] = {
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 875) "Unknown interrupt (type 0)",
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 876) "Unknown interrupt (type 1)",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 877) "PC-Card eject button",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 878) "Sound/Brightness button",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 879) "ADB message",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 880) "Battery state change",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 881) "Environment interrupt",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 882) "Tick timer",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 883) "Ghost interrupt (zero len)",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 884) "Empty interrupt (empty mask)",
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 885) "Max irqs in a row",
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 886) "Total CB1 triggered events",
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 887) "Total GPIO1 triggered events",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 888) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 889)
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 890) for (i = 0; i < NUM_IRQ_STATS; i++) {
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 891) seq_printf(m, " %2u: %10u (%s)\n",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 892) i, pmu_irq_stats[i], irq_names[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 893) }
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 894) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 895) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 896)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 897) static int pmu_battery_proc_show(struct seq_file *m, void *v)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 898) {
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 899) long batnum = (long)m->private;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 900)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 901) seq_putc(m, '\n');
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 902) seq_printf(m, "flags : %08x\n", pmu_batteries[batnum].flags);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 903) seq_printf(m, "charge : %d\n", pmu_batteries[batnum].charge);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 904) seq_printf(m, "max_charge : %d\n", pmu_batteries[batnum].max_charge);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 905) seq_printf(m, "current : %d\n", pmu_batteries[batnum].amperage);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 906) seq_printf(m, "voltage : %d\n", pmu_batteries[batnum].voltage);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 907) seq_printf(m, "time rem. : %d\n", pmu_batteries[batnum].time_remaining);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 908) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 909) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 910)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 911) static int pmu_options_proc_show(struct seq_file *m, void *v)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 912) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 913) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 914) if (pmu_kind == PMU_KEYLARGO_BASED &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 915) pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 916) seq_printf(m, "lid_wakeup=%d\n", option_lid_wakeup);
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 917) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 918) if (pmu_kind == PMU_KEYLARGO_BASED)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 919) seq_printf(m, "server_mode=%d\n", option_server_mode);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 920)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 921) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 922) }
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 923)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 924) static int pmu_options_proc_open(struct inode *inode, struct file *file)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 925) {
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 926) return single_open(file, pmu_options_proc_show, NULL);
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 927) }
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 928)
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 929) static ssize_t pmu_options_proc_write(struct file *file,
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 930) const char __user *buffer, size_t count, loff_t *pos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 931) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 932) char tmp[33];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 933) char *label, *val;
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 934) size_t fcount = count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 935)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 936) if (!count)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 937) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 938) if (count > 32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 939) count = 32;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 940) if (copy_from_user(tmp, buffer, count))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 941) return -EFAULT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 942) tmp[count] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 943)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 944) label = tmp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 945) while(*label == ' ')
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 946) label++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 947) val = label;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 948) while(*val && (*val != '=')) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 949) if (*val == ' ')
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 950) *val = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 951) val++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 952) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 953) if ((*val) == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 954) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 955) *(val++) = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 956) while(*val == ' ')
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 957) val++;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 958) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 959) if (pmu_kind == PMU_KEYLARGO_BASED &&
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 960) pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) >= 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 961) if (!strcmp(label, "lid_wakeup"))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 962) option_lid_wakeup = ((*val) == '1');
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 963) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 964) if (pmu_kind == PMU_KEYLARGO_BASED && !strcmp(label, "server_mode")) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 965) int new_value;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 966) new_value = ((*val) == '1');
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 967) if (new_value != option_server_mode)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 968) pmu_set_server_mode(new_value);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 969) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 970) return fcount;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 971) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 972)
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 973) static const struct proc_ops pmu_options_proc_ops = {
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 974) .proc_open = pmu_options_proc_open,
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 975) .proc_read = seq_read,
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 976) .proc_lseek = seq_lseek,
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 977) .proc_release = single_release,
97a32539b9568 (Alexey Dobriyan 2020-02-03 17:37:17 -0800 978) .proc_write = pmu_options_proc_write,
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 979) };
9d2f7342d0889 (Alexey Dobriyan 2009-11-26 20:53:06 +0000 980)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 981) #ifdef CONFIG_ADB
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 982) /* Send an ADB command */
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 983) static int pmu_send_request(struct adb_request *req, int sync)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 984) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 985) int i, ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 986)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 987) if (pmu_state == uninitialized || !pmu_fully_inited) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 988) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 989) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 990) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 991)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 992) ret = -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 993)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 994) switch (req->data[0]) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 995) case PMU_PACKET:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 996) for (i = 0; i < req->nbytes - 1; ++i)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 997) req->data[i] = req->data[i+1];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 998) --req->nbytes;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 999) if (pmu_data_len[req->data[0]][1] != 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1000) req->reply[0] = ADB_RET_OK;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1001) req->reply_len = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1002) } else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1003) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1004) ret = pmu_queue_request(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1005) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1006) case CUDA_PACKET:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1007) switch (req->data[1]) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1008) case CUDA_GET_TIME:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1009) if (req->nbytes != 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1010) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1011) req->data[0] = PMU_READ_RTC;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1012) req->nbytes = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1013) req->reply_len = 3;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1014) req->reply[0] = CUDA_PACKET;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1015) req->reply[1] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1016) req->reply[2] = CUDA_GET_TIME;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1017) ret = pmu_queue_request(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1018) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1019) case CUDA_SET_TIME:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1020) if (req->nbytes != 6)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1021) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1022) req->data[0] = PMU_SET_RTC;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1023) req->nbytes = 5;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1024) for (i = 1; i <= 4; ++i)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1025) req->data[i] = req->data[i+1];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1026) req->reply_len = 3;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1027) req->reply[0] = CUDA_PACKET;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1028) req->reply[1] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1029) req->reply[2] = CUDA_SET_TIME;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1030) ret = pmu_queue_request(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1031) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1032) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1033) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1034) case ADB_PACKET:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1035) if (!pmu_has_adb)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1036) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1037) for (i = req->nbytes - 1; i > 1; --i)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1038) req->data[i+2] = req->data[i];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1039) req->data[3] = req->nbytes - 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1040) req->data[2] = pmu_adb_flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1041) /*req->data[1] = req->data[1];*/
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1042) req->data[0] = PMU_ADB_CMD;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1043) req->nbytes += 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1044) req->reply_expected = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1045) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1046) ret = pmu_queue_request(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1047) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1048) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1049) if (ret) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1050) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1051) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1052) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1053)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1054) if (sync)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1055) while (!req->complete)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1056) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1057)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1058) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1059) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1060)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1061) /* Enable/disable autopolling */
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1062) static int __pmu_adb_autopoll(int devs)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1063) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1064) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1065)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1066) if (devs) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1067) pmu_request(&req, NULL, 5, PMU_ADB_CMD, 0, 0x86,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1068) adb_dev_map >> 8, adb_dev_map);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1069) pmu_adb_flags = 2;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1070) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1071) pmu_request(&req, NULL, 1, PMU_ADB_POLL_OFF);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1072) pmu_adb_flags = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1073) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1074) while (!req.complete)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1075) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1076) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1077) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1078)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1079) static int pmu_adb_autopoll(int devs)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1080) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1081) if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1082) return -ENXIO;
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1083)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1084) adb_dev_map = devs;
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1085) return __pmu_adb_autopoll(devs);
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1086) }
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1087)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1088) /* Reset the ADB bus */
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1089) static int pmu_adb_reset_bus(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1090) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1091) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1092) int save_autopoll = adb_dev_map;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1093)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1094) if (pmu_state == uninitialized || !pmu_fully_inited || !pmu_has_adb)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1095) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1096)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1097) /* anyone got a better idea?? */
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1098) __pmu_adb_autopoll(0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1099)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1100) req.nbytes = 4;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1101) req.done = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1102) req.data[0] = PMU_ADB_CMD;
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1103) req.data[1] = ADB_BUSRESET;
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1104) req.data[2] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1105) req.data[3] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1106) req.data[4] = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1107) req.reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1108) req.reply_expected = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1109) if (pmu_queue_request(&req) != 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1110) printk(KERN_ERR "pmu_adb_reset_bus: pmu_queue_request failed\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1111) return -EIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1112) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1113) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1114)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1115) if (save_autopoll != 0)
11a50873ef2b3 (Benjamin Herrenschmidt 2009-10-09 11:27:54 +0000 1116) __pmu_adb_autopoll(save_autopoll);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1117)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1118) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1119) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1120) #endif /* CONFIG_ADB */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1121)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1122) /* Construct and send a pmu request */
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1123) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1124) pmu_request(struct adb_request *req, void (*done)(struct adb_request *),
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1125) int nbytes, ...)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1126) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1127) va_list list;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1128) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1129)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1130) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1131) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1132)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1133) if (nbytes < 0 || nbytes > 32) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1134) printk(KERN_ERR "pmu_request: bad nbytes (%d)\n", nbytes);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1135) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1136) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1137) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1138) req->nbytes = nbytes;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1139) req->done = done;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1140) va_start(list, nbytes);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1141) for (i = 0; i < nbytes; ++i)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1142) req->data[i] = va_arg(list, int);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1143) va_end(list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1144) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1145) req->reply_expected = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1146) return pmu_queue_request(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1147) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1148)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1149) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1150) pmu_queue_request(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1151) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1152) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1153) int nsend;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1154)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1155) if (pmu_state == uninitialized) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1156) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1157) return -ENXIO;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1158) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1159) if (req->nbytes <= 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1160) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1161) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1162) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1163) nsend = pmu_data_len[req->data[0]][0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1164) if (nsend >= 0 && req->nbytes != nsend + 1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1165) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1166) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1167) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1168)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1169) req->next = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1170) req->sent = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1171) req->complete = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1172)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1173) spin_lock_irqsave(&pmu_lock, flags);
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 1174) if (current_req) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1175) last_req->next = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1176) last_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1177) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1178) current_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1179) last_req = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1180) if (pmu_state == idle)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1181) pmu_start();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1182) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1183) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1184)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1185) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1186) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1187)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1188) static inline void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1189) wait_for_ack(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1190) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1191) /* Sightly increased the delay, I had one occurrence of the message
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1192) * reported
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1193) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1194) int timeout = 4000;
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1195) while ((in_8(&via2[B]) & TACK) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1196) if (--timeout < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1197) printk(KERN_ERR "PMU not responding (!ack)\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1198) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1199) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1200) udelay(10);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1201) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1202) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1203)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1204) /* New PMU seems to be very sensitive to those timings, so we make sure
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1205) * PCI is flushed immediately */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1206) static inline void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1207) send_byte(int x)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1208) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1209) out_8(&via1[ACR], in_8(&via1[ACR]) | SR_OUT | SR_EXT);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1210) out_8(&via1[SR], x);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1211) out_8(&via2[B], in_8(&via2[B]) & ~TREQ); /* assert TREQ */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1212) (void)in_8(&via2[B]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1213) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1214)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1215) static inline void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1216) recv_byte(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1217) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1218) out_8(&via1[ACR], (in_8(&via1[ACR]) & ~SR_OUT) | SR_EXT);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1219) in_8(&via1[SR]); /* resets SR */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1220) out_8(&via2[B], in_8(&via2[B]) & ~TREQ);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1221) (void)in_8(&via2[B]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1222) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1223)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1224) static inline void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1225) pmu_done(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1226) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1227) void (*done)(struct adb_request *) = req->done;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1228) mb();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1229) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1230) /* Here, we assume that if the request has a done member, the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1231) * struct request will survive to setting req->complete to 1
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1232) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1233) if (done)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1234) (*done)(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1235) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1236)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1237) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1238) pmu_start(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1239) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1240) struct adb_request *req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1241)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1242) /* assert pmu_state == idle */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1243) /* get the packet to send */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1244) req = current_req;
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 1245) if (!req || pmu_state != idle
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1246) || (/*req->reply_expected && */req_awaiting_reply))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1247) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1248)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1249) pmu_state = sending;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1250) data_index = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1251) data_len = pmu_data_len[req->data[0]][0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1252)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1253) /* Sounds safer to make sure ACK is high before writing. This helped
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1254) * kill a problem with ADB and some iBooks
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1255) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1256) wait_for_ack();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1257) /* set the shift register to shift out and send a byte */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1258) send_byte(req->data[0]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1259) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1260)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1261) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1262) pmu_poll(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1263) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1264) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1265) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1266) if (disable_poll)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1267) return;
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1268) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1269) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1270)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1271) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1272) pmu_poll_adb(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1273) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1274) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1275) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1276) if (disable_poll)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1277) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1278) /* Kicks ADB read when PMU is suspended */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1279) adb_int_pending = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1280) do {
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1281) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1282) } while (pmu_suspended && (adb_int_pending || pmu_state != idle
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1283) || req_awaiting_reply));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1284) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1285)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1286) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1287) pmu_wait_complete(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1288) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1289) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1290) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1291) while((pmu_state != idle && pmu_state != locked) || !req->complete)
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1292) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1293) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1294)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1295) /* This function loops until the PMU is idle and prevents it from
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1296) * anwsering to ADB interrupts. pmu_request can still be called.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1297) * This is done to avoid spurrious shutdowns when we know we'll have
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1298) * interrupts switched off for a long time
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1299) */
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1300) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1301) pmu_suspend(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1302) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1303) unsigned long flags;
1b0e9d44ee6f9 (Johannes Berg 2007-11-14 06:08:32 +1100 1304)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1305) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1306) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1307)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1308) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1309) pmu_suspended++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1310) if (pmu_suspended > 1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1311) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1312) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1313) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1314)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1315) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1316) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1317) if (req_awaiting_reply)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1318) adb_int_pending = 1;
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1319) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1320) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1321) if (!adb_int_pending && pmu_state == idle && !req_awaiting_reply) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1322) if (gpio_irq >= 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1323) disable_irq_nosync(gpio_irq);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1324) out_8(&via1[IER], CB1_INT | IER_CLR);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1325) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1326) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1327) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1328) } while (1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1329) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1330)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1331) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1332) pmu_resume(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1333) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1334) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1335)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1336) if (pmu_state == uninitialized || pmu_suspended < 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1337) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1338)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1339) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1340) pmu_suspended--;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1341) if (pmu_suspended > 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1342) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1343) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1344) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1345) adb_int_pending = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1346) if (gpio_irq >= 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1347) enable_irq(gpio_irq);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1348) out_8(&via1[IER], CB1_INT | IER_SET);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1349) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1350) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1351) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1352)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1353) /* Interrupt data could be the result data from an ADB cmd */
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1354) static void
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1355) pmu_handle_data(unsigned char *data, int len)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1356) {
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1357) unsigned char ints;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1358) int idx;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1359) int i = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1360)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1361) asleep = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1362) if (drop_interrupts || len < 1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1363) adb_int_pending = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1364) pmu_irq_stats[8]++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1365) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1366) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1367)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1368) /* Get PMU interrupt mask */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1369) ints = data[0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1370)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1371) /* Record zero interrupts for stats */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1372) if (ints == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1373) pmu_irq_stats[9]++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1374)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1375) /* Hack to deal with ADB autopoll flag */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1376) if (ints & PMU_INT_ADB)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1377) ints &= ~(PMU_INT_ADB_AUTO | PMU_INT_AUTO_SRQ_POLL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1378)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1379) next:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1380) if (ints == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1381) if (i > pmu_irq_stats[10])
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1382) pmu_irq_stats[10] = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1383) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1384) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1385) i++;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1386)
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1387) idx = ffs(ints) - 1;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1388) ints &= ~BIT(idx);
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1389)
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1390) pmu_irq_stats[idx]++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1391)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1392) /* Note: for some reason, we get an interrupt with len=1,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1393) * data[0]==0 after each normal ADB interrupt, at least
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1394) * on the Pismo. Still investigating... --BenH
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1395) */
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1396) switch (BIT(idx)) {
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1397) case PMU_INT_ADB:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1398) if ((data[0] & PMU_INT_ADB_AUTO) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1399) struct adb_request *req = req_awaiting_reply;
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 1400) if (!req) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1401) printk(KERN_ERR "PMU: extra ADB reply\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1402) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1403) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1404) req_awaiting_reply = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1405) if (len <= 2)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1406) req->reply_len = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1407) else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1408) memcpy(req->reply, data + 1, len - 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1409) req->reply_len = len - 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1410) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1411) pmu_done(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1412) } else {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1413) #ifdef CONFIG_XMON
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1414) if (len == 4 && data[1] == 0x2c) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1415) extern int xmon_wants_key, xmon_adb_keycode;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1416) if (xmon_wants_key) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1417) xmon_adb_keycode = data[2];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1418) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1419) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1420) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1421) #endif /* CONFIG_XMON */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1422) #ifdef CONFIG_ADB
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1423) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1424) * XXX On the [23]400 the PMU gives us an up
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1425) * event for keycodes 0x74 or 0x75 when the PC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1426) * card eject buttons are released, so we
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1427) * ignore those events.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1428) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1429) if (!(pmu_kind == PMU_OHARE_BASED && len == 4
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1430) && data[1] == 0x2c && data[3] == 0xff
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1431) && (data[2] & ~1) == 0xf4))
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1432) adb_input(data+1, len-1, 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1433) #endif /* CONFIG_ADB */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1434) }
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1435) break;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1436)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1437) /* Sound/brightness button pressed */
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1438) case PMU_INT_SNDBRT:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1439) #ifdef CONFIG_PMAC_BACKLIGHT
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1440) if (len == 3)
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 1441) pmac_backlight_set_legacy_brightness_pmu(data[1] >> 4);
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 1442) #endif
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1443) break;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1444)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1445) /* Tick interrupt */
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1446) case PMU_INT_TICK:
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1447) /* Environment or tick interrupt, query batteries */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1448) if (pmu_battery_count) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1449) if ((--query_batt_timer) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1450) query_battery_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1451) query_batt_timer = BATTERY_POLLING_COUNT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1452) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1453) }
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1454) break;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1455)
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1456) case PMU_INT_ENVIRONMENT:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1457) if (pmu_battery_count)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1458) query_battery_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1459) pmu_pass_intr(data, len);
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1460) /* len == 6 is probably a bad check. But how do I
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1461) * know what PMU versions send what events here? */
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1462) if (len == 6) {
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1463) via_pmu_event(PMU_EVT_POWER, !!(data[1]&8));
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1464) via_pmu_event(PMU_EVT_LID, data[1]&1);
9e8e30a0cc0cc (Johannes Berg 2006-06-26 01:49:55 -0400 1465) }
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1466) break;
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1467)
b5c7cccaacdfa (Finn Thain 2018-07-02 04:21:19 -0400 1468) default:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1469) pmu_pass_intr(data, len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1470) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1471) goto next;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1472) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1473)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1474) static struct adb_request*
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1475) pmu_sr_intr(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1476) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1477) struct adb_request *req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1478) int bite = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1479)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1480) if (in_8(&via2[B]) & TREQ) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1481) printk(KERN_ERR "PMU: spurious SR intr (%x)\n", in_8(&via2[B]));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1482) return NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1483) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1484) /* The ack may not yet be low when we get the interrupt */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1485) while ((in_8(&via2[B]) & TACK) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1486) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1487)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1488) /* if reading grab the byte, and reset the interrupt */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1489) if (pmu_state == reading || pmu_state == reading_intr)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1490) bite = in_8(&via1[SR]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1491)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1492) /* reset TREQ and wait for TACK to go high */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1493) out_8(&via2[B], in_8(&via2[B]) | TREQ);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1494) wait_for_ack();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1495)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1496) switch (pmu_state) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1497) case sending:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1498) req = current_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1499) if (data_len < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1500) data_len = req->nbytes - 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1501) send_byte(data_len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1502) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1503) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1504) if (data_index <= data_len) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1505) send_byte(req->data[data_index++]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1506) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1507) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1508) req->sent = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1509) data_len = pmu_data_len[req->data[0]][1];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1510) if (data_len == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1511) pmu_state = idle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1512) current_req = req->next;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1513) if (req->reply_expected)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1514) req_awaiting_reply = req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1515) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1516) return req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1517) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1518) pmu_state = reading;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1519) data_index = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1520) reply_ptr = req->reply + req->reply_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1521) recv_byte();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1522) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1523) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1524)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1525) case intack:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1526) data_index = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1527) data_len = -1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1528) pmu_state = reading_intr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1529) reply_ptr = interrupt_data[int_data_last];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1530) recv_byte();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1531) if (gpio_irq >= 0 && !gpio_irq_enabled) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1532) enable_irq(gpio_irq);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1533) gpio_irq_enabled = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1534) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1535) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1536)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1537) case reading:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1538) case reading_intr:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1539) if (data_len == -1) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1540) data_len = bite;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1541) if (bite > 32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1542) printk(KERN_ERR "PMU: bad reply len %d\n", bite);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1543) } else if (data_index < 32) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1544) reply_ptr[data_index++] = bite;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1545) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1546) if (data_index < data_len) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1547) recv_byte();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1548) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1549) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1550)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1551) if (pmu_state == reading_intr) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1552) pmu_state = idle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1553) int_data_state[int_data_last] = int_data_ready;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1554) interrupt_data_len[int_data_last] = data_len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1555) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1556) req = current_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1557) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1558) * For PMU sleep and freq change requests, we lock the
c03983ac9b268 (Jean Delvare 2007-10-19 23:22:55 +0200 1559) * PMU until it's explicitly unlocked. This avoids any
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1560) * spurrious event polling getting in
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1561) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1562) current_req = req->next;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1563) req->reply_len += data_index;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1564) if (req->data[0] == PMU_SLEEP || req->data[0] == PMU_CPU_SPEED)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1565) pmu_state = locked;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1566) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1567) pmu_state = idle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1568) return req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1569) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1570) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1571)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1572) default:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1573) printk(KERN_ERR "via_pmu_interrupt: unknown state %d?\n",
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1574) pmu_state);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1575) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1576) return NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1577) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1578)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1579) static irqreturn_t
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1580) via_pmu_interrupt(int irq, void *arg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1581) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1582) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1583) int intr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1584) int nloop = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1585) int int_data = -1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1586) struct adb_request *req = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1587) int handled = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1588)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1589) /* This is a bit brutal, we can probably do better */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1590) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1591) ++disable_poll;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1592)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1593) for (;;) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1594) /* On 68k Macs, VIA interrupts are dispatched individually.
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1595) * Unless we are polling, the relevant IRQ flag has already
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1596) * been cleared.
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1597) */
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1598) intr = 0;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1599) if (IS_ENABLED(CONFIG_PPC_PMAC) || !irq) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1600) intr = in_8(&via1[IFR]) & (SR_INT | CB1_INT);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1601) out_8(&via1[IFR], intr);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1602) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1603) #ifndef CONFIG_PPC_PMAC
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1604) switch (irq) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1605) case IRQ_MAC_ADB_CL:
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1606) intr = CB1_INT;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1607) break;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1608) case IRQ_MAC_ADB_SR:
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1609) intr = SR_INT;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1610) break;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1611) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1612) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1613) if (intr == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1614) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1615) handled = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1616) if (++nloop > 1000) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1617) printk(KERN_DEBUG "PMU: stuck in intr loop, "
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1618) "intr=%x, ier=%x pmu_state=%d\n",
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1619) intr, in_8(&via1[IER]), pmu_state);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1620) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1621) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1622) if (intr & CB1_INT) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1623) adb_int_pending = 1;
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 1624) pmu_irq_stats[11]++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1625) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1626) if (intr & SR_INT) {
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1627) req = pmu_sr_intr();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1628) if (req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1629) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1630) }
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1631) #ifndef CONFIG_PPC_PMAC
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1632) break;
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1633) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1634) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1635)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1636) recheck:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1637) if (pmu_state == idle) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1638) if (adb_int_pending) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1639) if (int_data_state[0] == int_data_empty)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1640) int_data_last = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1641) else if (int_data_state[1] == int_data_empty)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1642) int_data_last = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1643) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1644) goto no_free_slot;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1645) pmu_state = intack;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1646) int_data_state[int_data_last] = int_data_fill;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1647) /* Sounds safer to make sure ACK is high before writing.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1648) * This helped kill a problem with ADB and some iBooks
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1649) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1650) wait_for_ack();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1651) send_byte(PMU_INT_ACK);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1652) adb_int_pending = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1653) } else if (current_req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1654) pmu_start();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1655) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1656) no_free_slot:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1657) /* Mark the oldest buffer for flushing */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1658) if (int_data_state[!int_data_last] == int_data_ready) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1659) int_data_state[!int_data_last] = int_data_flush;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1660) int_data = !int_data_last;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1661) } else if (int_data_state[int_data_last] == int_data_ready) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1662) int_data_state[int_data_last] = int_data_flush;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1663) int_data = int_data_last;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1664) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1665) --disable_poll;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1666) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1667)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1668) /* Deal with completed PMU requests outside of the lock */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1669) if (req) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1670) pmu_done(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1671) req = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1672) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1673)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1674) /* Deal with interrupt datas outside of the lock */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1675) if (int_data >= 0) {
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1676) pmu_handle_data(interrupt_data[int_data], interrupt_data_len[int_data]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1677) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1678) ++disable_poll;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1679) int_data_state[int_data] = int_data_empty;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1680) int_data = -1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1681) goto recheck;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1682) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1683)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1684) return IRQ_RETVAL(handled);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1685) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1686)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1687) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1688) pmu_unlock(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1689) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1690) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1691)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1692) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1693) if (pmu_state == locked)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1694) pmu_state = idle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1695) adb_int_pending = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1696) spin_unlock_irqrestore(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1697) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1698)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1699)
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 1700) static __maybe_unused irqreturn_t
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1701) gpio1_interrupt(int irq, void *arg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1702) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1703) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1704)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1705) if ((in_8(gpio_reg + 0x9) & 0x02) == 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1706) spin_lock_irqsave(&pmu_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1707) if (gpio_irq_enabled > 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1708) disable_irq_nosync(gpio_irq);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1709) gpio_irq_enabled = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1710) }
6edc22fc9cbb8 (Finn Thain 2018-07-02 04:21:19 -0400 1711) pmu_irq_stats[12]++;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1712) adb_int_pending = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1713) spin_unlock_irqrestore(&pmu_lock, flags);
7d12e780e003f (David Howells 2006-10-05 14:55:46 +0100 1714) via_pmu_interrupt(0, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1715) return IRQ_HANDLED;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1716) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1717) return IRQ_NONE;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1718) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1719)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1720) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1721) pmu_enable_irled(int on)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1722) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1723) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1724)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1725) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1726) return ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1727) if (pmu_kind == PMU_KEYLARGO_BASED)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1728) return ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1729)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1730) pmu_request(&req, NULL, 2, PMU_POWER_CTRL, PMU_POW_IRLED |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1731) (on ? PMU_POW_ON : PMU_POW_OFF));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1732) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1733) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1734)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1735) /* Offset between Unix time (1970-based) and Mac time (1904-based) */
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1736) #define RTC_OFFSET 2082844800
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1737)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1738) time64_t pmu_get_time(void)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1739) {
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1740) struct adb_request req;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1741) u32 now;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1742)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1743) if (pmu_request(&req, NULL, 1, PMU_READ_RTC) < 0)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1744) return 0;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1745) pmu_wait_complete(&req);
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1746) if (req.reply_len != 4)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1747) pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1748) now = (req.reply[0] << 24) + (req.reply[1] << 16) +
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1749) (req.reply[2] << 8) + req.reply[3];
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1750) return (time64_t)now - RTC_OFFSET;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1751) }
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1752)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1753) int pmu_set_rtc_time(struct rtc_time *tm)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1754) {
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1755) u32 now;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1756) struct adb_request req;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1757)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1758) now = lower_32_bits(rtc_tm_to_time64(tm) + RTC_OFFSET);
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1759) if (pmu_request(&req, NULL, 5, PMU_SET_RTC,
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1760) now >> 24, now >> 16, now >> 8, now) < 0)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1761) return -ENXIO;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1762) pmu_wait_complete(&req);
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1763) if (req.reply_len != 0)
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1764) pr_err("%s: got %d byte reply\n", __func__, req.reply_len);
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1765) return 0;
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1766) }
0792a2c8e0bbd (Finn Thain 2018-09-11 20:18:44 -0400 1767)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1768) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1769) pmu_restart(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1770) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1771) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1772)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1773) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1774) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1775)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1776) local_irq_disable();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1777)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1778) drop_interrupts = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1779)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1780) if (pmu_kind != PMU_KEYLARGO_BASED) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1781) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1782) PMU_INT_TICK );
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1783) while(!req.complete)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1784) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1785) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1786)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1787) pmu_request(&req, NULL, 1, PMU_RESET);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1788) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1789) for (;;)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1790) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1791) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1792)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1793) void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1794) pmu_shutdown(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1795) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1796) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1797)
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1798) if (pmu_state == uninitialized)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1799) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1800)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1801) local_irq_disable();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1802)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1803) drop_interrupts = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1804)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1805) if (pmu_kind != PMU_KEYLARGO_BASED) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1806) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, PMU_INT_ADB |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1807) PMU_INT_TICK );
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1808) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1809) } else {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1810) /* Disable server mode on shutdown or we'll just
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1811) * wake up again
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1812) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1813) pmu_set_server_mode(0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1814) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1815)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1816) pmu_request(&req, NULL, 5, PMU_SHUTDOWN,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1817) 'M', 'A', 'T', 'T');
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1818) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1819) for (;;)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1820) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1821) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1822)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1823) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1824) pmu_present(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1825) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 1826) return pmu_state != uninitialized;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1827) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1828)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 1829) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1830) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1831) * Put the powerbook to sleep.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1832) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1833)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1834) static u32 save_via[8];
0751fdf280416 (Michael Ellerman 2021-04-16 21:38:04 +1000 1835) static int __fake_sleep;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1836)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1837) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1838) save_via_state(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1839) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1840) save_via[0] = in_8(&via1[ANH]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1841) save_via[1] = in_8(&via1[DIRA]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1842) save_via[2] = in_8(&via1[B]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1843) save_via[3] = in_8(&via1[DIRB]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1844) save_via[4] = in_8(&via1[PCR]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1845) save_via[5] = in_8(&via1[ACR]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1846) save_via[6] = in_8(&via1[T1CL]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1847) save_via[7] = in_8(&via1[T1CH]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1848) }
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1849) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1850) restore_via_state(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1851) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1852) out_8(&via1[ANH], save_via[0]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1853) out_8(&via1[DIRA], save_via[1]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1854) out_8(&via1[B], save_via[2]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1855) out_8(&via1[DIRB], save_via[3]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1856) out_8(&via1[PCR], save_via[4]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1857) out_8(&via1[ACR], save_via[5]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1858) out_8(&via1[T1CL], save_via[6]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1859) out_8(&via1[T1CH], save_via[7]);
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1860) out_8(&via1[IER], IER_CLR | 0x7f); /* disable all intrs */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1861) out_8(&via1[IFR], 0x7f); /* clear IFR */
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 1862) out_8(&via1[IER], IER_SET | SR_INT | CB1_INT);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1863) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1864)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1865) #define GRACKLE_PM (1<<7)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1866) #define GRACKLE_DOZE (1<<5)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1867) #define GRACKLE_NAP (1<<4)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1868) #define GRACKLE_SLEEP (1<<3)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1869)
3bea63136fd9b (Olaf Hering 2006-03-21 23:00:05 -0800 1870) static int powerbook_sleep_grackle(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1871) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1872) unsigned long save_l2cr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1873) unsigned short pmcr1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1874) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1875) struct pci_dev *grackle;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1876)
67c8d32692666 (Sinan Kaya 2017-12-19 00:37:48 -0500 1877) grackle = pci_get_domain_bus_and_slot(0, 0, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1878) if (!grackle)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1879) return -ENODEV;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1880)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1881) /* Turn off various things. Darwin does some retry tests here... */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1882) pmu_request(&req, NULL, 2, PMU_POWER_CTRL0, PMU_POW0_OFF|PMU_POW0_HARD_DRIVE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1883) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1884) pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1885) PMU_POW_OFF|PMU_POW_BACKLIGHT|PMU_POW_IRLED|PMU_POW_MEDIABAY);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1886) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1887)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1888) /* For 750, save backside cache setting and disable it */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1889) save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1890)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1891) if (!__fake_sleep) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1892) /* Ask the PMU to put us to sleep */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1893) pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1894) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1895) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1896)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1897) /* The VIA is supposed not to be restored correctly*/
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1898) save_via_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1899) /* We shut down some HW */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1900) pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1901)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1902) pci_read_config_word(grackle, 0x70, &pmcr1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1903) /* Apparently, MacOS uses NAP mode for Grackle ??? */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1904) pmcr1 &= ~(GRACKLE_DOZE|GRACKLE_SLEEP);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1905) pmcr1 |= GRACKLE_PM|GRACKLE_NAP;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1906) pci_write_config_word(grackle, 0x70, pmcr1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1907)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1908) /* Call low-level ASM sleep handler */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1909) if (__fake_sleep)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1910) mdelay(5000);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1911) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1912) low_sleep_handler();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1913)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1914) /* We're awake again, stop grackle PM */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1915) pci_read_config_word(grackle, 0x70, &pmcr1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1916) pmcr1 &= ~(GRACKLE_PM|GRACKLE_DOZE|GRACKLE_SLEEP|GRACKLE_NAP);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1917) pci_write_config_word(grackle, 0x70, pmcr1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1918)
c78f830547087 (Alan Cox 2007-04-23 14:56:01 +0100 1919) pci_dev_put(grackle);
c78f830547087 (Alan Cox 2007-04-23 14:56:01 +0100 1920)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1921) /* Make sure the PMU is idle */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1922) pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1923) restore_via_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1924)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1925) /* Restore L2 cache */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1926) if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1927) _set_L2CR(save_l2cr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1928)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1929) /* Restore userland MMU context */
d2adba3fd137b (Aneesh Kumar K.V 2016-04-29 23:26:01 +1000 1930) switch_mmu_context(NULL, current->active_mm, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1931)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1932) /* Power things up */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1933) pmu_unlock();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1934) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1935) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1936) pmu_request(&req, NULL, 2, PMU_POWER_CTRL0,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1937) PMU_POW0_ON|PMU_POW0_HARD_DRIVE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1938) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1939) pmu_request(&req, NULL, 2, PMU_POWER_CTRL,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1940) PMU_POW_ON|PMU_POW_BACKLIGHT|PMU_POW_CHARGER|PMU_POW_IRLED|PMU_POW_MEDIABAY);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1941) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1942)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1943) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1944) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1945)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 1946) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1947) powerbook_sleep_Core99(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1948) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1949) unsigned long save_l2cr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1950) unsigned long save_l3cr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1951) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1952)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1953) if (pmac_call_feature(PMAC_FTR_SLEEP_STATE,NULL,0,-1) < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1954) printk(KERN_ERR "Sleep mode not supported on this machine\n");
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1955) return -ENOSYS;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1956) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1957)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1958) if (num_online_cpus() > 1 || cpu_is_offline(0))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1959) return -EAGAIN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1960)
b16eeb4729259 (Benjamin Herrenschmidt 2005-05-27 12:53:02 -0700 1961) /* Stop environment and ADB interrupts */
b16eeb4729259 (Benjamin Herrenschmidt 2005-05-27 12:53:02 -0700 1962) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, 0);
b16eeb4729259 (Benjamin Herrenschmidt 2005-05-27 12:53:02 -0700 1963) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1964)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1965) /* Tell PMU what events will wake us up */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1966) pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_CLR_WAKEUP_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1967) 0xff, 0xff);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1968) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1969) pmu_request(&req, NULL, 4, PMU_POWER_EVENTS, PMU_PWR_SET_WAKEUP_EVENTS,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1970) 0, PMU_PWR_WAKEUP_KEY |
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1971) (option_lid_wakeup ? PMU_PWR_WAKEUP_LID_OPEN : 0));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1972) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1973)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1974) /* Save the state of the L2 and L3 caches */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1975) save_l3cr = _get_L3CR(); /* (returns -1 if not available) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1976) save_l2cr = _get_L2CR(); /* (returns -1 if not available) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1977)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1978) if (!__fake_sleep) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1979) /* Ask the PMU to put us to sleep */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1980) pmu_request(&req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1981) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1982) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1983)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1984) /* The VIA is supposed not to be restored correctly*/
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1985) save_via_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1986)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1987) /* Shut down various ASICs. There's a chance that we can no longer
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1988) * talk to the PMU after this, so I moved it to _after_ sending the
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1989) * sleep command to it. Still need to be checked.
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1990) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1991) pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1992)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1993) /* Call low-level ASM sleep handler */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1994) if (__fake_sleep)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1995) mdelay(5000);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1996) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1997) low_sleep_handler();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1998)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 1999) /* Restore Apple core ASICs state */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2000) pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2001)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2002) /* Restore VIA */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2003) restore_via_state();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2004)
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2005) /* tweak LPJ before cpufreq is there */
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2006) loops_per_jiffy *= 2;
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2007)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2008) /* Restore video */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2009) pmac_call_early_video_resume();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2010)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2011) /* Restore L2 cache */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2012) if (save_l2cr != 0xffffffff && (save_l2cr & L2CR_L2E) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2013) _set_L2CR(save_l2cr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2014) /* Restore L3 cache */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2015) if (save_l3cr != 0xffffffff && (save_l3cr & L3CR_L3E) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2016) _set_L3CR(save_l3cr);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2017)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2018) /* Restore userland MMU context */
d2adba3fd137b (Aneesh Kumar K.V 2016-04-29 23:26:01 +1000 2019) switch_mmu_context(NULL, current->active_mm, NULL);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2020)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2021) /* Tell PMU we are ready */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2022) pmu_unlock();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2023) pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2024) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2025) pmu_request(&req, NULL, 2, PMU_SET_INTR_MASK, pmu_intr_mask);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2026) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2027)
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2028) /* Restore LPJ, cpufreq will adjust the cpu frequency */
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2029) loops_per_jiffy /= 2;
0086b5ec7834b (Benjamin Herrenschmidt 2005-06-10 14:19:02 +1000 2030)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2031) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2032) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2033)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2034) #define PB3400_MEM_CTRL 0xf8000000
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2035) #define PB3400_MEM_CTRL_SLEEP 0x70
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2036)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2037) static void __iomem *pb3400_mem_ctrl;
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2038)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2039) static void powerbook_sleep_init_3400(void)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2040) {
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2041) /* map in the memory controller registers */
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2042) pb3400_mem_ctrl = ioremap(PB3400_MEM_CTRL, 0x100);
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2043) if (pb3400_mem_ctrl == NULL)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2044) printk(KERN_WARNING "ioremap failed: sleep won't be possible");
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2045) }
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2046)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2047) static int powerbook_sleep_3400(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2048) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2049) int i, x;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2050) unsigned int hid0;
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2051) unsigned long msr;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2052) struct adb_request sleep_req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2053) unsigned int __iomem *mem_ctrl_sleep;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2054)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2055) if (pb3400_mem_ctrl == NULL)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2056) return -ENOMEM;
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2057) mem_ctrl_sleep = pb3400_mem_ctrl + PB3400_MEM_CTRL_SLEEP;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2058)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2059) /* Set the memory controller to keep the memory refreshed
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2060) while we're asleep */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2061) for (i = 0x403f; i >= 0x4000; --i) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2062) out_be32(mem_ctrl_sleep, i);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2063) do {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2064) x = (in_be32(mem_ctrl_sleep) >> 16) & 0x3ff;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2065) } while (x == 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2066) if (x >= 0x100)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2067) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2068) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2069)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2070) /* Ask the PMU to put us to sleep */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2071) pmu_request(&sleep_req, NULL, 5, PMU_SLEEP, 'M', 'A', 'T', 'T');
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2072) pmu_wait_complete(&sleep_req);
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2073) pmu_unlock();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2074)
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2075) pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 1);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2076)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2077) asleep = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2078)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2079) /* Put the CPU into sleep mode */
21fe3301f11a9 (Benjamin Herrenschmidt 2005-11-07 16:41:59 +1100 2080) hid0 = mfspr(SPRN_HID0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2081) hid0 = (hid0 & ~(HID0_NAP | HID0_DOZE)) | HID0_SLEEP;
21fe3301f11a9 (Benjamin Herrenschmidt 2005-11-07 16:41:59 +1100 2082) mtspr(SPRN_HID0, hid0);
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2083) local_irq_enable();
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2084) msr = mfmsr() | MSR_POW;
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2085) while (asleep) {
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2086) mb();
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2087) mtmsr(msr);
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2088) isync();
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2089) }
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2090) local_irq_disable();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2091)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2092) /* OK, we're awake again, start restoring things */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2093) out_be32(mem_ctrl_sleep, 0x3f);
887ef35ae4eb2 (Paul Mackerras 2007-12-19 22:45:31 +1100 2094) pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, 0);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2095)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2096) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2097) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2098)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2099) #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2100)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2101) /*
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2102) * Support for /dev/pmu device
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2103) */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2104) #define RB_SIZE 0x10
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2105) struct pmu_private {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2106) struct list_head list;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2107) int rb_get;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2108) int rb_put;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2109) struct rb_entry {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2110) unsigned short len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2111) unsigned char data[16];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2112) } rb_buf[RB_SIZE];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2113) wait_queue_head_t wait;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2114) spinlock_t lock;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2115) #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2116) int backlight_locker;
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2117) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2118) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2119)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2120) static LIST_HEAD(all_pmu_pvt);
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2121) static DEFINE_SPINLOCK(all_pvt_lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2122)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2123) static void
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2124) pmu_pass_intr(unsigned char *data, int len)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2125) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2126) struct pmu_private *pp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2127) struct list_head *list;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2128) int i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2129) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2130)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2131) if (len > sizeof(pp->rb_buf[0].data))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2132) len = sizeof(pp->rb_buf[0].data);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2133) spin_lock_irqsave(&all_pvt_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2134) for (list = &all_pmu_pvt; (list = list->next) != &all_pmu_pvt; ) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2135) pp = list_entry(list, struct pmu_private, list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2136) spin_lock(&pp->lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2137) i = pp->rb_put + 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2138) if (i >= RB_SIZE)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2139) i = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2140) if (i != pp->rb_get) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2141) struct rb_entry *rp = &pp->rb_buf[pp->rb_put];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2142) rp->len = len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2143) memcpy(rp->data, data, len);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2144) pp->rb_put = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2145) wake_up_interruptible(&pp->wait);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2146) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2147) spin_unlock(&pp->lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2148) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2149) spin_unlock_irqrestore(&all_pvt_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2150) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2151)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2152) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2153) pmu_open(struct inode *inode, struct file *file)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2154) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2155) struct pmu_private *pp;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2156) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2157)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2158) pp = kmalloc(sizeof(struct pmu_private), GFP_KERNEL);
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 2159) if (!pp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2160) return -ENOMEM;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2161) pp->rb_get = pp->rb_put = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2162) spin_lock_init(&pp->lock);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2163) init_waitqueue_head(&pp->wait);
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 2164) mutex_lock(&pmu_info_proc_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2165) spin_lock_irqsave(&all_pvt_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2166) #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2167) pp->backlight_locker = 0;
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2168) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2169) list_add(&pp->list, &all_pmu_pvt);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2170) spin_unlock_irqrestore(&all_pvt_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2171) file->private_data = pp;
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 2172) mutex_unlock(&pmu_info_proc_mutex);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2173) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2174) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2175)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2176) static ssize_t
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2177) pmu_read(struct file *file, char __user *buf,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2178) size_t count, loff_t *ppos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2179) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2180) struct pmu_private *pp = file->private_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2181) DECLARE_WAITQUEUE(wait, current);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2182) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2183) int ret = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2184)
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 2185) if (count < 1 || !pp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2186) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2187)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2188) spin_lock_irqsave(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2189) add_wait_queue(&pp->wait, &wait);
111fbc68fd895 (Fabian Frederick 2015-02-20 19:12:53 +0100 2190) set_current_state(TASK_INTERRUPTIBLE);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2191)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2192) for (;;) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2193) ret = -EAGAIN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2194) if (pp->rb_get != pp->rb_put) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2195) int i = pp->rb_get;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2196) struct rb_entry *rp = &pp->rb_buf[i];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2197) ret = rp->len;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2198) spin_unlock_irqrestore(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2199) if (ret > count)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2200) ret = count;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2201) if (ret > 0 && copy_to_user(buf, rp->data, ret))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2202) ret = -EFAULT;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2203) if (++i >= RB_SIZE)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2204) i = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2205) spin_lock_irqsave(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2206) pp->rb_get = i;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2207) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2208) if (ret >= 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2209) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2210) if (file->f_flags & O_NONBLOCK)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2211) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2212) ret = -ERESTARTSYS;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2213) if (signal_pending(current))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2214) break;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2215) spin_unlock_irqrestore(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2216) schedule();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2217) spin_lock_irqsave(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2218) }
111fbc68fd895 (Fabian Frederick 2015-02-20 19:12:53 +0100 2219) __set_current_state(TASK_RUNNING);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2220) remove_wait_queue(&pp->wait, &wait);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2221) spin_unlock_irqrestore(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2222)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2223) return ret;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2224) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2225)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2226) static ssize_t
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2227) pmu_write(struct file *file, const char __user *buf,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2228) size_t count, loff_t *ppos)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2229) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2230) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2231) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2232)
afc9a42b7464f (Al Viro 2017-07-03 06:39:46 -0400 2233) static __poll_t
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2234) pmu_fpoll(struct file *filp, poll_table *wait)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2235) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2236) struct pmu_private *pp = filp->private_data;
afc9a42b7464f (Al Viro 2017-07-03 06:39:46 -0400 2237) __poll_t mask = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2238) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2239)
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 2240) if (!pp)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2241) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2242) poll_wait(filp, &pp->wait, wait);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2243) spin_lock_irqsave(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2244) if (pp->rb_get != pp->rb_put)
a9a08845e9acb (Linus Torvalds 2018-02-11 14:34:03 -0800 2245) mask |= EPOLLIN;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2246) spin_unlock_irqrestore(&pp->lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2247) return mask;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2248) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2249)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2250) static int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2251) pmu_release(struct inode *inode, struct file *file)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2252) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2253) struct pmu_private *pp = file->private_data;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2254) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2255)
d8731527acee5 (Mathieu Malaterre 2018-04-13 20:41:43 +0200 2256) if (pp) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2257) file->private_data = NULL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2258) spin_lock_irqsave(&all_pvt_lock, flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2259) list_del(&pp->list);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2260) spin_unlock_irqrestore(&all_pvt_lock, flags);
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2261)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2262) #if defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_PMAC_BACKLIGHT)
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2263) if (pp->backlight_locker)
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2264) pmac_backlight_enable();
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2265) #endif
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2266)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2267) kfree(pp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2268) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2269) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2270) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2271)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2272) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2273) static void pmac_suspend_disable_irqs(void)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2274) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2275) /* Call platform functions marked "on sleep" */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2276) pmac_pfunc_i2c_suspend();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2277) pmac_pfunc_base_suspend();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2278) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2279)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2280) static int powerbook_sleep(suspend_state_t state)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2281) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2282) int error = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2283)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2284) /* Wait for completion of async requests */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2285) while (!batt_req.complete)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2286) pmu_poll();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2287)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2288) /* Giveup the lazy FPU & vec so we don't have to back them
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2289) * up from the low level code
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2290) */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2291) enable_kernel_fp();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2292)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2293) #ifdef CONFIG_ALTIVEC
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2294) if (cpu_has_feature(CPU_FTR_ALTIVEC))
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2295) enable_kernel_altivec();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2296) #endif /* CONFIG_ALTIVEC */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2297)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2298) switch (pmu_kind) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2299) case PMU_OHARE_BASED:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2300) error = powerbook_sleep_3400();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2301) break;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2302) case PMU_HEATHROW_BASED:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2303) case PMU_PADDINGTON_BASED:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2304) error = powerbook_sleep_grackle();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2305) break;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2306) case PMU_KEYLARGO_BASED:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2307) error = powerbook_sleep_Core99();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2308) break;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2309) default:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2310) return -ENOSYS;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2311) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2312)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2313) if (error)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2314) return error;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2315)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2316) mdelay(100);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2317)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2318) return 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2319) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2320)
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2321) static void pmac_suspend_enable_irqs(void)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2322) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2323) /* Force a poll of ADB interrupts */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2324) adb_int_pending = 1;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2325) via_pmu_interrupt(0, NULL);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2326)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2327) mdelay(10);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2328)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2329) /* Call platform functions marked "on wake" */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2330) pmac_pfunc_base_resume();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2331) pmac_pfunc_i2c_resume();
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2332) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2333)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2334) static int pmu_sleep_valid(suspend_state_t state)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2335) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2336) return state == PM_SUSPEND_MEM
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2337) && (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) >= 0);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2338) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2339)
2f55ac072f534 (Lionel Debroux 2010-11-16 14:14:02 +0100 2340) static const struct platform_suspend_ops pmu_pm_ops = {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2341) .enter = powerbook_sleep,
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2342) .valid = pmu_sleep_valid,
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2343) };
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2344)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2345) static int register_pmu_pm_ops(void)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2346) {
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2347) if (pmu_kind == PMU_OHARE_BASED)
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2348) powerbook_sleep_init_3400();
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2349) ppc_md.suspend_disable_irqs = pmac_suspend_disable_irqs;
7ac5dde99eb9f (Scott Wood 2007-12-13 04:35:19 +1100 2350) ppc_md.suspend_enable_irqs = pmac_suspend_enable_irqs;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2351) suspend_set_ops(&pmu_pm_ops);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2352)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2353) return 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2354) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2355)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2356) device_initcall(register_pmu_pm_ops);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2357) #endif
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2358)
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2359) static int pmu_ioctl(struct file *filp,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2360) u_int cmd, u_long arg)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2361) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2362) __u32 __user *argp = (__u32 __user *)arg;
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2363) int error = -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2364)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2365) switch (cmd) {
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 2366) #ifdef CONFIG_PPC_PMAC
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2367) case PMU_IOC_SLEEP:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2368) if (!capable(CAP_SYS_ADMIN))
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2369) return -EACCES;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2370) return pm_suspend(PM_SUSPEND_MEM);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2371) case PMU_IOC_CAN_SLEEP:
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2372) if (pmac_call_feature(PMAC_FTR_SLEEP_STATE, NULL, 0, -1) < 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2373) return put_user(0, argp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2374) else
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2375) return put_user(1, argp);
c16a85a5aad47 (Finn Thain 2018-07-02 04:21:19 -0400 2376) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2377)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2378) #ifdef CONFIG_PMAC_BACKLIGHT_LEGACY
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2379) /* Compatibility ioctl's for backlight */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2380) case PMU_IOC_GET_BACKLIGHT:
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2381) {
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2382) int brightness;
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2383)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2384) brightness = pmac_backlight_get_legacy_brightness();
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2385) if (brightness < 0)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2386) return brightness;
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2387) else
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2388) return put_user(brightness, argp);
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2389)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2390) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2391) case PMU_IOC_SET_BACKLIGHT:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2392) {
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2393) int brightness;
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2394)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2395) error = get_user(brightness, argp);
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2396) if (error)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2397) return error;
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2398)
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2399) return pmac_backlight_set_legacy_brightness(brightness);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2400) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2401) #ifdef CONFIG_INPUT_ADBHID
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2402) case PMU_IOC_GRAB_BACKLIGHT: {
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2403) struct pmu_private *pp = filp->private_data;
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2404)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2405) if (pp->backlight_locker)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2406) return 0;
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2407)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2408) pp->backlight_locker = 1;
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2409) pmac_backlight_disable();
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2410)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2411) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2412) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2413) #endif /* CONFIG_INPUT_ADBHID */
5474c120aafe7 (Michael Hanselmann 2006-06-25 05:47:08 -0700 2414) #endif /* CONFIG_PMAC_BACKLIGHT_LEGACY */
4b755999d6e0c (Michael Hanselmann 2006-07-30 03:04:19 -0700 2415)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2416) case PMU_IOC_GET_MODEL:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2417) return put_user(pmu_kind, argp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2418) case PMU_IOC_HAS_ADB:
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2419) return put_user(pmu_has_adb, argp);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2420) }
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2421) return error;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2422) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2423)
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2424) static long pmu_unlocked_ioctl(struct file *filp,
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2425) u_int cmd, u_long arg)
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2426) {
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2427) int ret;
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2428)
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 2429) mutex_lock(&pmu_info_proc_mutex);
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2430) ret = pmu_ioctl(filp, cmd, arg);
d851b6e04ee97 (Arnd Bergmann 2010-06-02 14:28:52 +0200 2431) mutex_unlock(&pmu_info_proc_mutex);
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2432)
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2433) return ret;
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2434) }
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2435)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2436) #ifdef CONFIG_COMPAT
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2437) #define PMU_IOC_GET_BACKLIGHT32 _IOR('B', 1, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2438) #define PMU_IOC_SET_BACKLIGHT32 _IOW('B', 2, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2439) #define PMU_IOC_GET_MODEL32 _IOR('B', 3, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2440) #define PMU_IOC_HAS_ADB32 _IOR('B', 4, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2441) #define PMU_IOC_CAN_SLEEP32 _IOR('B', 5, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2442) #define PMU_IOC_GRAB_BACKLIGHT32 _IOR('B', 6, compat_size_t)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2443)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2444) static long compat_pmu_ioctl (struct file *filp, u_int cmd, u_long arg)
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2445) {
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2446) switch (cmd) {
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2447) case PMU_IOC_SLEEP:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2448) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2449) case PMU_IOC_GET_BACKLIGHT32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2450) cmd = PMU_IOC_GET_BACKLIGHT;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2451) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2452) case PMU_IOC_SET_BACKLIGHT32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2453) cmd = PMU_IOC_SET_BACKLIGHT;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2454) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2455) case PMU_IOC_GET_MODEL32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2456) cmd = PMU_IOC_GET_MODEL;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2457) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2458) case PMU_IOC_HAS_ADB32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2459) cmd = PMU_IOC_HAS_ADB;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2460) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2461) case PMU_IOC_CAN_SLEEP32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2462) cmd = PMU_IOC_CAN_SLEEP;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2463) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2464) case PMU_IOC_GRAB_BACKLIGHT32:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2465) cmd = PMU_IOC_GRAB_BACKLIGHT;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2466) break;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2467) default:
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2468) return -ENOIOCTLCMD;
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2469) }
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2470) return pmu_unlocked_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2471) }
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2472) #endif
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2473)
fa027c2a0a0d6 (Arjan van de Ven 2007-02-12 00:55:33 -0800 2474) static const struct file_operations pmu_device_fops = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2475) .read = pmu_read,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2476) .write = pmu_write,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2477) .poll = pmu_fpoll,
55929332c92e5 (Arnd Bergmann 2010-04-27 00:24:05 +0200 2478) .unlocked_ioctl = pmu_unlocked_ioctl,
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2479) #ifdef CONFIG_COMPAT
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2480) .compat_ioctl = compat_pmu_ioctl,
4cc4587fb14bb (Andreas Schwab 2010-08-22 06:23:17 +0000 2481) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2482) .open = pmu_open,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2483) .release = pmu_release,
6038f373a3dc1 (Arnd Bergmann 2010-08-15 18:52:59 +0200 2484) .llseek = noop_llseek,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2485) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2486)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2487) static struct miscdevice pmu_device = {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2488) PMU_MINOR, "pmu", &pmu_device_fops
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2489) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2490)
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2491) static int pmu_device_init(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2492) {
c57902d52e2d6 (Finn Thain 2018-07-02 04:21:18 -0400 2493) if (pmu_state == uninitialized)
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2494) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2495) if (misc_register(&pmu_device) < 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2496) printk(KERN_ERR "via-pmu: cannot register misc device.\n");
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2497) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2498) }
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2499) device_initcall(pmu_device_init);
8c8709334cec8 (Benjamin Herrenschmidt 2005-06-27 14:36:34 -0700 2500)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2501)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2502) #ifdef DEBUG_SLEEP
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2503) static inline void
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2504) polled_handshake(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2505) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2506) via2[B] &= ~TREQ; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2507) while ((via2[B] & TACK) != 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2508) ;
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2509) via2[B] |= TREQ; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2510) while ((via2[B] & TACK) == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2511) ;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2512) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2513)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2514) static inline void
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2515) polled_send_byte(int x)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2516) {
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2517) via1[ACR] |= SR_OUT | SR_EXT; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2518) via1[SR] = x; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2519) polled_handshake();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2520) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2521)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2522) static inline int
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2523) polled_recv_byte(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2524) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2525) int x;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2526)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2527) via1[ACR] = (via1[ACR] & ~SR_OUT) | SR_EXT; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2528) x = via1[SR]; eieio();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2529) polled_handshake();
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2530) x = via1[SR]; eieio();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2531) return x;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2532) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2533)
aacaf9bd9646f (Jon Loeliger 2005-09-17 10:36:54 -0500 2534) int
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2535) pmu_polled_request(struct adb_request *req)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2536) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2537) unsigned long flags;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2538) int i, l, c;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2539)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2540) req->complete = 1;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2541) c = req->data[0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2542) l = pmu_data_len[c][0];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2543) if (l >= 0 && req->nbytes != l + 1)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2544) return -EINVAL;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2545)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2546) local_irq_save(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2547) while (pmu_state != idle)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2548) pmu_poll();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2549)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2550) while ((via2[B] & TACK) == 0)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2551) ;
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2552) polled_send_byte(c);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2553) if (l < 0) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2554) l = req->nbytes - 1;
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2555) polled_send_byte(l);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2556) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2557) for (i = 1; i <= l; ++i)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2558) polled_send_byte(req->data[i]);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2559)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2560) l = pmu_data_len[c][1];
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2561) if (l < 0)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2562) l = polled_recv_byte();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2563) for (i = 0; i < l; ++i)
c70c35da52c06 (Finn Thain 2018-07-02 04:21:18 -0400 2564) req->reply[i + req->reply_len] = polled_recv_byte();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2565)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2566) if (req->done)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2567) (*req->done)(req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2568)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2569) local_irq_restore(flags);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2570) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2571) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2572)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2573) /* N.B. This doesn't work on the 3400 */
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2574) void pmu_blink(int n)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2575) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2576) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2577)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2578) memset(&req, 0, sizeof(req));
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2579)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2580) for (; n > 0; --n) {
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2581) req.nbytes = 4;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2582) req.done = NULL;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2583) req.data[0] = 0xee;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2584) req.data[1] = 4;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2585) req.data[2] = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2586) req.data[3] = 1;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2587) req.reply[0] = ADB_RET_OK;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2588) req.reply_len = 1;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2589) req.reply_expected = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2590) pmu_polled_request(&req);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2591) mdelay(50);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2592) req.nbytes = 4;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2593) req.done = NULL;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2594) req.data[0] = 0xee;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2595) req.data[1] = 4;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2596) req.data[2] = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2597) req.data[3] = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2598) req.reply[0] = ADB_RET_OK;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2599) req.reply_len = 1;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2600) req.reply_expected = 0;
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2601) pmu_polled_request(&req);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2602) mdelay(50);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2603) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2604) mdelay(50);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2605) }
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2606) #endif /* DEBUG_SLEEP */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2607)
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2608) #if defined(CONFIG_SUSPEND) && defined(CONFIG_PPC32)
f596575e81999 (Johannes Berg 2007-05-08 01:08:00 +1000 2609) int pmu_sys_suspended;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2610)
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2611) static int pmu_syscore_suspend(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2612) {
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2613) /* Suspend PMU event interrupts */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2614) pmu_suspend();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2615) pmu_sys_suspended = 1;
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2616)
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2617) #ifdef CONFIG_PMAC_BACKLIGHT
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2618) /* Tell backlight code not to muck around with the chip anymore */
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2619) pmu_backlight_set_sleep(1);
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2620) #endif
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2621)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2622) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2623) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2624)
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2625) static void pmu_syscore_resume(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2626) {
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2627) struct adb_request req;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2628)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2629) if (!pmu_sys_suspended)
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2630) return;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2631)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2632) /* Tell PMU we are ready */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2633) pmu_request(&req, NULL, 2, PMU_SYSTEM_READY, 2);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2634) pmu_wait_complete(&req);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2635)
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2636) #ifdef CONFIG_PMAC_BACKLIGHT
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2637) /* Tell backlight code it can use the chip again */
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2638) pmu_backlight_set_sleep(0);
0094f2cdcfb6f (Benjamin Herrenschmidt 2007-12-20 15:00:21 +1100 2639) #endif
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2640) /* Resume PMU event interrupts */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2641) pmu_resume();
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2642) pmu_sys_suspended = 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2643) }
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2644)
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2645) static struct syscore_ops pmu_syscore_ops = {
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2646) .suspend = pmu_syscore_suspend,
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2647) .resume = pmu_syscore_resume,
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2648) };
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2649)
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2650) static int pmu_syscore_register(void)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2651) {
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2652) register_syscore_ops(&pmu_syscore_ops);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2653)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2654) return 0;
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2655) }
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2656) subsys_initcall(pmu_syscore_register);
e83b906c99eb8 (Benjamin Herrenschmidt 2011-05-20 15:37:22 +1000 2657) #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2658)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2659) EXPORT_SYMBOL(pmu_request);
730745a5c4509 (Benjamin Herrenschmidt 2006-01-07 11:30:44 +1100 2660) EXPORT_SYMBOL(pmu_queue_request);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2661) EXPORT_SYMBOL(pmu_poll);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2662) EXPORT_SYMBOL(pmu_poll_adb);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2663) EXPORT_SYMBOL(pmu_wait_complete);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2664) EXPORT_SYMBOL(pmu_suspend);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2665) EXPORT_SYMBOL(pmu_resume);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2666) EXPORT_SYMBOL(pmu_unlock);
620a245978d00 (Guido Guenther 2008-03-09 06:20:17 +1100 2667) #if defined(CONFIG_PPC32)
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2668) EXPORT_SYMBOL(pmu_enable_irled);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2669) EXPORT_SYMBOL(pmu_battery_count);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2670) EXPORT_SYMBOL(pmu_batteries);
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2671) EXPORT_SYMBOL(pmu_power_flags);
f91266edba3c6 (Johannes Berg 2007-12-12 01:25:59 +1100 2672) #endif /* CONFIG_SUSPEND && CONFIG_PPC32 */
^1da177e4c3f4 (Linus Torvalds 2005-04-16 15:20:36 -0700 2673)