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.
26 #include <core/device.h>
27 #include <core/notify.h>
30 nvkm_gpio_drive(struct nvkm_gpio
*gpio
, int idx
, int line
, int dir
, int out
)
32 const struct nvkm_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
33 return impl
->drive
? impl
->drive(gpio
, line
, dir
, out
) : -ENODEV
;
37 nvkm_gpio_sense(struct nvkm_gpio
*gpio
, int idx
, int line
)
39 const struct nvkm_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
40 return impl
->sense
? impl
->sense(gpio
, line
) : -ENODEV
;
44 nvkm_gpio_find(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
,
45 struct dcb_gpio_func
*func
)
47 struct nvkm_bios
*bios
= nvkm_bios(gpio
);
51 if (line
== 0xff && tag
== 0xff)
54 data
= dcb_gpio_match(bios
, idx
, tag
, line
, &ver
, &len
, func
);
58 /* Apple iMac G4 NV18 */
59 if (nv_device_match(nv_object(gpio
), 0x0189, 0x10de, 0x0010)) {
60 if (tag
== DCB_GPIO_TVDAC0
) {
61 *func
= (struct dcb_gpio_func
) {
62 .func
= DCB_GPIO_TVDAC0
,
75 nvkm_gpio_set(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
, int state
)
77 struct dcb_gpio_func func
;
80 ret
= nvkm_gpio_find(gpio
, idx
, tag
, line
, &func
);
82 int dir
= !!(func
.log
[state
] & 0x02);
83 int out
= !!(func
.log
[state
] & 0x01);
84 ret
= nvkm_gpio_drive(gpio
, idx
, func
.line
, dir
, out
);
91 nvkm_gpio_get(struct nvkm_gpio
*gpio
, int idx
, u8 tag
, u8 line
)
93 struct dcb_gpio_func func
;
96 ret
= nvkm_gpio_find(gpio
, idx
, tag
, line
, &func
);
98 ret
= nvkm_gpio_sense(gpio
, idx
, func
.line
);
100 ret
= (ret
== (func
.log
[1] & 1));
107 nvkm_gpio_intr_fini(struct nvkm_event
*event
, int type
, int index
)
109 struct nvkm_gpio
*gpio
= container_of(event
, typeof(*gpio
), event
);
110 const struct nvkm_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
111 impl
->intr_mask(gpio
, type
, 1 << index
, 0);
115 nvkm_gpio_intr_init(struct nvkm_event
*event
, int type
, int index
)
117 struct nvkm_gpio
*gpio
= container_of(event
, typeof(*gpio
), event
);
118 const struct nvkm_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
119 impl
->intr_mask(gpio
, type
, 1 << index
, 1 << index
);
123 nvkm_gpio_intr_ctor(struct nvkm_object
*object
, void *data
, u32 size
,
124 struct nvkm_notify
*notify
)
126 struct nvkm_gpio_ntfy_req
*req
= data
;
127 if (!WARN_ON(size
!= sizeof(*req
))) {
128 notify
->size
= sizeof(struct nvkm_gpio_ntfy_rep
);
129 notify
->types
= req
->mask
;
130 notify
->index
= req
->line
;
137 nvkm_gpio_intr(struct nvkm_subdev
*subdev
)
139 struct nvkm_gpio
*gpio
= nvkm_gpio(subdev
);
140 const struct nvkm_gpio_impl
*impl
= (void *)nv_object(gpio
)->oclass
;
143 impl
->intr_stat(gpio
, &hi
, &lo
);
145 for (i
= 0; (hi
| lo
) && i
< impl
->lines
; i
++) {
146 struct nvkm_gpio_ntfy_rep rep
= {
147 .mask
= (NVKM_GPIO_HI
* !!(hi
& (1 << i
))) |
148 (NVKM_GPIO_LO
* !!(lo
& (1 << i
))),
150 nvkm_event_send(&gpio
->event
, rep
.mask
, i
, &rep
, sizeof(rep
));
154 static const struct nvkm_event_func
155 nvkm_gpio_intr_func
= {
156 .ctor
= nvkm_gpio_intr_ctor
,
157 .init
= nvkm_gpio_intr_init
,
158 .fini
= nvkm_gpio_intr_fini
,
162 _nvkm_gpio_fini(struct nvkm_object
*object
, bool suspend
)
164 const struct nvkm_gpio_impl
*impl
= (void *)object
->oclass
;
165 struct nvkm_gpio
*gpio
= nvkm_gpio(object
);
166 u32 mask
= (1 << impl
->lines
) - 1;
168 impl
->intr_mask(gpio
, NVKM_GPIO_TOGGLED
, mask
, 0);
169 impl
->intr_stat(gpio
, &mask
, &mask
);
171 return nvkm_subdev_fini(&gpio
->base
, suspend
);
174 static struct dmi_system_id gpio_reset_ids
[] = {
176 .ident
= "Apple Macbook 10,1",
178 DMI_MATCH(DMI_SYS_VENDOR
, "Apple Inc."),
179 DMI_MATCH(DMI_PRODUCT_NAME
, "MacBookPro10,1"),
186 _nvkm_gpio_init(struct nvkm_object
*object
)
188 struct nvkm_gpio
*gpio
= nvkm_gpio(object
);
191 ret
= nvkm_subdev_init(&gpio
->base
);
195 if (gpio
->reset
&& dmi_check_system(gpio_reset_ids
))
196 gpio
->reset(gpio
, DCB_GPIO_UNUSED
);
202 _nvkm_gpio_dtor(struct nvkm_object
*object
)
204 struct nvkm_gpio
*gpio
= (void *)object
;
205 nvkm_event_fini(&gpio
->event
);
206 nvkm_subdev_destroy(&gpio
->base
);
210 nvkm_gpio_create_(struct nvkm_object
*parent
, struct nvkm_object
*engine
,
211 struct nvkm_oclass
*oclass
, int length
, void **pobject
)
213 const struct nvkm_gpio_impl
*impl
= (void *)oclass
;
214 struct nvkm_gpio
*gpio
;
217 ret
= nvkm_subdev_create_(parent
, engine
, oclass
, 0, "GPIO",
218 "gpio", length
, pobject
);
223 gpio
->find
= nvkm_gpio_find
;
224 gpio
->set
= nvkm_gpio_set
;
225 gpio
->get
= nvkm_gpio_get
;
226 gpio
->reset
= impl
->reset
;
228 ret
= nvkm_event_init(&nvkm_gpio_intr_func
, 2, impl
->lines
,
233 nv_subdev(gpio
)->intr
= nvkm_gpio_intr
;
238 _nvkm_gpio_ctor(struct nvkm_object
*parent
, struct nvkm_object
*engine
,
239 struct nvkm_oclass
*oclass
, void *data
, u32 size
,
240 struct nvkm_object
**pobject
)
242 struct nvkm_gpio
*gpio
;
245 ret
= nvkm_gpio_create(parent
, engine
, oclass
, &gpio
);
246 *pobject
= nv_object(gpio
);