diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /drivers/i2c/busses/i2c-powermac.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'drivers/i2c/busses/i2c-powermac.c')
-rw-r--r-- | drivers/i2c/busses/i2c-powermac.c | 150 |
1 files changed, 85 insertions, 65 deletions
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 3c9d71f60187..b289ec99eeba 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c | |||
@@ -49,48 +49,38 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, | |||
49 | int rc = 0; | 49 | int rc = 0; |
50 | int read = (read_write == I2C_SMBUS_READ); | 50 | int read = (read_write == I2C_SMBUS_READ); |
51 | int addrdir = (addr << 1) | read; | 51 | int addrdir = (addr << 1) | read; |
52 | int mode, subsize, len; | ||
53 | u32 subaddr; | ||
54 | u8 *buf; | ||
52 | u8 local[2]; | 55 | u8 local[2]; |
53 | 56 | ||
54 | rc = pmac_i2c_open(bus, 0); | 57 | if (size == I2C_SMBUS_QUICK || size == I2C_SMBUS_BYTE) { |
55 | if (rc) | 58 | mode = pmac_i2c_mode_std; |
56 | return rc; | 59 | subsize = 0; |
60 | subaddr = 0; | ||
61 | } else { | ||
62 | mode = read ? pmac_i2c_mode_combined : pmac_i2c_mode_stdsub; | ||
63 | subsize = 1; | ||
64 | subaddr = command; | ||
65 | } | ||
57 | 66 | ||
58 | switch (size) { | 67 | switch (size) { |
59 | case I2C_SMBUS_QUICK: | 68 | case I2C_SMBUS_QUICK: |
60 | rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); | 69 | buf = NULL; |
61 | if (rc) | 70 | len = 0; |
62 | goto bail; | ||
63 | rc = pmac_i2c_xfer(bus, addrdir, 0, 0, NULL, 0); | ||
64 | break; | 71 | break; |
65 | case I2C_SMBUS_BYTE: | 72 | case I2C_SMBUS_BYTE: |
66 | rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); | ||
67 | if (rc) | ||
68 | goto bail; | ||
69 | rc = pmac_i2c_xfer(bus, addrdir, 0, 0, &data->byte, 1); | ||
70 | break; | ||
71 | case I2C_SMBUS_BYTE_DATA: | 73 | case I2C_SMBUS_BYTE_DATA: |
72 | rc = pmac_i2c_setmode(bus, read ? | 74 | buf = &data->byte; |
73 | pmac_i2c_mode_combined : | 75 | len = 1; |
74 | pmac_i2c_mode_stdsub); | ||
75 | if (rc) | ||
76 | goto bail; | ||
77 | rc = pmac_i2c_xfer(bus, addrdir, 1, command, &data->byte, 1); | ||
78 | break; | 76 | break; |
79 | case I2C_SMBUS_WORD_DATA: | 77 | case I2C_SMBUS_WORD_DATA: |
80 | rc = pmac_i2c_setmode(bus, read ? | ||
81 | pmac_i2c_mode_combined : | ||
82 | pmac_i2c_mode_stdsub); | ||
83 | if (rc) | ||
84 | goto bail; | ||
85 | if (!read) { | 78 | if (!read) { |
86 | local[0] = data->word & 0xff; | 79 | local[0] = data->word & 0xff; |
87 | local[1] = (data->word >> 8) & 0xff; | 80 | local[1] = (data->word >> 8) & 0xff; |
88 | } | 81 | } |
89 | rc = pmac_i2c_xfer(bus, addrdir, 1, command, local, 2); | 82 | buf = local; |
90 | if (rc == 0 && read) { | 83 | len = 2; |
91 | data->word = ((u16)local[1]) << 8; | ||
92 | data->word |= local[0]; | ||
93 | } | ||
94 | break; | 84 | break; |
95 | 85 | ||
96 | /* Note that these are broken vs. the expected smbus API where | 86 | /* Note that these are broken vs. the expected smbus API where |
@@ -105,28 +95,49 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, | |||
105 | * a repeat start/addr phase (but not stop in between) | 95 | * a repeat start/addr phase (but not stop in between) |
106 | */ | 96 | */ |
107 | case I2C_SMBUS_BLOCK_DATA: | 97 | case I2C_SMBUS_BLOCK_DATA: |
108 | rc = pmac_i2c_setmode(bus, read ? | 98 | buf = data->block; |
109 | pmac_i2c_mode_combined : | 99 | len = data->block[0] + 1; |
110 | pmac_i2c_mode_stdsub); | ||
111 | if (rc) | ||
112 | goto bail; | ||
113 | rc = pmac_i2c_xfer(bus, addrdir, 1, command, data->block, | ||
114 | data->block[0] + 1); | ||
115 | |||
116 | break; | 100 | break; |
117 | case I2C_SMBUS_I2C_BLOCK_DATA: | 101 | case I2C_SMBUS_I2C_BLOCK_DATA: |
118 | rc = pmac_i2c_setmode(bus, read ? | 102 | buf = &data->block[1]; |
119 | pmac_i2c_mode_combined : | 103 | len = data->block[0]; |
120 | pmac_i2c_mode_stdsub); | ||
121 | if (rc) | ||
122 | goto bail; | ||
123 | rc = pmac_i2c_xfer(bus, addrdir, 1, command, | ||
124 | &data->block[1], data->block[0]); | ||
125 | break; | 104 | break; |
126 | 105 | ||
127 | default: | 106 | default: |
128 | rc = -EINVAL; | 107 | return -EINVAL; |
108 | } | ||
109 | |||
110 | rc = pmac_i2c_open(bus, 0); | ||
111 | if (rc) { | ||
112 | dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc); | ||
113 | return rc; | ||
114 | } | ||
115 | |||
116 | rc = pmac_i2c_setmode(bus, mode); | ||
117 | if (rc) { | ||
118 | dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n", | ||
119 | mode, rc); | ||
120 | goto bail; | ||
129 | } | 121 | } |
122 | |||
123 | rc = pmac_i2c_xfer(bus, addrdir, subsize, subaddr, buf, len); | ||
124 | if (rc) { | ||
125 | if (rc == -ENXIO) | ||
126 | dev_dbg(&adap->dev, | ||
127 | "I2C transfer at 0x%02x failed, size %d, " | ||
128 | "err %d\n", addrdir >> 1, size, rc); | ||
129 | else | ||
130 | dev_err(&adap->dev, | ||
131 | "I2C transfer at 0x%02x failed, size %d, " | ||
132 | "err %d\n", addrdir >> 1, size, rc); | ||
133 | goto bail; | ||
134 | } | ||
135 | |||
136 | if (size == I2C_SMBUS_WORD_DATA && read) { | ||
137 | data->word = ((u16)local[1]) << 8; | ||
138 | data->word |= local[0]; | ||
139 | } | ||
140 | |||
130 | bail: | 141 | bail: |
131 | pmac_i2c_close(bus); | 142 | pmac_i2c_close(bus); |
132 | return rc; | 143 | return rc; |
@@ -146,20 +157,39 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap, | |||
146 | int read; | 157 | int read; |
147 | int addrdir; | 158 | int addrdir; |
148 | 159 | ||
160 | if (num != 1) { | ||
161 | dev_err(&adap->dev, | ||
162 | "Multi-message I2C transactions not supported\n"); | ||
163 | return -EOPNOTSUPP; | ||
164 | } | ||
165 | |||
149 | if (msgs->flags & I2C_M_TEN) | 166 | if (msgs->flags & I2C_M_TEN) |
150 | return -EINVAL; | 167 | return -EINVAL; |
151 | read = (msgs->flags & I2C_M_RD) != 0; | 168 | read = (msgs->flags & I2C_M_RD) != 0; |
152 | addrdir = (msgs->addr << 1) | read; | 169 | addrdir = (msgs->addr << 1) | read; |
153 | if (msgs->flags & I2C_M_REV_DIR_ADDR) | ||
154 | addrdir ^= 1; | ||
155 | 170 | ||
156 | rc = pmac_i2c_open(bus, 0); | 171 | rc = pmac_i2c_open(bus, 0); |
157 | if (rc) | 172 | if (rc) { |
173 | dev_err(&adap->dev, "Failed to open I2C, err %d\n", rc); | ||
158 | return rc; | 174 | return rc; |
175 | } | ||
159 | rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); | 176 | rc = pmac_i2c_setmode(bus, pmac_i2c_mode_std); |
160 | if (rc) | 177 | if (rc) { |
178 | dev_err(&adap->dev, "Failed to set I2C mode %d, err %d\n", | ||
179 | pmac_i2c_mode_std, rc); | ||
161 | goto bail; | 180 | goto bail; |
181 | } | ||
162 | rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len); | 182 | rc = pmac_i2c_xfer(bus, addrdir, 0, 0, msgs->buf, msgs->len); |
183 | if (rc < 0) { | ||
184 | if (rc == -ENXIO) | ||
185 | dev_dbg(&adap->dev, "I2C %s 0x%02x failed, err %d\n", | ||
186 | addrdir & 1 ? "read from" : "write to", | ||
187 | addrdir >> 1, rc); | ||
188 | else | ||
189 | dev_err(&adap->dev, "I2C %s 0x%02x failed, err %d\n", | ||
190 | addrdir & 1 ? "read from" : "write to", | ||
191 | addrdir >> 1, rc); | ||
192 | } | ||
163 | bail: | 193 | bail: |
164 | pmac_i2c_close(bus); | 194 | pmac_i2c_close(bus); |
165 | return rc < 0 ? rc : 1; | 195 | return rc < 0 ? rc : 1; |
@@ -183,19 +213,16 @@ static const struct i2c_algorithm i2c_powermac_algorithm = { | |||
183 | static int __devexit i2c_powermac_remove(struct platform_device *dev) | 213 | static int __devexit i2c_powermac_remove(struct platform_device *dev) |
184 | { | 214 | { |
185 | struct i2c_adapter *adapter = platform_get_drvdata(dev); | 215 | struct i2c_adapter *adapter = platform_get_drvdata(dev); |
186 | struct pmac_i2c_bus *bus = i2c_get_adapdata(adapter); | ||
187 | int rc; | 216 | int rc; |
188 | 217 | ||
189 | rc = i2c_del_adapter(adapter); | 218 | rc = i2c_del_adapter(adapter); |
190 | pmac_i2c_detach_adapter(bus, adapter); | ||
191 | i2c_set_adapdata(adapter, NULL); | ||
192 | /* We aren't that prepared to deal with this... */ | 219 | /* We aren't that prepared to deal with this... */ |
193 | if (rc) | 220 | if (rc) |
194 | printk(KERN_WARNING | 221 | printk(KERN_WARNING |
195 | "i2c-powermac.c: Failed to remove bus %s !\n", | 222 | "i2c-powermac.c: Failed to remove bus %s !\n", |
196 | adapter->name); | 223 | adapter->name); |
197 | platform_set_drvdata(dev, NULL); | 224 | platform_set_drvdata(dev, NULL); |
198 | kfree(adapter); | 225 | memset(adapter, 0, sizeof(*adapter)); |
199 | 226 | ||
200 | return 0; | 227 | return 0; |
201 | } | 228 | } |
@@ -206,12 +233,12 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) | |||
206 | struct pmac_i2c_bus *bus = dev->dev.platform_data; | 233 | struct pmac_i2c_bus *bus = dev->dev.platform_data; |
207 | struct device_node *parent = NULL; | 234 | struct device_node *parent = NULL; |
208 | struct i2c_adapter *adapter; | 235 | struct i2c_adapter *adapter; |
209 | char name[32]; | ||
210 | const char *basename; | 236 | const char *basename; |
211 | int rc; | 237 | int rc; |
212 | 238 | ||
213 | if (bus == NULL) | 239 | if (bus == NULL) |
214 | return -EINVAL; | 240 | return -EINVAL; |
241 | adapter = pmac_i2c_get_adapter(bus); | ||
215 | 242 | ||
216 | /* Ok, now we need to make up a name for the interface that will | 243 | /* Ok, now we need to make up a name for the interface that will |
217 | * match what we used to do in the past, that is basically the | 244 | * match what we used to do in the past, that is basically the |
@@ -237,29 +264,22 @@ static int __devinit i2c_powermac_probe(struct platform_device *dev) | |||
237 | default: | 264 | default: |
238 | return -EINVAL; | 265 | return -EINVAL; |
239 | } | 266 | } |
240 | snprintf(name, 32, "%s %d", basename, pmac_i2c_get_channel(bus)); | 267 | snprintf(adapter->name, sizeof(adapter->name), "%s %d", basename, |
268 | pmac_i2c_get_channel(bus)); | ||
241 | of_node_put(parent); | 269 | of_node_put(parent); |
242 | 270 | ||
243 | adapter = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL); | ||
244 | if (adapter == NULL) { | ||
245 | printk(KERN_ERR "i2c-powermac: can't allocate inteface !\n"); | ||
246 | return -ENOMEM; | ||
247 | } | ||
248 | platform_set_drvdata(dev, adapter); | 271 | platform_set_drvdata(dev, adapter); |
249 | strcpy(adapter->name, name); | ||
250 | adapter->algo = &i2c_powermac_algorithm; | 272 | adapter->algo = &i2c_powermac_algorithm; |
251 | i2c_set_adapdata(adapter, bus); | 273 | i2c_set_adapdata(adapter, bus); |
252 | adapter->dev.parent = &dev->dev; | 274 | adapter->dev.parent = &dev->dev; |
253 | pmac_i2c_attach_adapter(bus, adapter); | ||
254 | rc = i2c_add_adapter(adapter); | 275 | rc = i2c_add_adapter(adapter); |
255 | if (rc) { | 276 | if (rc) { |
256 | printk(KERN_ERR "i2c-powermac: Adapter %s registration " | 277 | printk(KERN_ERR "i2c-powermac: Adapter %s registration " |
257 | "failed\n", name); | 278 | "failed\n", adapter->name); |
258 | i2c_set_adapdata(adapter, NULL); | 279 | memset(adapter, 0, sizeof(*adapter)); |
259 | pmac_i2c_detach_adapter(bus, adapter); | ||
260 | } | 280 | } |
261 | 281 | ||
262 | printk(KERN_INFO "PowerMac i2c bus %s registered\n", name); | 282 | printk(KERN_INFO "PowerMac i2c bus %s registered\n", adapter->name); |
263 | 283 | ||
264 | if (!strncmp(basename, "uni-n", 5)) { | 284 | if (!strncmp(basename, "uni-n", 5)) { |
265 | struct device_node *np; | 285 | struct device_node *np; |