2 * Copyright 2011 Red Hat Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
25 #include <subdev/gpio.h>
26 #include <subdev/bios.h>
27 #include <subdev/bios/gpio.h>
30 nouveau_gpio_drive(struct nouveau_gpio
*gpio
,
31 int idx
, int line
, int dir
, int out
)
33 return gpio
->drive
? gpio
->drive(gpio
, line
, dir
, out
) : -ENODEV
;
37 nouveau_gpio_sense(struct nouveau_gpio
*gpio
, int idx
, int line
)
39 return gpio
->sense
? gpio
->sense(gpio
, line
) : -ENODEV
;
43 nouveau_gpio_find(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
44 struct dcb_gpio_func
*func
)
46 struct nouveau_bios
*bios
= nouveau_bios(gpio
);
50 if (line
== 0xff && tag
== 0xff)
53 data
= dcb_gpio_match(bios
, idx
, tag
, line
, &ver
, &len
, func
);
57 /* Apple iMac G4 NV18 */
58 if (nv_device_match(nv_object(gpio
), 0x0189, 0x10de, 0x0010)) {
59 if (tag
== DCB_GPIO_TVDAC0
) {
60 *func
= (struct dcb_gpio_func
) {
61 .func
= DCB_GPIO_TVDAC0
,
74 nouveau_gpio_set(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
, int state
)
76 struct dcb_gpio_func func
;
79 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
81 int dir
= !!(func
.log
[state
] & 0x02);
82 int out
= !!(func
.log
[state
] & 0x01);
83 ret
= nouveau_gpio_drive(gpio
, idx
, func
.line
, dir
, out
);
90 nouveau_gpio_get(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
)
92 struct dcb_gpio_func func
;
95 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
97 ret
= nouveau_gpio_sense(gpio
, idx
, func
.line
);
99 ret
= (ret
== (func
.log
[1] & 1));
106 nouveau_gpio_irq(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
, bool on
)
108 struct dcb_gpio_func func
;
111 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
113 if (idx
== 0 && gpio
->irq_enable
)
114 gpio
->irq_enable(gpio
, func
.line
, on
);
123 struct nouveau_gpio
*gpio
;
124 struct list_head head
;
125 struct work_struct work
;
127 struct dcb_gpio_func func
;
128 void (*handler
)(void *, int);
134 nouveau_gpio_isr_bh(struct work_struct
*work
)
136 struct gpio_isr
*isr
= container_of(work
, struct gpio_isr
, work
);
137 struct nouveau_gpio
*gpio
= isr
->gpio
;
141 state
= nouveau_gpio_get(gpio
, isr
->idx
, isr
->func
.func
,
144 isr
->handler(isr
->data
, state
);
146 spin_lock_irqsave(&gpio
->lock
, flags
);
147 isr
->inhibit
= false;
148 spin_unlock_irqrestore(&gpio
->lock
, flags
);
152 nouveau_gpio_isr_run(struct nouveau_gpio
*gpio
, int idx
, u32 line_mask
)
154 struct gpio_isr
*isr
;
159 spin_lock(&gpio
->lock
);
160 list_for_each_entry(isr
, &gpio
->isr
, head
) {
161 if (line_mask
& (1 << isr
->func
.line
)) {
165 schedule_work(&isr
->work
);
168 spin_unlock(&gpio
->lock
);
172 nouveau_gpio_isr_add(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
173 void (*handler
)(void *, int), void *data
)
175 struct gpio_isr
*isr
;
179 isr
= kzalloc(sizeof(*isr
), GFP_KERNEL
);
183 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &isr
->func
);
189 INIT_WORK(&isr
->work
, nouveau_gpio_isr_bh
);
191 isr
->handler
= handler
;
195 spin_lock_irqsave(&gpio
->lock
, flags
);
196 list_add(&isr
->head
, &gpio
->isr
);
197 spin_unlock_irqrestore(&gpio
->lock
, flags
);
202 nouveau_gpio_isr_del(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
203 void (*handler
)(void *, int), void *data
)
205 struct gpio_isr
*isr
, *tmp
;
206 struct dcb_gpio_func func
;
211 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
213 spin_lock_irqsave(&gpio
->lock
, flags
);
214 list_for_each_entry_safe(isr
, tmp
, &gpio
->isr
, head
) {
215 if (memcmp(&isr
->func
, &func
, sizeof(func
)) ||
217 isr
->handler
!= handler
|| isr
->data
!= data
)
219 list_move_tail(&isr
->head
, &tofree
);
221 spin_unlock_irqrestore(&gpio
->lock
, flags
);
223 list_for_each_entry_safe(isr
, tmp
, &tofree
, head
) {
224 flush_work(&isr
->work
);
231 nouveau_gpio_create_(struct nouveau_object
*parent
,
232 struct nouveau_object
*engine
,
233 struct nouveau_oclass
*oclass
, int length
, void **pobject
)
235 struct nouveau_gpio
*gpio
;
238 ret
= nouveau_subdev_create_(parent
, engine
, oclass
, 0, "GPIO", "gpio",
244 gpio
->find
= nouveau_gpio_find
;
245 gpio
->set
= nouveau_gpio_set
;
246 gpio
->get
= nouveau_gpio_get
;
247 gpio
->irq
= nouveau_gpio_irq
;
248 gpio
->isr_run
= nouveau_gpio_isr_run
;
249 gpio
->isr_add
= nouveau_gpio_isr_add
;
250 gpio
->isr_del
= nouveau_gpio_isr_del
;
251 INIT_LIST_HEAD(&gpio
->isr
);
252 spin_lock_init(&gpio
->lock
);
256 static struct dmi_system_id gpio_reset_ids
[] = {
258 .ident
= "Apple Macbook 10,1",
260 DMI_MATCH(DMI_SYS_VENDOR
, "Apple Inc."),
261 DMI_MATCH(DMI_PRODUCT_NAME
, "MacBookPro10,1"),
268 nouveau_gpio_init(struct nouveau_gpio
*gpio
)
270 int ret
= nouveau_subdev_init(&gpio
->base
);
271 if (ret
== 0 && gpio
->reset
) {
272 if (dmi_check_system(gpio_reset_ids
))
273 gpio
->reset(gpio
, DCB_GPIO_UNUSED
);