diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_i2c.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_i2c.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c new file mode 100644 index 000000000000..5ee9d4c25753 --- /dev/null +++ b/drivers/gpu/drm/i915/intel_i2c.c | |||
@@ -0,0 +1,180 @@ | |||
1 | /* | ||
2 | * Copyright (c) 2006 Dave Airlie <airlied@linux.ie> | ||
3 | * Copyright © 2006-2008 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Permission is hereby granted, free of charge, to any person obtaining a | ||
7 | * copy of this software and associated documentation files (the "Software"), | ||
8 | * to deal in the Software without restriction, including without limitation | ||
9 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||
10 | * and/or sell copies of the Software, and to permit persons to whom the | ||
11 | * Software is furnished to do so, subject to the following conditions: | ||
12 | * | ||
13 | * The above copyright notice and this permission notice (including the next | ||
14 | * paragraph) shall be included in all copies or substantial portions of the | ||
15 | * Software. | ||
16 | * | ||
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
20 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
22 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
23 | * DEALINGS IN THE SOFTWARE. | ||
24 | * | ||
25 | * Authors: | ||
26 | * Eric Anholt <eric@anholt.net> | ||
27 | */ | ||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/i2c-id.h> | ||
30 | #include <linux/i2c-algo-bit.h> | ||
31 | #include "drmP.h" | ||
32 | #include "drm.h" | ||
33 | #include "intel_drv.h" | ||
34 | #include "i915_drm.h" | ||
35 | #include "i915_drv.h" | ||
36 | |||
37 | /* | ||
38 | * Intel GPIO access functions | ||
39 | */ | ||
40 | |||
41 | #define I2C_RISEFALL_TIME 20 | ||
42 | |||
43 | static int get_clock(void *data) | ||
44 | { | ||
45 | struct intel_i2c_chan *chan = data; | ||
46 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
47 | u32 val; | ||
48 | |||
49 | val = I915_READ(chan->reg); | ||
50 | return ((val & GPIO_CLOCK_VAL_IN) != 0); | ||
51 | } | ||
52 | |||
53 | static int get_data(void *data) | ||
54 | { | ||
55 | struct intel_i2c_chan *chan = data; | ||
56 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
57 | u32 val; | ||
58 | |||
59 | val = I915_READ(chan->reg); | ||
60 | return ((val & GPIO_DATA_VAL_IN) != 0); | ||
61 | } | ||
62 | |||
63 | static void set_clock(void *data, int state_high) | ||
64 | { | ||
65 | struct intel_i2c_chan *chan = data; | ||
66 | struct drm_device *dev = chan->drm_dev; | ||
67 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
68 | u32 reserved = 0, clock_bits; | ||
69 | |||
70 | /* On most chips, these bits must be preserved in software. */ | ||
71 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
72 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
73 | GPIO_CLOCK_PULLUP_DISABLE); | ||
74 | |||
75 | if (state_high) | ||
76 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
77 | else | ||
78 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
79 | GPIO_CLOCK_VAL_MASK; | ||
80 | I915_WRITE(chan->reg, reserved | clock_bits); | ||
81 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
82 | } | ||
83 | |||
84 | static void set_data(void *data, int state_high) | ||
85 | { | ||
86 | struct intel_i2c_chan *chan = data; | ||
87 | struct drm_device *dev = chan->drm_dev; | ||
88 | struct drm_i915_private *dev_priv = chan->drm_dev->dev_private; | ||
89 | u32 reserved = 0, data_bits; | ||
90 | |||
91 | /* On most chips, these bits must be preserved in software. */ | ||
92 | if (!IS_I830(dev) && !IS_845G(dev)) | ||
93 | reserved = I915_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
94 | GPIO_CLOCK_PULLUP_DISABLE); | ||
95 | |||
96 | if (state_high) | ||
97 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
98 | else | ||
99 | data_bits = GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
100 | GPIO_DATA_VAL_MASK; | ||
101 | |||
102 | I915_WRITE(chan->reg, reserved | data_bits); | ||
103 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
104 | } | ||
105 | |||
106 | /** | ||
107 | * intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg | ||
108 | * @dev: DRM device | ||
109 | * @output: driver specific output device | ||
110 | * @reg: GPIO reg to use | ||
111 | * @name: name for this bus | ||
112 | * | ||
113 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | ||
114 | * in output probing and control (e.g. DDC or SDVO control functions). | ||
115 | * | ||
116 | * Possible values for @reg include: | ||
117 | * %GPIOA | ||
118 | * %GPIOB | ||
119 | * %GPIOC | ||
120 | * %GPIOD | ||
121 | * %GPIOE | ||
122 | * %GPIOF | ||
123 | * %GPIOG | ||
124 | * %GPIOH | ||
125 | * see PRM for details on how these different busses are used. | ||
126 | */ | ||
127 | struct intel_i2c_chan *intel_i2c_create(struct drm_device *dev, const u32 reg, | ||
128 | const char *name) | ||
129 | { | ||
130 | struct intel_i2c_chan *chan; | ||
131 | |||
132 | chan = kzalloc(sizeof(struct intel_i2c_chan), GFP_KERNEL); | ||
133 | if (!chan) | ||
134 | goto out_free; | ||
135 | |||
136 | chan->drm_dev = dev; | ||
137 | chan->reg = reg; | ||
138 | snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); | ||
139 | chan->adapter.owner = THIS_MODULE; | ||
140 | chan->adapter.algo_data = &chan->algo; | ||
141 | chan->adapter.dev.parent = &dev->pdev->dev; | ||
142 | chan->algo.setsda = set_data; | ||
143 | chan->algo.setscl = set_clock; | ||
144 | chan->algo.getsda = get_data; | ||
145 | chan->algo.getscl = get_clock; | ||
146 | chan->algo.udelay = 20; | ||
147 | chan->algo.timeout = usecs_to_jiffies(2200); | ||
148 | chan->algo.data = chan; | ||
149 | |||
150 | i2c_set_adapdata(&chan->adapter, chan); | ||
151 | |||
152 | if(i2c_bit_add_bus(&chan->adapter)) | ||
153 | goto out_free; | ||
154 | |||
155 | /* JJJ: raise SCL and SDA? */ | ||
156 | set_data(chan, 1); | ||
157 | set_clock(chan, 1); | ||
158 | udelay(20); | ||
159 | |||
160 | return chan; | ||
161 | |||
162 | out_free: | ||
163 | kfree(chan); | ||
164 | return NULL; | ||
165 | } | ||
166 | |||
167 | /** | ||
168 | * intel_i2c_destroy - unregister and free i2c bus resources | ||
169 | * @output: channel to free | ||
170 | * | ||
171 | * Unregister the adapter from the i2c layer, then free the structure. | ||
172 | */ | ||
173 | void intel_i2c_destroy(struct intel_i2c_chan *chan) | ||
174 | { | ||
175 | if (!chan) | ||
176 | return; | ||
177 | |||
178 | i2c_del_adapter(&chan->adapter); | ||
179 | kfree(chan); | ||
180 | } | ||