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/bios.h>
26 #include <subdev/bios/gpio.h>
31 nouveau_gpio_drive(struct nouveau_gpio
*gpio
,
32 int idx
, int line
, int dir
, int out
)
34 const struct nouveau_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
35 return impl
->drive
? impl
->drive(gpio
, line
, dir
, out
) : -ENODEV
;
39 nouveau_gpio_sense(struct nouveau_gpio
*gpio
, int idx
, int line
)
41 const struct nouveau_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
42 return impl
->sense
? impl
->sense(gpio
, line
) : -ENODEV
;
46 nouveau_gpio_find(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
47 struct dcb_gpio_func
*func
)
49 struct nouveau_bios
*bios
= nouveau_bios(gpio
);
53 if (line
== 0xff && tag
== 0xff)
56 data
= dcb_gpio_match(bios
, idx
, tag
, line
, &ver
, &len
, func
);
60 /* Apple iMac G4 NV18 */
61 if (nv_device_match(nv_object(gpio
), 0x0189, 0x10de, 0x0010)) {
62 if (tag
== DCB_GPIO_TVDAC0
) {
63 *func
= (struct dcb_gpio_func
) {
64 .func
= DCB_GPIO_TVDAC0
,
77 nouveau_gpio_set(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
, int state
)
79 struct dcb_gpio_func func
;
82 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
84 int dir
= !!(func
.log
[state
] & 0x02);
85 int out
= !!(func
.log
[state
] & 0x01);
86 ret
= nouveau_gpio_drive(gpio
, idx
, func
.line
, dir
, out
);
93 nouveau_gpio_get(struct nouveau_gpio
*gpio
, int idx
, u8 tag
, u8 line
)
95 struct dcb_gpio_func func
;
98 ret
= nouveau_gpio_find(gpio
, idx
, tag
, line
, &func
);
100 ret
= nouveau_gpio_sense(gpio
, idx
, func
.line
);
102 ret
= (ret
== (func
.log
[1] & 1));
109 nouveau_gpio_intr_disable(struct nouveau_event
*event
, int type
, int index
)
111 struct nouveau_gpio
*gpio
= nouveau_gpio(event
->priv
);
112 const struct nouveau_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
113 impl
->intr_mask(gpio
, NVKM_GPIO_TOGGLED
, 1 << index
, 0);
117 nouveau_gpio_intr_enable(struct nouveau_event
*event
, int type
, int index
)
119 struct nouveau_gpio
*gpio
= nouveau_gpio(event
->priv
);
120 const struct nouveau_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
121 impl
->intr_mask(gpio
, NVKM_GPIO_TOGGLED
, 1 << index
, 1 << index
);
125 nouveau_gpio_intr(struct nouveau_subdev
*subdev
)
127 struct nouveau_gpio
*gpio
= nouveau_gpio(subdev
);
128 const struct nouveau_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
131 impl
->intr_stat(gpio
, &hi
, &lo
);
133 for (i
= 0; (hi
| lo
) && i
< impl
->lines
; i
++) {
134 if ((hi
| lo
) & (1 << i
))
135 nouveau_event_trigger(gpio
->events
, 1, i
);
140 _nouveau_gpio_fini(struct nouveau_object
*object
, bool suspend
)
142 const struct nouveau_gpio_impl
*impl
= (void *)object
->oclass
;
143 struct nouveau_gpio
*gpio
= nouveau_gpio(object
);
144 u32 mask
= (1 << impl
->lines
) - 1;
146 impl
->intr_mask(gpio
, NVKM_GPIO_TOGGLED
, mask
, 0);
147 impl
->intr_stat(gpio
, &mask
, &mask
);
149 return nouveau_subdev_fini(&gpio
->base
, suspend
);
152 static struct dmi_system_id gpio_reset_ids
[] = {
154 .ident
= "Apple Macbook 10,1",
156 DMI_MATCH(DMI_SYS_VENDOR
, "Apple Inc."),
157 DMI_MATCH(DMI_PRODUCT_NAME
, "MacBookPro10,1"),
164 _nouveau_gpio_init(struct nouveau_object
*object
)
166 struct nouveau_gpio
*gpio
= nouveau_gpio(object
);
169 ret
= nouveau_subdev_init(&gpio
->base
);
173 if (gpio
->reset
&& dmi_check_system(gpio_reset_ids
))
174 gpio
->reset(gpio
, DCB_GPIO_UNUSED
);
180 _nouveau_gpio_dtor(struct nouveau_object
*object
)
182 struct nouveau_gpio
*gpio
= (void *)object
;
183 nouveau_event_destroy(&gpio
->events
);
184 nouveau_subdev_destroy(&gpio
->base
);
188 nouveau_gpio_create_(struct nouveau_object
*parent
,
189 struct nouveau_object
*engine
,
190 struct nouveau_oclass
*oclass
,
191 int length
, void **pobject
)
193 const struct nouveau_gpio_impl
*impl
= (void *)oclass
;
194 struct nouveau_gpio
*gpio
;
197 ret
= nouveau_subdev_create_(parent
, engine
, oclass
, 0, "GPIO", "gpio",
203 gpio
->find
= nouveau_gpio_find
;
204 gpio
->set
= nouveau_gpio_set
;
205 gpio
->get
= nouveau_gpio_get
;
206 gpio
->reset
= impl
->reset
;
208 ret
= nouveau_event_create(1, impl
->lines
, &gpio
->events
);
212 gpio
->events
->priv
= gpio
;
213 gpio
->events
->enable
= nouveau_gpio_intr_enable
;
214 gpio
->events
->disable
= nouveau_gpio_intr_disable
;
215 nv_subdev(gpio
)->intr
= nouveau_gpio_intr
;
220 _nouveau_gpio_ctor(struct nouveau_object
*parent
, struct nouveau_object
*engine
,
221 struct nouveau_oclass
*oclass
, void *data
, u32 size
,
222 struct nouveau_object
**pobject
)
224 struct nouveau_gpio
*gpio
;
227 ret
= nouveau_gpio_create(parent
, engine
, oclass
, &gpio
);
228 *pobject
= nv_object(gpio
);