~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/pcmcia/sa1100_nanoengine.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * drivers/pcmcia/sa1100_nanoengine.c
 
3
 *
 
4
 * PCMCIA implementation routines for BSI nanoEngine.
 
5
 *
 
6
 * In order to have a fully functional pcmcia subsystem in a BSE nanoEngine
 
7
 * board you should carefully read this:
 
8
 * http://cambuca.ldhs.cetuc.puc-rio.br/nanoengine/
 
9
 *
 
10
 * Copyright (C) 2010 Marcelo Roberto Jimenez <mroberto@cpti.cetuc.puc-rio.br>
 
11
 *
 
12
 * Based on original work for kernel 2.4 by
 
13
 * Miguel Freitas <miguel@cpti.cetuc.puc-rio.br>
 
14
 *
 
15
 * This program is free software; you can redistribute it and/or modify
 
16
 * it under the terms of the GNU General Public License version 2 as
 
17
 * published by the Free Software Foundation.
 
18
 *
 
19
 */
 
20
#include <linux/device.h>
 
21
#include <linux/errno.h>
 
22
#include <linux/interrupt.h>
 
23
#include <linux/irq.h>
 
24
#include <linux/init.h>
 
25
#include <linux/kernel.h>
 
26
#include <linux/module.h>
 
27
#include <linux/signal.h>
 
28
 
 
29
#include <asm/mach-types.h>
 
30
#include <asm/irq.h>
 
31
 
 
32
#include <mach/hardware.h>
 
33
#include <mach/nanoengine.h>
 
34
 
 
35
#include "sa1100_generic.h"
 
36
 
 
37
static struct pcmcia_irqs irqs_skt0[] = {
 
38
        /* socket, IRQ, name */
 
39
        { 0, NANOENGINE_IRQ_GPIO_PC_CD0, "PC CD0" },
 
40
};
 
41
 
 
42
static struct pcmcia_irqs irqs_skt1[] = {
 
43
        /* socket, IRQ, name */
 
44
        { 1, NANOENGINE_IRQ_GPIO_PC_CD1, "PC CD1" },
 
45
};
 
46
 
 
47
struct nanoengine_pins {
 
48
        unsigned input_pins;
 
49
        unsigned output_pins;
 
50
        unsigned clear_outputs;
 
51
        unsigned transition_pins;
 
52
        unsigned pci_irq;
 
53
        struct pcmcia_irqs *pcmcia_irqs;
 
54
        unsigned pcmcia_irqs_size;
 
55
};
 
56
 
 
57
static struct nanoengine_pins nano_skts[] = {
 
58
        {
 
59
                .input_pins             = GPIO_PC_READY0 | GPIO_PC_CD0,
 
60
                .output_pins            = GPIO_PC_RESET0,
 
61
                .clear_outputs          = GPIO_PC_RESET0,
 
62
                .transition_pins        = NANOENGINE_IRQ_GPIO_PC_CD0,
 
63
                .pci_irq                = NANOENGINE_IRQ_GPIO_PC_READY0,
 
64
                .pcmcia_irqs            = irqs_skt0,
 
65
                .pcmcia_irqs_size       = ARRAY_SIZE(irqs_skt0)
 
66
        }, {
 
67
                .input_pins             = GPIO_PC_READY1 | GPIO_PC_CD1,
 
68
                .output_pins            = GPIO_PC_RESET1,
 
69
                .clear_outputs          = GPIO_PC_RESET1,
 
70
                .transition_pins        = NANOENGINE_IRQ_GPIO_PC_CD1,
 
71
                .pci_irq                = NANOENGINE_IRQ_GPIO_PC_READY1,
 
72
                .pcmcia_irqs            = irqs_skt1,
 
73
                .pcmcia_irqs_size       = ARRAY_SIZE(irqs_skt1)
 
74
        }
 
75
};
 
76
 
 
77
unsigned num_nano_pcmcia_sockets = ARRAY_SIZE(nano_skts);
 
78
 
 
79
static int nanoengine_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
 
80
{
 
81
        unsigned i = skt->nr;
 
82
 
 
83
        if (i >= num_nano_pcmcia_sockets)
 
84
                return -ENXIO;
 
85
 
 
86
        GPDR &= ~nano_skts[i].input_pins;
 
87
        GPDR |= nano_skts[i].output_pins;
 
88
        GPCR = nano_skts[i].clear_outputs;
 
89
        irq_set_irq_type(nano_skts[i].transition_pins, IRQ_TYPE_EDGE_BOTH);
 
90
        skt->socket.pci_irq = nano_skts[i].pci_irq;
 
91
 
 
92
        return soc_pcmcia_request_irqs(skt,
 
93
                nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
 
94
}
 
95
 
 
96
/*
 
97
 * Release all resources.
 
98
 */
 
99
static void nanoengine_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
 
100
{
 
101
        unsigned i = skt->nr;
 
102
 
 
103
        if (i >= num_nano_pcmcia_sockets)
 
104
                return;
 
105
 
 
106
        soc_pcmcia_free_irqs(skt,
 
107
                nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
 
108
}
 
109
 
 
110
static int nanoengine_pcmcia_configure_socket(
 
111
        struct soc_pcmcia_socket *skt, const socket_state_t *state)
 
112
{
 
113
        unsigned reset;
 
114
        unsigned i = skt->nr;
 
115
 
 
116
        if (i >= num_nano_pcmcia_sockets)
 
117
                return -ENXIO;
 
118
 
 
119
        switch (i) {
 
120
        case 0:
 
121
                reset = GPIO_PC_RESET0;
 
122
                break;
 
123
        case 1:
 
124
                reset = GPIO_PC_RESET1;
 
125
                break;
 
126
        default:
 
127
                return -ENXIO;
 
128
        }
 
129
 
 
130
        if (state->flags & SS_RESET)
 
131
                GPSR = reset;
 
132
        else
 
133
                GPCR = reset;
 
134
 
 
135
        return 0;
 
136
}
 
137
 
 
138
static void nanoengine_pcmcia_socket_state(
 
139
        struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
 
140
{
 
141
        unsigned long levels = GPLR;
 
142
        unsigned i = skt->nr;
 
143
 
 
144
        if (i >= num_nano_pcmcia_sockets)
 
145
                return;
 
146
 
 
147
        memset(state, 0, sizeof(struct pcmcia_state));
 
148
        switch (i) {
 
149
        case 0:
 
150
                state->ready = (levels & GPIO_PC_READY0) ? 1 : 0;
 
151
                state->detect = !(levels & GPIO_PC_CD0) ? 1 : 0;
 
152
                break;
 
153
        case 1:
 
154
                state->ready = (levels & GPIO_PC_READY1) ? 1 : 0;
 
155
                state->detect = !(levels & GPIO_PC_CD1) ? 1 : 0;
 
156
                break;
 
157
        default:
 
158
                return;
 
159
        }
 
160
        state->bvd1 = 1;
 
161
        state->bvd2 = 1;
 
162
        state->wrprot = 0; /* Not available */
 
163
        state->vs_3v = 1; /* Can only apply 3.3V */
 
164
        state->vs_Xv = 0;
 
165
}
 
166
 
 
167
/*
 
168
 * Enable card status IRQs on (re-)initialisation.  This can
 
169
 * be called at initialisation, power management event, or
 
170
 * pcmcia event.
 
171
 */
 
172
static void nanoengine_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
 
173
{
 
174
        unsigned i = skt->nr;
 
175
 
 
176
        if (i >= num_nano_pcmcia_sockets)
 
177
                return;
 
178
 
 
179
        soc_pcmcia_enable_irqs(skt,
 
180
                nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
 
181
}
 
182
 
 
183
/*
 
184
 * Disable card status IRQs on suspend.
 
185
 */
 
186
static void nanoengine_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
 
187
{
 
188
        unsigned i = skt->nr;
 
189
 
 
190
        if (i >= num_nano_pcmcia_sockets)
 
191
                return;
 
192
 
 
193
        soc_pcmcia_disable_irqs(skt,
 
194
                nano_skts[i].pcmcia_irqs, nano_skts[i].pcmcia_irqs_size);
 
195
}
 
196
 
 
197
static struct pcmcia_low_level nanoengine_pcmcia_ops = {
 
198
        .owner                  = THIS_MODULE,
 
199
 
 
200
        .hw_init                = nanoengine_pcmcia_hw_init,
 
201
        .hw_shutdown            = nanoengine_pcmcia_hw_shutdown,
 
202
 
 
203
        .configure_socket       = nanoengine_pcmcia_configure_socket,
 
204
        .socket_state           = nanoengine_pcmcia_socket_state,
 
205
        .socket_init            = nanoengine_pcmcia_socket_init,
 
206
        .socket_suspend         = nanoengine_pcmcia_socket_suspend,
 
207
};
 
208
 
 
209
int pcmcia_nanoengine_init(struct device *dev)
 
210
{
 
211
        int ret = -ENODEV;
 
212
 
 
213
        if (machine_is_nanoengine())
 
214
                ret = sa11xx_drv_pcmcia_probe(
 
215
                        dev, &nanoengine_pcmcia_ops, 0, 2);
 
216
 
 
217
        return ret;
 
218
}
 
219