drm/i915: Set GPU freq to idle_freq initially
[dragonfly.git] / sys / dev / drm / drm_dp_iic_helper.c
blob6b8c8ab759aa4dfe10c9311d121d88e4a511db24
1 /*
2 * Copyright © 2009 Keith Packard
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
22 * $FreeBSD: head/sys/dev/drm2/drm_dp_iic_helper.c 249249 2013-04-08 08:37:57Z dumbbell $
25 #include <sys/types.h>
26 #include <sys/kobj.h>
27 #include <sys/bus.h>
28 #include <bus/iicbus/iic.h>
29 #include "iicbus_if.h"
30 #include <bus/iicbus/iiconf.h>
31 #include <drm/drmP.h>
32 #include <drm/drm_dp_helper.h>
34 static int
35 iic_dp_aux_transaction(device_t idev, int mode, uint8_t write_byte,
36 uint8_t *read_byte)
38 struct i2c_algo_dp_aux_data *aux_data;
39 int ret;
41 aux_data = device_get_softc(idev);
42 ret = (*aux_data->aux_ch)(idev, mode, write_byte, read_byte);
43 return (ret);
47 * I2C over AUX CH
51 * Send the address. If the I2C link is running, this 'restarts'
52 * the connection with the new address, this is used for doing
53 * a write followed by a read (as needed for DDC)
55 static int
56 iic_dp_aux_address(device_t idev, u16 address, bool reading)
58 struct i2c_algo_dp_aux_data *aux_data;
59 int mode, ret;
61 aux_data = device_get_softc(idev);
62 mode = MODE_I2C_START;
63 if (reading)
64 mode |= MODE_I2C_READ;
65 else
66 mode |= MODE_I2C_WRITE;
67 aux_data->address = address;
68 aux_data->running = true;
69 ret = iic_dp_aux_transaction(idev, mode, 0, NULL);
70 return (ret);
74 * Stop the I2C transaction. This closes out the link, sending
75 * a bare address packet with the MOT bit turned off
77 static void
78 iic_dp_aux_stop(device_t idev, bool reading)
80 struct i2c_algo_dp_aux_data *aux_data;
81 int mode;
83 aux_data = device_get_softc(idev);
84 mode = MODE_I2C_STOP;
85 if (reading)
86 mode |= MODE_I2C_READ;
87 else
88 mode |= MODE_I2C_WRITE;
89 if (aux_data->running) {
90 (void)iic_dp_aux_transaction(idev, mode, 0, NULL);
91 aux_data->running = false;
96 * Write a single byte to the current I2C address, the
97 * the I2C link must be running or this returns -EIO
99 static int
100 iic_dp_aux_put_byte(device_t idev, u8 byte)
102 struct i2c_algo_dp_aux_data *aux_data;
103 int ret;
105 aux_data = device_get_softc(idev);
107 if (!aux_data->running)
108 return (EIO);
110 ret = iic_dp_aux_transaction(idev, MODE_I2C_WRITE, byte, NULL);
111 return (ret);
115 * Read a single byte from the current I2C address, the
116 * I2C link must be running or this returns -EIO
118 static int
119 iic_dp_aux_get_byte(device_t idev, u8 *byte_ret)
121 struct i2c_algo_dp_aux_data *aux_data;
122 int ret;
124 aux_data = device_get_softc(idev);
126 if (!aux_data->running)
127 return (EIO);
129 ret = iic_dp_aux_transaction(idev, MODE_I2C_READ, 0, byte_ret);
130 return (ret);
133 static int
134 iic_dp_aux_xfer(device_t idev, struct iic_msg *msgs, uint32_t num)
136 u8 *buf;
137 int b, m, ret;
138 u16 len;
139 bool reading;
141 ret = 0;
142 reading = false;
144 for (m = 0; m < num; m++) {
145 len = msgs[m].len;
146 buf = msgs[m].buf;
147 reading = (msgs[m].flags & IIC_M_RD) != 0;
148 ret = iic_dp_aux_address(idev, msgs[m].slave >> 1, reading);
149 if (ret != 0)
150 break;
151 if (reading) {
152 for (b = 0; b < len; b++) {
153 ret = iic_dp_aux_get_byte(idev, &buf[b]);
154 if (ret != 0)
155 break;
157 } else {
158 for (b = 0; b < len; b++) {
159 ret = iic_dp_aux_put_byte(idev, buf[b]);
160 if (ret != 0)
161 break;
164 if (ret != 0)
165 break;
167 iic_dp_aux_stop(idev, reading);
168 DRM_DEBUG_KMS("dp_aux_xfer return %d\n", ret);
169 return (ret);
172 static void
173 iic_dp_aux_reset_bus(device_t idev)
176 (void)iic_dp_aux_address(idev, 0, false);
177 (void)iic_dp_aux_stop(idev, false);
180 static int
181 iic_dp_aux_reset(device_t idev, u_char speed, u_char addr, u_char *oldaddr)
184 iic_dp_aux_reset_bus(idev);
185 return (0);
188 static int
189 iic_dp_aux_prepare_bus(device_t idev)
192 /* adapter->retries = 3; */
193 iic_dp_aux_reset_bus(idev);
194 return (0);
197 static int
198 iic_dp_aux_probe(device_t idev)
201 return (BUS_PROBE_DEFAULT);
204 static int
205 iic_dp_aux_attach(device_t idev)
207 struct i2c_algo_dp_aux_data *aux_data;
209 aux_data = device_get_softc(idev);
210 aux_data->port = device_add_child(idev, "iicbus", -1);
211 if (aux_data->port == NULL)
212 return (ENXIO);
213 device_quiet(aux_data->port);
214 bus_generic_attach(idev);
215 return (0);
219 iic_dp_aux_add_bus(device_t dev, const char *name,
220 int (*ch)(device_t idev, int mode, uint8_t write_byte, uint8_t *read_byte),
221 void *priv, device_t *bus, device_t *adapter)
223 device_t ibus;
224 struct i2c_algo_dp_aux_data *data;
225 int idx, error;
226 static int dp_bus_counter;
228 idx = atomic_fetchadd_int(&dp_bus_counter, 1);
229 ibus = device_add_child(dev, "drm_iic_dp_aux", idx);
230 if (ibus == NULL) {
231 DRM_ERROR("drm_iic_dp_aux bus %d creation error\n", idx);
232 return (-ENXIO);
234 device_quiet(ibus);
235 error = device_probe_and_attach(ibus);
236 if (error != 0) {
237 device_delete_child(dev, ibus);
238 DRM_ERROR("drm_iic_dp_aux bus %d attach failed, %d\n",
239 idx, error);
240 return (-error);
242 data = device_get_softc(ibus);
243 data->running = false;
244 data->address = 0;
245 data->aux_ch = ch;
246 data->priv = priv;
247 error = iic_dp_aux_prepare_bus(ibus);
248 if (error == 0) {
249 *bus = ibus;
250 *adapter = data->port;
252 return (error);
255 static device_method_t drm_iic_dp_aux_methods[] = {
256 DEVMETHOD(device_probe, iic_dp_aux_probe),
257 DEVMETHOD(device_attach, iic_dp_aux_attach),
258 DEVMETHOD(device_detach, bus_generic_detach),
259 DEVMETHOD(iicbus_reset, iic_dp_aux_reset),
260 DEVMETHOD(iicbus_transfer, iic_dp_aux_xfer),
261 DEVMETHOD_END
263 static driver_t drm_iic_dp_aux_driver = {
264 "drm_iic_dp_aux",
265 drm_iic_dp_aux_methods,
266 sizeof(struct i2c_algo_dp_aux_data)
268 static devclass_t drm_iic_dp_aux_devclass;
269 DRIVER_MODULE_ORDERED(drm_iic_dp_aux, drm, drm_iic_dp_aux_driver,
270 drm_iic_dp_aux_devclass, NULL, NULL, SI_ORDER_SECOND);