]>
Commit | Line | Data |
---|---|---|
a0b25635 BS |
1 | /* |
2 | * Copyright 2011 Red Hat Inc. | |
3 | * | |
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: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
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. | |
21 | * | |
22 | * Authors: Ben Skeggs | |
23 | */ | |
24 | ||
02a841d4 | 25 | #include <subdev/gpio.h> |
e0996aea BS |
26 | #include <subdev/bios.h> |
27 | #include <subdev/bios/gpio.h> | |
a0b25635 | 28 | |
e0996aea BS |
29 | static int |
30 | nouveau_gpio_drive(struct nouveau_gpio *gpio, | |
31 | int idx, int line, int dir, int out) | |
a0b25635 | 32 | { |
e0996aea | 33 | return gpio->drive ? gpio->drive(gpio, line, dir, out) : -ENODEV; |
a0b25635 BS |
34 | } |
35 | ||
e0996aea BS |
36 | static int |
37 | nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line) | |
a0b25635 | 38 | { |
e0996aea | 39 | return gpio->sense ? gpio->sense(gpio, line) : -ENODEV; |
a0b25635 BS |
40 | } |
41 | ||
e0996aea BS |
42 | static int |
43 | nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, | |
44 | struct dcb_gpio_func *func) | |
a0b25635 | 45 | { |
d2bcea68 BS |
46 | struct nouveau_bios *bios = nouveau_bios(gpio); |
47 | u8 ver, len; | |
48 | u16 data; | |
49 | ||
e0996aea | 50 | if (line == 0xff && tag == 0xff) |
a0b25635 BS |
51 | return -EINVAL; |
52 | ||
d2bcea68 BS |
53 | data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func); |
54 | if (data) | |
e0996aea | 55 | return 0; |
a0b25635 BS |
56 | |
57 | /* Apple iMac G4 NV18 */ | |
e0996aea BS |
58 | if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) { |
59 | if (tag == DCB_GPIO_TVDAC0) { | |
60 | *func = (struct dcb_gpio_func) { | |
a0b25635 BS |
61 | .func = DCB_GPIO_TVDAC0, |
62 | .line = 4, | |
63 | .log[0] = 0, | |
64 | .log[1] = 1, | |
65 | }; | |
66 | return 0; | |
67 | } | |
68 | } | |
69 | ||
70 | return -EINVAL; | |
71 | } | |
72 | ||
e0996aea BS |
73 | static int |
74 | nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state) | |
a0b25635 | 75 | { |
e0996aea | 76 | struct dcb_gpio_func func; |
a0b25635 BS |
77 | int ret; |
78 | ||
e0996aea | 79 | ret = nouveau_gpio_find(gpio, idx, tag, line, &func); |
a0b25635 | 80 | if (ret == 0) { |
e0996aea BS |
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); | |
a0b25635 BS |
84 | } |
85 | ||
86 | return ret; | |
87 | } | |
88 | ||
e0996aea BS |
89 | static int |
90 | nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line) | |
a0b25635 | 91 | { |
e0996aea | 92 | struct dcb_gpio_func func; |
a0b25635 BS |
93 | int ret; |
94 | ||
e0996aea | 95 | ret = nouveau_gpio_find(gpio, idx, tag, line, &func); |
a0b25635 | 96 | if (ret == 0) { |
e0996aea | 97 | ret = nouveau_gpio_sense(gpio, idx, func.line); |
a0b25635 | 98 | if (ret >= 0) |
e0996aea | 99 | ret = (ret == (func.log[1] & 1)); |
a0b25635 BS |
100 | } |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
4f47643d BS |
105 | void |
106 | _nouveau_gpio_dtor(struct nouveau_object *object) | |
a0b25635 | 107 | { |
4f47643d BS |
108 | struct nouveau_gpio *gpio = (void *)object; |
109 | nouveau_event_destroy(&gpio->events); | |
110 | nouveau_subdev_destroy(&gpio->base); | |
a0b25635 BS |
111 | } |
112 | ||
113 | int | |
e0996aea BS |
114 | nouveau_gpio_create_(struct nouveau_object *parent, |
115 | struct nouveau_object *engine, | |
0f080066 BS |
116 | struct nouveau_oclass *oclass, int lines, |
117 | int length, void **pobject) | |
a0b25635 | 118 | { |
e0996aea BS |
119 | struct nouveau_gpio *gpio; |
120 | int ret; | |
a0b25635 | 121 | |
e0996aea BS |
122 | ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio", |
123 | length, pobject); | |
124 | gpio = *pobject; | |
125 | if (ret) | |
126 | return ret; | |
a0b25635 | 127 | |
4f47643d BS |
128 | ret = nouveau_event_create(lines, &gpio->events); |
129 | if (ret) | |
130 | return ret; | |
131 | ||
e0996aea BS |
132 | gpio->find = nouveau_gpio_find; |
133 | gpio->set = nouveau_gpio_set; | |
134 | gpio->get = nouveau_gpio_get; | |
e0996aea | 135 | return 0; |
a0b25635 BS |
136 | } |
137 | ||
e0996aea BS |
138 | static struct dmi_system_id gpio_reset_ids[] = { |
139 | { | |
140 | .ident = "Apple Macbook 10,1", | |
141 | .matches = { | |
142 | DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."), | |
143 | DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"), | |
144 | } | |
145 | }, | |
146 | { } | |
147 | }; | |
a0b25635 BS |
148 | |
149 | int | |
e0996aea | 150 | nouveau_gpio_init(struct nouveau_gpio *gpio) |
a0b25635 | 151 | { |
e0996aea BS |
152 | int ret = nouveau_subdev_init(&gpio->base); |
153 | if (ret == 0 && gpio->reset) { | |
154 | if (dmi_check_system(gpio_reset_ids)) | |
1ed73166 | 155 | gpio->reset(gpio, DCB_GPIO_UNUSED); |
a0b25635 | 156 | } |
e0996aea | 157 | return ret; |
a0b25635 | 158 | } |