| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 1 | /* | 
 | 2 |  * Industry-pack bus. | 
 | 3 |  * | 
| Samuel Iglesias Gonsalvez | 7685972 | 2012-11-16 16:19:58 +0100 | [diff] [blame] | 4 |  * Copyright (C) 2011-2012 CERN (www.cern.ch) | 
 | 5 |  * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com> | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 6 |  * | 
 | 7 |  * This program is free software; you can redistribute it and/or modify it | 
 | 8 |  * under the terms of the GNU General Public License as published by the Free | 
| Samuel Iglesias Gonsalvez | 416289b | 2012-05-11 10:17:13 +0200 | [diff] [blame] | 9 |  * Software Foundation; version 2 of the License. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 10 |  */ | 
 | 11 |  | 
| Jens Taprogge | 849e0ad | 2012-09-04 17:01:13 +0200 | [diff] [blame] | 12 | #include <linux/mod_devicetable.h> | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 13 | #include <linux/device.h> | 
| Jens Taprogge | faa75c4 | 2012-09-12 14:55:38 +0200 | [diff] [blame] | 14 | #include <linux/interrupt.h> | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 15 |  | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 16 | #define IPACK_IDPROM_OFFSET_I			0x01 | 
 | 17 | #define IPACK_IDPROM_OFFSET_P			0x03 | 
 | 18 | #define IPACK_IDPROM_OFFSET_A			0x05 | 
 | 19 | #define IPACK_IDPROM_OFFSET_C			0x07 | 
 | 20 | #define IPACK_IDPROM_OFFSET_MANUFACTURER_ID	0x09 | 
 | 21 | #define IPACK_IDPROM_OFFSET_MODEL		0x0B | 
 | 22 | #define IPACK_IDPROM_OFFSET_REVISION		0x0D | 
 | 23 | #define IPACK_IDPROM_OFFSET_RESERVED		0x0F | 
 | 24 | #define IPACK_IDPROM_OFFSET_DRIVER_ID_L		0x11 | 
 | 25 | #define IPACK_IDPROM_OFFSET_DRIVER_ID_H		0x13 | 
 | 26 | #define IPACK_IDPROM_OFFSET_NUM_BYTES		0x15 | 
 | 27 | #define IPACK_IDPROM_OFFSET_CRC			0x17 | 
 | 28 |  | 
| Samuel Iglesias Gonsalvez | 27cf2d1 | 2012-11-16 19:33:46 +0100 | [diff] [blame] | 29 | /* | 
 | 30 |  * IndustryPack Fromat, Vendor and Device IDs. | 
 | 31 |  */ | 
 | 32 |  | 
 | 33 | /* ID section format versions */ | 
 | 34 | #define IPACK_ID_VERSION_INVALID	0x00 | 
 | 35 | #define IPACK_ID_VERSION_1		0x01 | 
 | 36 | #define IPACK_ID_VERSION_2		0x02 | 
 | 37 |  | 
 | 38 | /* Vendors and devices. Sort key: vendor first, device next. */ | 
 | 39 | #define IPACK1_VENDOR_ID_RESERVED1	0x00 | 
 | 40 | #define IPACK1_VENDOR_ID_RESERVED2	0xFF | 
 | 41 | #define IPACK1_VENDOR_ID_UNREGISTRED01	0x01 | 
 | 42 | #define IPACK1_VENDOR_ID_UNREGISTRED02	0x02 | 
 | 43 | #define IPACK1_VENDOR_ID_UNREGISTRED03	0x03 | 
 | 44 | #define IPACK1_VENDOR_ID_UNREGISTRED04	0x04 | 
 | 45 | #define IPACK1_VENDOR_ID_UNREGISTRED05	0x05 | 
 | 46 | #define IPACK1_VENDOR_ID_UNREGISTRED06	0x06 | 
 | 47 | #define IPACK1_VENDOR_ID_UNREGISTRED07	0x07 | 
 | 48 | #define IPACK1_VENDOR_ID_UNREGISTRED08	0x08 | 
 | 49 | #define IPACK1_VENDOR_ID_UNREGISTRED09	0x09 | 
 | 50 | #define IPACK1_VENDOR_ID_UNREGISTRED10	0x0A | 
 | 51 | #define IPACK1_VENDOR_ID_UNREGISTRED11	0x0B | 
 | 52 | #define IPACK1_VENDOR_ID_UNREGISTRED12	0x0C | 
 | 53 | #define IPACK1_VENDOR_ID_UNREGISTRED13	0x0D | 
 | 54 | #define IPACK1_VENDOR_ID_UNREGISTRED14	0x0E | 
 | 55 | #define IPACK1_VENDOR_ID_UNREGISTRED15	0x0F | 
 | 56 |  | 
 | 57 | #define IPACK1_VENDOR_ID_SBS            0xF0 | 
 | 58 | #define IPACK1_DEVICE_ID_SBS_OCTAL_232  0x22 | 
 | 59 | #define IPACK1_DEVICE_ID_SBS_OCTAL_422  0x2A | 
 | 60 | #define IPACK1_DEVICE_ID_SBS_OCTAL_485  0x48 | 
 | 61 |  | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 62 | struct ipack_bus_ops; | 
 | 63 | struct ipack_driver; | 
 | 64 |  | 
 | 65 | enum ipack_space { | 
 | 66 | 	IPACK_IO_SPACE    = 0, | 
| Jens Taprogge | 84a08fa | 2012-09-27 12:37:29 +0200 | [diff] [blame] | 67 | 	IPACK_ID_SPACE, | 
| Jens Taprogge | e4af949 | 2012-09-13 12:32:19 +0200 | [diff] [blame] | 68 | 	IPACK_INT_SPACE, | 
| Jens Taprogge | fe4a3ed | 2012-09-27 12:37:36 +0200 | [diff] [blame] | 69 | 	IPACK_MEM8_SPACE, | 
| Jens Taprogge | 48a9735 | 2012-09-27 12:37:37 +0200 | [diff] [blame] | 70 | 	IPACK_MEM16_SPACE, | 
| Jens Taprogge | 84a08fa | 2012-09-27 12:37:29 +0200 | [diff] [blame] | 71 | 	/* Dummy for counting the number of entries.  Must remain the last | 
 | 72 | 	 * entry */ | 
 | 73 | 	IPACK_SPACE_COUNT, | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 74 | }; | 
 | 75 |  | 
 | 76 | /** | 
| Jens Taprogge | bb29ab8 | 2012-09-27 12:37:28 +0200 | [diff] [blame] | 77 |  */ | 
 | 78 | struct ipack_region { | 
 | 79 | 	phys_addr_t start; | 
 | 80 | 	size_t      size; | 
 | 81 | }; | 
 | 82 |  | 
 | 83 | /** | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 84 |  *	struct ipack_device | 
 | 85 |  * | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 86 |  *	@slot: Slot where the device is plugged in the carrier board | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 87 |  *	@bus: ipack_bus_device where the device is plugged to. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 88 |  *	@id_space: Virtual address to ID space. | 
 | 89 |  *	@io_space: Virtual address to IO space. | 
 | 90 |  *	@mem_space: Virtual address to MEM space. | 
 | 91 |  *	@dev: device in kernel representation. | 
 | 92 |  * | 
 | 93 |  * Warning: Direct access to mapped memory is possible but the endianness | 
 | 94 |  * is not the same with PCI carrier or VME carrier. The endianness is managed | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 95 |  * by the carrier board throught bus->ops. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 96 |  */ | 
 | 97 | struct ipack_device { | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 98 | 	unsigned int slot; | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 99 | 	struct ipack_bus_device *bus; | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 100 | 	struct device dev; | 
| Jens Taprogge | 1e91795 | 2012-09-27 12:37:26 +0200 | [diff] [blame] | 101 | 	void (*release) (struct ipack_device *dev); | 
| Jens Taprogge | a19ad7d | 2012-09-27 12:37:31 +0200 | [diff] [blame] | 102 | 	struct ipack_region      region[IPACK_SPACE_COUNT]; | 
| Jens Taprogge | e8ed327 | 2012-09-04 17:01:15 +0200 | [diff] [blame] | 103 | 	u8                      *id; | 
| Jens Taprogge | 187e478 | 2012-09-04 17:01:14 +0200 | [diff] [blame] | 104 | 	size_t			 id_avail; | 
| Jens Taprogge | e8ed327 | 2012-09-04 17:01:15 +0200 | [diff] [blame] | 105 | 	u32			 id_vendor; | 
 | 106 | 	u32			 id_device; | 
| Jens Taprogge | 187e478 | 2012-09-04 17:01:14 +0200 | [diff] [blame] | 107 | 	u8			 id_format; | 
| Jens Taprogge | a92caeb | 2012-09-11 13:35:03 +0200 | [diff] [blame] | 108 | 	unsigned int		 id_crc_correct:1; | 
| Jens Taprogge | 0b0f3a1 | 2012-09-11 13:34:57 +0200 | [diff] [blame] | 109 | 	unsigned int		 speed_8mhz:1; | 
 | 110 | 	unsigned int		 speed_32mhz:1; | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 111 | }; | 
 | 112 |  | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 113 | /** | 
| Jens Taprogge | 26c295c | 2012-09-27 12:37:40 +0200 | [diff] [blame] | 114 |  * struct ipack_driver_ops -- Callbacks to IPack device driver | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 115 |  * | 
| Jens Taprogge | 26c295c | 2012-09-27 12:37:40 +0200 | [diff] [blame] | 116 |  * @probe:  Probe function | 
 | 117 |  * @remove: Prepare imminent removal of the device.  Services provided by the | 
 | 118 |  *          device should be revoked. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 119 |  */ | 
 | 120 |  | 
 | 121 | struct ipack_driver_ops { | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 122 | 	int (*probe) (struct ipack_device *dev); | 
 | 123 | 	void (*remove) (struct ipack_device *dev); | 
 | 124 | }; | 
 | 125 |  | 
 | 126 | /** | 
| Jens Taprogge | 26c295c | 2012-09-27 12:37:40 +0200 | [diff] [blame] | 127 |  * struct ipack_driver -- Specific data to each ipack device driver | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 128 |  * | 
| Jens Taprogge | 26c295c | 2012-09-27 12:37:40 +0200 | [diff] [blame] | 129 |  * @driver: Device driver kernel representation | 
 | 130 |  * @ops:    Callbacks provided by the IPack device driver | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 131 |  */ | 
 | 132 | struct ipack_driver { | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 133 | 	struct device_driver driver; | 
| Jens Taprogge | 849e0ad | 2012-09-04 17:01:13 +0200 | [diff] [blame] | 134 | 	const struct ipack_device_id *id_table; | 
| Jens Taprogge | e801113 | 2012-09-04 17:01:17 +0200 | [diff] [blame] | 135 | 	const struct ipack_driver_ops *ops; | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 136 | }; | 
 | 137 |  | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 138 | /** | 
 | 139 |  *	struct ipack_bus_ops - available operations on a bridge module | 
 | 140 |  * | 
 | 141 |  *	@map_space: map IP address space | 
 | 142 |  *	@unmap_space: unmap IP address space | 
 | 143 |  *	@request_irq: request IRQ | 
 | 144 |  *	@free_irq: free IRQ | 
| Jens Taprogge | 7b6ab33 | 2012-09-11 13:34:55 +0200 | [diff] [blame] | 145 |  *	@get_clockrate: Returns the clockrate the carrier is currently | 
 | 146 |  *		communicating with the device at. | 
 | 147 |  *	@set_clockrate: Sets the clock-rate for carrier / module communication. | 
 | 148 |  *		Should return -EINVAL if the requested speed is not supported. | 
 | 149 |  *	@get_error: Returns the error state for the slot the device is attached | 
 | 150 |  *		to. | 
 | 151 |  *	@get_timeout: Returns 1 if the communication with the device has | 
 | 152 |  *		previously timed out. | 
 | 153 |  *	@reset_timeout: Resets the state returned by get_timeout. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 154 |  */ | 
 | 155 | struct ipack_bus_ops { | 
| Jens Taprogge | c6e2dfa | 2012-09-13 12:32:21 +0200 | [diff] [blame] | 156 | 	int (*request_irq) (struct ipack_device *dev, | 
| Jens Taprogge | faa75c4 | 2012-09-12 14:55:38 +0200 | [diff] [blame] | 157 | 			    irqreturn_t (*handler)(void *), void *arg); | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 158 | 	int (*free_irq) (struct ipack_device *dev); | 
| Jens Taprogge | 7b6ab33 | 2012-09-11 13:34:55 +0200 | [diff] [blame] | 159 | 	int (*get_clockrate) (struct ipack_device *dev); | 
 | 160 | 	int (*set_clockrate) (struct ipack_device *dev, int mherz); | 
 | 161 | 	int (*get_error) (struct ipack_device *dev); | 
 | 162 | 	int (*get_timeout) (struct ipack_device *dev); | 
 | 163 | 	int (*reset_timeout) (struct ipack_device *dev); | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 164 | }; | 
 | 165 |  | 
 | 166 | /** | 
 | 167 |  *	struct ipack_bus_device | 
 | 168 |  * | 
 | 169 |  *	@dev: pointer to carrier device | 
 | 170 |  *	@slots: number of slots available | 
 | 171 |  *	@bus_nr: ipack bus number | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 172 |  *	@ops: bus operations for the mezzanine drivers | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 173 |  */ | 
 | 174 | struct ipack_bus_device { | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 175 | 	struct device *parent; | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 176 | 	int slots; | 
 | 177 | 	int bus_nr; | 
| Stephen Hemminger | 9869a93 | 2012-09-10 11:14:01 -0700 | [diff] [blame] | 178 | 	const struct ipack_bus_ops *ops; | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 179 | }; | 
 | 180 |  | 
 | 181 | /** | 
 | 182 |  *	ipack_bus_register -- register a new ipack bus | 
 | 183 |  * | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 184 |  * @parent: pointer to the parent device, if any. | 
 | 185 |  * @slots: number of slots available in the bus device. | 
 | 186 |  * @ops: bus operations for the mezzanine drivers. | 
 | 187 |  * | 
 | 188 |  * The carrier board device should call this function to register itself as | 
 | 189 |  * available bus device in ipack. | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 190 |  */ | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 191 | struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, | 
| Stephen Hemminger | 9869a93 | 2012-09-10 11:14:01 -0700 | [diff] [blame] | 192 | 					    const struct ipack_bus_ops *ops); | 
| Samuel Iglesias Gonsalvez | d346587 | 2012-05-09 15:27:19 +0200 | [diff] [blame] | 193 |  | 
 | 194 | /** | 
 | 195 |  *	ipack_bus_unregister -- unregister an ipack bus | 
 | 196 |  */ | 
 | 197 | int ipack_bus_unregister(struct ipack_bus_device *bus); | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 198 |  | 
 | 199 | /** | 
| Jens Taprogge | 26c295c | 2012-09-27 12:37:40 +0200 | [diff] [blame] | 200 |  * ipack_driver_register -- Register a new ipack device driver | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 201 |  * | 
 | 202 |  * Called by a ipack driver to register itself as a driver | 
 | 203 |  * that can manage ipack devices. | 
 | 204 |  */ | 
| Stephen Hemminger | 9869a93 | 2012-09-10 11:14:01 -0700 | [diff] [blame] | 205 | int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, | 
 | 206 | 			  const char *name); | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 207 | void ipack_driver_unregister(struct ipack_driver *edrv); | 
 | 208 |  | 
 | 209 | /** | 
| Jens Taprogge | 1e91795 | 2012-09-27 12:37:26 +0200 | [diff] [blame] | 210 |  *	ipack_device_register -- register an IPack device with the kernel | 
 | 211 |  *	@dev: the new device to register. | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 212 |  * | 
| Jens Taprogge | 1e91795 | 2012-09-27 12:37:26 +0200 | [diff] [blame] | 213 |  *	Register a new IPack device ("module" in IndustryPack jargon). The call | 
 | 214 |  *	is done by the carrier driver.  The carrier should populate the fields | 
| Jens Taprogge | a19ad7d | 2012-09-27 12:37:31 +0200 | [diff] [blame] | 215 |  *	bus and slot as well as the region array of @dev prior to calling this | 
 | 216 |  *	function.  The rest of the fields will be allocated and populated | 
 | 217 |  *	during registration. | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 218 |  * | 
| Jens Taprogge | 1e91795 | 2012-09-27 12:37:26 +0200 | [diff] [blame] | 219 |  *	Return zero on success or error code on failure. | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 220 |  */ | 
| Jens Taprogge | 1e91795 | 2012-09-27 12:37:26 +0200 | [diff] [blame] | 221 | int ipack_device_register(struct ipack_device *dev); | 
| Samuel Iglesias Gonsalvez | ec44033 | 2012-05-18 11:10:05 +0200 | [diff] [blame] | 222 | void ipack_device_unregister(struct ipack_device *dev); | 
| Jens Taprogge | 849e0ad | 2012-09-04 17:01:13 +0200 | [diff] [blame] | 223 |  | 
 | 224 | /** | 
 | 225 |  * DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table | 
 | 226 |  * @_table: device table name | 
 | 227 |  * | 
 | 228 |  * This macro is used to create a struct ipack_device_id array (a device table) | 
 | 229 |  * in a generic manner. | 
 | 230 |  */ | 
 | 231 | #define DEFINE_IPACK_DEVICE_TABLE(_table) \ | 
| Bill Pemberton | d79251f | 2012-11-19 13:25:25 -0500 | [diff] [blame] | 232 | 	const struct ipack_device_id _table[] | 
| Jens Taprogge | 849e0ad | 2012-09-04 17:01:13 +0200 | [diff] [blame] | 233 | /** | 
 | 234 |  * IPACK_DEVICE - macro used to describe a specific IndustryPack device | 
 | 235 |  * @_format: the format version (currently either 1 or 2, 8 bit value) | 
 | 236 |  * @vend:    the 8 or 24 bit IndustryPack Vendor ID | 
 | 237 |  * @dev:     the 8 or 16  bit IndustryPack Device ID | 
 | 238 |  * | 
 | 239 |  * This macro is used to create a struct ipack_device_id that matches a specific | 
 | 240 |  * device. | 
 | 241 |  */ | 
 | 242 | #define IPACK_DEVICE(_format, vend, dev) \ | 
 | 243 | 	 .format = (_format), \ | 
 | 244 | 	 .vendor = (vend), \ | 
 | 245 | 	 .device = (dev) |