diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi.c | 139 |
1 files changed, 95 insertions, 44 deletions
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index ecca4a6a6f94..964124b60db2 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c | |||
@@ -178,6 +178,96 @@ struct boardinfo { | |||
178 | static LIST_HEAD(board_list); | 178 | static LIST_HEAD(board_list); |
179 | static DEFINE_MUTEX(board_lock); | 179 | static DEFINE_MUTEX(board_lock); |
180 | 180 | ||
181 | /** | ||
182 | * spi_alloc_device - Allocate a new SPI device | ||
183 | * @master: Controller to which device is connected | ||
184 | * Context: can sleep | ||
185 | * | ||
186 | * Allows a driver to allocate and initialize a spi_device without | ||
187 | * registering it immediately. This allows a driver to directly | ||
188 | * fill the spi_device with device parameters before calling | ||
189 | * spi_add_device() on it. | ||
190 | * | ||
191 | * Caller is responsible to call spi_add_device() on the returned | ||
192 | * spi_device structure to add it to the SPI master. If the caller | ||
193 | * needs to discard the spi_device without adding it, then it should | ||
194 | * call spi_dev_put() on it. | ||
195 | * | ||
196 | * Returns a pointer to the new device, or NULL. | ||
197 | */ | ||
198 | struct spi_device *spi_alloc_device(struct spi_master *master) | ||
199 | { | ||
200 | struct spi_device *spi; | ||
201 | struct device *dev = master->dev.parent; | ||
202 | |||
203 | if (!spi_master_get(master)) | ||
204 | return NULL; | ||
205 | |||
206 | spi = kzalloc(sizeof *spi, GFP_KERNEL); | ||
207 | if (!spi) { | ||
208 | dev_err(dev, "cannot alloc spi_device\n"); | ||
209 | spi_master_put(master); | ||
210 | return NULL; | ||
211 | } | ||
212 | |||
213 | spi->master = master; | ||
214 | spi->dev.parent = dev; | ||
215 | spi->dev.bus = &spi_bus_type; | ||
216 | spi->dev.release = spidev_release; | ||
217 | device_initialize(&spi->dev); | ||
218 | return spi; | ||
219 | } | ||
220 | EXPORT_SYMBOL_GPL(spi_alloc_device); | ||
221 | |||
222 | /** | ||
223 | * spi_add_device - Add spi_device allocated with spi_alloc_device | ||
224 | * @spi: spi_device to register | ||
225 | * | ||
226 | * Companion function to spi_alloc_device. Devices allocated with | ||
227 | * spi_alloc_device can be added onto the spi bus with this function. | ||
228 | * | ||
229 | * Returns 0 on success; non-zero on failure | ||
230 | */ | ||
231 | int spi_add_device(struct spi_device *spi) | ||
232 | { | ||
233 | struct device *dev = spi->master->dev.parent; | ||
234 | int status; | ||
235 | |||
236 | /* Chipselects are numbered 0..max; validate. */ | ||
237 | if (spi->chip_select >= spi->master->num_chipselect) { | ||
238 | dev_err(dev, "cs%d >= max %d\n", | ||
239 | spi->chip_select, | ||
240 | spi->master->num_chipselect); | ||
241 | return -EINVAL; | ||
242 | } | ||
243 | |||
244 | /* Set the bus ID string */ | ||
245 | snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id, | ||
246 | "%s.%u", spi->master->dev.bus_id, | ||
247 | spi->chip_select); | ||
248 | |||
249 | /* drivers may modify this initial i/o setup */ | ||
250 | status = spi->master->setup(spi); | ||
251 | if (status < 0) { | ||
252 | dev_err(dev, "can't %s %s, status %d\n", | ||
253 | "setup", spi->dev.bus_id, status); | ||
254 | return status; | ||
255 | } | ||
256 | |||
257 | /* driver core catches callers that misbehave by defining | ||
258 | * devices that already exist. | ||
259 | */ | ||
260 | status = device_add(&spi->dev); | ||
261 | if (status < 0) { | ||
262 | dev_err(dev, "can't %s %s, status %d\n", | ||
263 | "add", spi->dev.bus_id, status); | ||
264 | return status; | ||
265 | } | ||
266 | |||
267 | dev_dbg(dev, "registered child %s\n", spi->dev.bus_id); | ||
268 | return 0; | ||
269 | } | ||
270 | EXPORT_SYMBOL_GPL(spi_add_device); | ||
181 | 271 | ||
182 | /** | 272 | /** |
183 | * spi_new_device - instantiate one new SPI device | 273 | * spi_new_device - instantiate one new SPI device |
@@ -197,7 +287,6 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
197 | struct spi_board_info *chip) | 287 | struct spi_board_info *chip) |
198 | { | 288 | { |
199 | struct spi_device *proxy; | 289 | struct spi_device *proxy; |
200 | struct device *dev = master->dev.parent; | ||
201 | int status; | 290 | int status; |
202 | 291 | ||
203 | /* NOTE: caller did any chip->bus_num checks necessary. | 292 | /* NOTE: caller did any chip->bus_num checks necessary. |
@@ -207,66 +296,28 @@ struct spi_device *spi_new_device(struct spi_master *master, | |||
207 | * suggests syslogged diagnostics are best here (ugh). | 296 | * suggests syslogged diagnostics are best here (ugh). |
208 | */ | 297 | */ |
209 | 298 | ||
210 | /* Chipselects are numbered 0..max; validate. */ | 299 | proxy = spi_alloc_device(master); |
211 | if (chip->chip_select >= master->num_chipselect) { | 300 | if (!proxy) |
212 | dev_err(dev, "cs%d > max %d\n", | ||
213 | chip->chip_select, | ||
214 | master->num_chipselect); | ||
215 | return NULL; | ||
216 | } | ||
217 | |||
218 | if (!spi_master_get(master)) | ||
219 | return NULL; | 301 | return NULL; |
220 | 302 | ||
221 | WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias)); | 303 | WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias)); |
222 | 304 | ||
223 | proxy = kzalloc(sizeof *proxy, GFP_KERNEL); | ||
224 | if (!proxy) { | ||
225 | dev_err(dev, "can't alloc dev for cs%d\n", | ||
226 | chip->chip_select); | ||
227 | goto fail; | ||
228 | } | ||
229 | proxy->master = master; | ||
230 | proxy->chip_select = chip->chip_select; | 305 | proxy->chip_select = chip->chip_select; |
231 | proxy->max_speed_hz = chip->max_speed_hz; | 306 | proxy->max_speed_hz = chip->max_speed_hz; |
232 | proxy->mode = chip->mode; | 307 | proxy->mode = chip->mode; |
233 | proxy->irq = chip->irq; | 308 | proxy->irq = chip->irq; |
234 | strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); | 309 | strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias)); |
235 | |||
236 | snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id, | ||
237 | "%s.%u", master->dev.bus_id, | ||
238 | chip->chip_select); | ||
239 | proxy->dev.parent = dev; | ||
240 | proxy->dev.bus = &spi_bus_type; | ||
241 | proxy->dev.platform_data = (void *) chip->platform_data; | 310 | proxy->dev.platform_data = (void *) chip->platform_data; |
242 | proxy->controller_data = chip->controller_data; | 311 | proxy->controller_data = chip->controller_data; |
243 | proxy->controller_state = NULL; | 312 | proxy->controller_state = NULL; |
244 | proxy->dev.release = spidev_release; | ||
245 | 313 | ||
246 | /* drivers may modify this initial i/o setup */ | 314 | status = spi_add_device(proxy); |
247 | status = master->setup(proxy); | ||
248 | if (status < 0) { | 315 | if (status < 0) { |
249 | dev_err(dev, "can't %s %s, status %d\n", | 316 | spi_dev_put(proxy); |
250 | "setup", proxy->dev.bus_id, status); | 317 | return NULL; |
251 | goto fail; | ||
252 | } | 318 | } |
253 | 319 | ||
254 | /* driver core catches callers that misbehave by defining | ||
255 | * devices that already exist. | ||
256 | */ | ||
257 | status = device_register(&proxy->dev); | ||
258 | if (status < 0) { | ||
259 | dev_err(dev, "can't %s %s, status %d\n", | ||
260 | "add", proxy->dev.bus_id, status); | ||
261 | goto fail; | ||
262 | } | ||
263 | dev_dbg(dev, "registered child %s\n", proxy->dev.bus_id); | ||
264 | return proxy; | 320 | return proxy; |
265 | |||
266 | fail: | ||
267 | spi_master_put(master); | ||
268 | kfree(proxy); | ||
269 | return NULL; | ||
270 | } | 321 | } |
271 | EXPORT_SYMBOL_GPL(spi_new_device); | 322 | EXPORT_SYMBOL_GPL(spi_new_device); |
272 | 323 | ||