aboutsummaryrefslogtreecommitdiffstats
path: root/ubuntu/omnibook/ec.c
blob: 714ce4ac0d98d1745fb2a36fd6b9e16fecae2a38 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*
 * ec.c -- low level functions to access Embedded Controller,
 * 
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 * 
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * Written by Soós Péter <sp@osb.hu>, 2002-2004
 * Modified by Mathieu Bérard <mathieu.berard@crans.org>, 2006
 */

#include "omnibook.h"

#include <linux/types.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/ioport.h>

#include <asm/io.h>
#include "hardware.h"

/*
 * Interrupt control
 */

static DEFINE_SPINLOCK(omnibook_ec_lock);

/*
 * Registers of the embedded controller
 */

#define OMNIBOOK_EC_DATA		0x62
#define OMNIBOOK_EC_SC			0x66

/*
 * Embedded controller status register bits
 */

#define OMNIBOOK_EC_STAT_OBF		0x01	/* Output buffer full */
#define OMNIBOOK_EC_STAT_IBF		0x02	/* Input buffer full */


/*
 * Embedded controller commands
 */

#define OMNIBOOK_EC_CMD_READ		0x80
#define OMNIBOOK_EC_CMD_WRITE		0x81

/*
 * Wait for embedded controller buffer
 */

static int omnibook_ec_wait(u8 event)
{
	int timeout = OMNIBOOK_TIMEOUT;

	switch (event) {
	case OMNIBOOK_EC_STAT_OBF:
		while (!(inb(OMNIBOOK_EC_SC) & event) && timeout--)
			mdelay(1);
		break;
	case OMNIBOOK_EC_STAT_IBF:
		while ((inb(OMNIBOOK_EC_SC) & event) && timeout--)
			mdelay(1);
		break;
	default:
		return -EINVAL;
	}
	if (timeout > 0)
		return 0;
	return -ETIME;
}

/*
 * Read from the embedded controller
 * Decide at run-time if we can use the much cleaner ACPI EC driver instead of
 * this implementation, this is the case if ACPI has been compiled and is not
 * disabled.
 */

static int omnibook_ec_read(const struct omnibook_operation *io_op, u8 * data)
{
	int retval;

#ifdef CONFIG_ACPI_EC
	if (likely(!acpi_disabled)) {
		retval = ec_read((u8) io_op->read_addr, data);
		if (io_op->read_mask)
			*data &= io_op->read_mask;
//		dprintk("ACPI EC read at %lx success %i.\n", io_op->read_addr, retval);
		return retval;
	}
#endif
	spin_lock_irq(&omnibook_ec_lock);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_IBF);
	if (retval)
		goto end;
	outb(OMNIBOOK_EC_CMD_READ, OMNIBOOK_EC_SC);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_IBF);
	if (retval)
		goto end;
	outb((u8) io_op->read_addr, OMNIBOOK_EC_DATA);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_OBF);
	if (retval)
		goto end;
	*data = inb(OMNIBOOK_EC_DATA);
	if (io_op->read_mask)
		*data &= io_op->read_mask;
      end:
	spin_unlock_irq(&omnibook_ec_lock);
//	dprintk("Custom EC read at %lx success %i.\n", io_op->read_addr, retval);
	return retval;
}

/*
 * Write to the embedded controller:
 * If OMNIBOOK_LEGACY is set, decide at run-time if we can use the much cleaner 
 * ACPI EC driver instead of this legacy implementation. 
 * This is the case if ACPI has been compiled and is not
 * disabled.
 * If OMNIBOOK_LEGACY is unset, we drop our custoim implementation
 */

static int omnibook_ec_write(const struct omnibook_operation *io_op, u8 data)
{
	int retval;

#ifdef CONFIG_ACPI_EC
	if (likely(!acpi_disabled)) {
		retval = ec_write((u8) io_op->write_addr, data);
//		dprintk("ACPI EC write at %lx success %i.\n", io_op->write_addr, retval);
		return retval;
	}
#endif

	spin_lock_irq(&omnibook_ec_lock);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_IBF);
	if (retval)
		goto end;
	outb(OMNIBOOK_EC_CMD_WRITE, OMNIBOOK_EC_SC);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_IBF);
	if (retval)
		goto end;
	outb((u8) io_op->write_addr, OMNIBOOK_EC_DATA);
	retval = omnibook_ec_wait(OMNIBOOK_EC_STAT_IBF);
	if (retval)
		goto end;
	outb(data, OMNIBOOK_EC_DATA);
      end:
	spin_unlock_irq(&omnibook_ec_lock);
//	dprintk("Custom EC write at %lx success %i.\n", io_op->write_addr, retval);
	return retval;
}

static int omnibook_ec_display(const struct omnibook_operation *io_op, unsigned int *state)
{
	int retval;
	u8 raw_state;

	retval = __backend_byte_read(io_op, &raw_state);
	if (retval < 0)
		return retval;

	*state = !!(raw_state) & DISPLAY_CRT_DET;

	return DISPLAY_CRT_DET;
}

/*
 * Backend interface declarations
 */

struct omnibook_backend ec_backend = {
	.name = "ec",
	.byte_read = omnibook_ec_read,
	.byte_write = omnibook_ec_write,
	.display_get = omnibook_ec_display,
};

/* End of file */