diff options
author | Alan Cox <alan@linux.intel.com> | 2011-11-03 14:21:53 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2011-11-16 06:25:59 -0500 |
commit | 5091b7eb3f90a0aa5bb4f265b8427782539342c2 (patch) | |
tree | 1c291529f87c8a35cd3a2b16e454f2c28ba9b5b7 | |
parent | f910b411053f04d5ccd6219a912eaea2b6f5ea6e (diff) |
gma500: Add the i2c bus support
Again this might be a candidate for sharing later.
Signed-off-by: Alan Cox <alan@linux.intel.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r-- | drivers/gpu/drm/gma500/intel_i2c.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/drivers/gpu/drm/gma500/intel_i2c.c b/drivers/gpu/drm/gma500/intel_i2c.c new file mode 100644 index 000000000000..e33432df510c --- /dev/null +++ b/drivers/gpu/drm/gma500/intel_i2c.c | |||
@@ -0,0 +1,169 @@ | |||
1 | /* | ||
2 | * Copyright © 2006-2007 Intel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify it | ||
5 | * under the terms and conditions of the GNU General Public License, | ||
6 | * version 2, as published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
11 | * more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License along with | ||
14 | * this program; if not, write to the Free Software Foundation, Inc., | ||
15 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
16 | * | ||
17 | * Authors: | ||
18 | * Eric Anholt <eric@anholt.net> | ||
19 | */ | ||
20 | |||
21 | #include <linux/i2c.h> | ||
22 | #include <linux/i2c-algo-bit.h> | ||
23 | |||
24 | #include "psb_drv.h" | ||
25 | #include "psb_intel_reg.h" | ||
26 | |||
27 | /* | ||
28 | * Intel GPIO access functions | ||
29 | */ | ||
30 | |||
31 | #define I2C_RISEFALL_TIME 20 | ||
32 | |||
33 | static int get_clock(void *data) | ||
34 | { | ||
35 | struct psb_intel_i2c_chan *chan = data; | ||
36 | struct drm_device *dev = chan->drm_dev; | ||
37 | u32 val; | ||
38 | |||
39 | val = REG_READ(chan->reg); | ||
40 | return (val & GPIO_CLOCK_VAL_IN) != 0; | ||
41 | } | ||
42 | |||
43 | static int get_data(void *data) | ||
44 | { | ||
45 | struct psb_intel_i2c_chan *chan = data; | ||
46 | struct drm_device *dev = chan->drm_dev; | ||
47 | u32 val; | ||
48 | |||
49 | val = REG_READ(chan->reg); | ||
50 | return (val & GPIO_DATA_VAL_IN) != 0; | ||
51 | } | ||
52 | |||
53 | static void set_clock(void *data, int state_high) | ||
54 | { | ||
55 | struct psb_intel_i2c_chan *chan = data; | ||
56 | struct drm_device *dev = chan->drm_dev; | ||
57 | u32 reserved = 0, clock_bits; | ||
58 | |||
59 | /* On most chips, these bits must be preserved in software. */ | ||
60 | reserved = | ||
61 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
62 | GPIO_CLOCK_PULLUP_DISABLE); | ||
63 | |||
64 | if (state_high) | ||
65 | clock_bits = GPIO_CLOCK_DIR_IN | GPIO_CLOCK_DIR_MASK; | ||
66 | else | ||
67 | clock_bits = GPIO_CLOCK_DIR_OUT | GPIO_CLOCK_DIR_MASK | | ||
68 | GPIO_CLOCK_VAL_MASK; | ||
69 | REG_WRITE(chan->reg, reserved | clock_bits); | ||
70 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
71 | } | ||
72 | |||
73 | static void set_data(void *data, int state_high) | ||
74 | { | ||
75 | struct psb_intel_i2c_chan *chan = data; | ||
76 | struct drm_device *dev = chan->drm_dev; | ||
77 | u32 reserved = 0, data_bits; | ||
78 | |||
79 | /* On most chips, these bits must be preserved in software. */ | ||
80 | reserved = | ||
81 | REG_READ(chan->reg) & (GPIO_DATA_PULLUP_DISABLE | | ||
82 | GPIO_CLOCK_PULLUP_DISABLE); | ||
83 | |||
84 | if (state_high) | ||
85 | data_bits = GPIO_DATA_DIR_IN | GPIO_DATA_DIR_MASK; | ||
86 | else | ||
87 | data_bits = | ||
88 | GPIO_DATA_DIR_OUT | GPIO_DATA_DIR_MASK | | ||
89 | GPIO_DATA_VAL_MASK; | ||
90 | |||
91 | REG_WRITE(chan->reg, reserved | data_bits); | ||
92 | udelay(I2C_RISEFALL_TIME); /* wait for the line to change state */ | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * psb_intel_i2c_create - instantiate an Intel i2c bus using the specified GPIO reg | ||
97 | * @dev: DRM device | ||
98 | * @output: driver specific output device | ||
99 | * @reg: GPIO reg to use | ||
100 | * @name: name for this bus | ||
101 | * | ||
102 | * Creates and registers a new i2c bus with the Linux i2c layer, for use | ||
103 | * in output probing and control (e.g. DDC or SDVO control functions). | ||
104 | * | ||
105 | * Possible values for @reg include: | ||
106 | * %GPIOA | ||
107 | * %GPIOB | ||
108 | * %GPIOC | ||
109 | * %GPIOD | ||
110 | * %GPIOE | ||
111 | * %GPIOF | ||
112 | * %GPIOG | ||
113 | * %GPIOH | ||
114 | * see PRM for details on how these different busses are used. | ||
115 | */ | ||
116 | struct psb_intel_i2c_chan *psb_intel_i2c_create(struct drm_device *dev, | ||
117 | const u32 reg, const char *name) | ||
118 | { | ||
119 | struct psb_intel_i2c_chan *chan; | ||
120 | |||
121 | chan = kzalloc(sizeof(struct psb_intel_i2c_chan), GFP_KERNEL); | ||
122 | if (!chan) | ||
123 | goto out_free; | ||
124 | |||
125 | chan->drm_dev = dev; | ||
126 | chan->reg = reg; | ||
127 | snprintf(chan->adapter.name, I2C_NAME_SIZE, "intel drm %s", name); | ||
128 | chan->adapter.owner = THIS_MODULE; | ||
129 | chan->adapter.algo_data = &chan->algo; | ||
130 | chan->adapter.dev.parent = &dev->pdev->dev; | ||
131 | chan->algo.setsda = set_data; | ||
132 | chan->algo.setscl = set_clock; | ||
133 | chan->algo.getsda = get_data; | ||
134 | chan->algo.getscl = get_clock; | ||
135 | chan->algo.udelay = 20; | ||
136 | chan->algo.timeout = usecs_to_jiffies(2200); | ||
137 | chan->algo.data = chan; | ||
138 | |||
139 | i2c_set_adapdata(&chan->adapter, chan); | ||
140 | |||
141 | if (i2c_bit_add_bus(&chan->adapter)) | ||
142 | goto out_free; | ||
143 | |||
144 | /* JJJ: raise SCL and SDA? */ | ||
145 | set_data(chan, 1); | ||
146 | set_clock(chan, 1); | ||
147 | udelay(20); | ||
148 | |||
149 | return chan; | ||
150 | |||
151 | out_free: | ||
152 | kfree(chan); | ||
153 | return NULL; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * psb_intel_i2c_destroy - unregister and free i2c bus resources | ||
158 | * @output: channel to free | ||
159 | * | ||
160 | * Unregister the adapter from the i2c layer, then free the structure. | ||
161 | */ | ||
162 | void psb_intel_i2c_destroy(struct psb_intel_i2c_chan *chan) | ||
163 | { | ||
164 | if (!chan) | ||
165 | return; | ||
166 | |||
167 | i2c_del_adapter(&chan->adapter); | ||
168 | kfree(chan); | ||
169 | } | ||