aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux/ipack.h
blob: 8bddc3fbdddfb164cb4b8dc671311b92441b7460 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*
 * Industry-pack bus.
 *
 * Copyright (C) 2011-2012 CERN (www.cern.ch)
 * Author: Samuel Iglesias Gonsalvez <siglesias@igalia.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; version 2 of the License.
 */

#include <linux/mod_devicetable.h>
#include <linux/device.h>
#include <linux/interrupt.h>

#define IPACK_IDPROM_OFFSET_I			0x01
#define IPACK_IDPROM_OFFSET_P			0x03
#define IPACK_IDPROM_OFFSET_A			0x05
#define IPACK_IDPROM_OFFSET_C			0x07
#define IPACK_IDPROM_OFFSET_MANUFACTURER_ID	0x09
#define IPACK_IDPROM_OFFSET_MODEL		0x0B
#define IPACK_IDPROM_OFFSET_REVISION		0x0D
#define IPACK_IDPROM_OFFSET_RESERVED		0x0F
#define IPACK_IDPROM_OFFSET_DRIVER_ID_L		0x11
#define IPACK_IDPROM_OFFSET_DRIVER_ID_H		0x13
#define IPACK_IDPROM_OFFSET_NUM_BYTES		0x15
#define IPACK_IDPROM_OFFSET_CRC			0x17

/*
 * IndustryPack Fromat, Vendor and Device IDs.
 */

/* ID section format versions */
#define IPACK_ID_VERSION_INVALID	0x00
#define IPACK_ID_VERSION_1		0x01
#define IPACK_ID_VERSION_2		0x02

/* Vendors and devices. Sort key: vendor first, device next. */
#define IPACK1_VENDOR_ID_RESERVED1	0x00
#define IPACK1_VENDOR_ID_RESERVED2	0xFF
#define IPACK1_VENDOR_ID_UNREGISTRED01	0x01
#define IPACK1_VENDOR_ID_UNREGISTRED02	0x02
#define IPACK1_VENDOR_ID_UNREGISTRED03	0x03
#define IPACK1_VENDOR_ID_UNREGISTRED04	0x04
#define IPACK1_VENDOR_ID_UNREGISTRED05	0x05
#define IPACK1_VENDOR_ID_UNREGISTRED06	0x06
#define IPACK1_VENDOR_ID_UNREGISTRED07	0x07
#define IPACK1_VENDOR_ID_UNREGISTRED08	0x08
#define IPACK1_VENDOR_ID_UNREGISTRED09	0x09
#define IPACK1_VENDOR_ID_UNREGISTRED10	0x0A
#define IPACK1_VENDOR_ID_UNREGISTRED11	0x0B
#define IPACK1_VENDOR_ID_UNREGISTRED12	0x0C
#define IPACK1_VENDOR_ID_UNREGISTRED13	0x0D
#define IPACK1_VENDOR_ID_UNREGISTRED14	0x0E
#define IPACK1_VENDOR_ID_UNREGISTRED15	0x0F

#define IPACK1_VENDOR_ID_SBS            0xF0
#define IPACK1_DEVICE_ID_SBS_OCTAL_232  0x22
#define IPACK1_DEVICE_ID_SBS_OCTAL_422  0x2A
#define IPACK1_DEVICE_ID_SBS_OCTAL_485  0x48

struct ipack_bus_ops;
struct ipack_driver;

enum ipack_space {
	IPACK_IO_SPACE    = 0,
	IPACK_ID_SPACE,
	IPACK_INT_SPACE,
	IPACK_MEM8_SPACE,
	IPACK_MEM16_SPACE,
	/* Dummy for counting the number of entries.  Must remain the last
	 * entry */
	IPACK_SPACE_COUNT,
};

/**
 */
struct ipack_region {
	phys_addr_t start;
	size_t      size;
};

/**
 *	struct ipack_device
 *
 *	@slot: Slot where the device is plugged in the carrier board
 *	@bus: ipack_bus_device where the device is plugged to.
 *	@id_space: Virtual address to ID space.
 *	@io_space: Virtual address to IO space.
 *	@mem_space: Virtual address to MEM space.
 *	@dev: device in kernel representation.
 *
 * Warning: Direct access to mapped memory is possible but the endianness
 * is not the same with PCI carrier or VME carrier. The endianness is managed
 * by the carrier board throught bus->ops.
 */
struct ipack_device {
	unsigned int slot;
	struct ipack_bus_device *bus;
	struct device dev;
	void (*release) (struct ipack_device *dev);
	struct ipack_region      region[IPACK_SPACE_COUNT];
	u8                      *id;
	size_t			 id_avail;
	u32			 id_vendor;
	u32			 id_device;
	u8			 id_format;
	unsigned int		 id_crc_correct:1;
	unsigned int		 speed_8mhz:1;
	unsigned int		 speed_32mhz:1;
};

/**
 * struct ipack_driver_ops -- Callbacks to IPack device driver
 *
 * @probe:  Probe function
 * @remove: Prepare imminent removal of the device.  Services provided by the
 *          device should be revoked.
 */

struct ipack_driver_ops {
	int (*probe) (struct ipack_device *dev);
	void (*remove) (struct ipack_device *dev);
};

/**
 * struct ipack_driver -- Specific data to each ipack device driver
 *
 * @driver: Device driver kernel representation
 * @ops:    Callbacks provided by the IPack device driver
 */
struct ipack_driver {
	struct device_driver driver;
	const struct ipack_device_id *id_table;
	const struct ipack_driver_ops *ops;
};

/**
 *	struct ipack_bus_ops - available operations on a bridge module
 *
 *	@map_space: map IP address space
 *	@unmap_space: unmap IP address space
 *	@request_irq: request IRQ
 *	@free_irq: free IRQ
 *	@get_clockrate: Returns the clockrate the carrier is currently
 *		communicating with the device at.
 *	@set_clockrate: Sets the clock-rate for carrier / module communication.
 *		Should return -EINVAL if the requested speed is not supported.
 *	@get_error: Returns the error state for the slot the device is attached
 *		to.
 *	@get_timeout: Returns 1 if the communication with the device has
 *		previously timed out.
 *	@reset_timeout: Resets the state returned by get_timeout.
 */
struct ipack_bus_ops {
	int (*request_irq) (struct ipack_device *dev,
			    irqreturn_t (*handler)(void *), void *arg);
	int (*free_irq) (struct ipack_device *dev);
	int (*get_clockrate) (struct ipack_device *dev);
	int (*set_clockrate) (struct ipack_device *dev, int mherz);
	int (*get_error) (struct ipack_device *dev);
	int (*get_timeout) (struct ipack_device *dev);
	int (*reset_timeout) (struct ipack_device *dev);
};

/**
 *	struct ipack_bus_device
 *
 *	@dev: pointer to carrier device
 *	@slots: number of slots available
 *	@bus_nr: ipack bus number
 *	@ops: bus operations for the mezzanine drivers
 */
struct ipack_bus_device {
	struct module *owner;
	struct device *parent;
	int slots;
	int bus_nr;
	const struct ipack_bus_ops *ops;
};

/**
 *	ipack_bus_register -- register a new ipack bus
 *
 * @parent: pointer to the parent device, if any.
 * @slots: number of slots available in the bus device.
 * @ops: bus operations for the mezzanine drivers.
 *
 * The carrier board device should call this function to register itself as
 * available bus device in ipack.
 */
struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots,
					    const struct ipack_bus_ops *ops,
					    struct module *owner);

/**
 *	ipack_bus_unregister -- unregister an ipack bus
 */
int ipack_bus_unregister(struct ipack_bus_device *bus);

/**
 * ipack_driver_register -- Register a new ipack device driver
 *
 * Called by a ipack driver to register itself as a driver
 * that can manage ipack devices.
 */
int ipack_driver_register(struct ipack_driver *edrv, struct module *owner,
			  const char *name);
void ipack_driver_unregister(struct ipack_driver *edrv);

/**
 *	ipack_device_init -- initialize an IPack device
 * @dev: the new device to initialize.
 *
 * Initialize a new IPack device ("module" in IndustryPack jargon). The call
 * is done by the carrier driver.  The carrier should populate the fields
 * bus and slot as well as the region array of @dev prior to calling this
 * function.  The rest of the fields will be allocated and populated
 * during initalization.
 *
 * Return zero on success or error code on failure.
 *
 * NOTE: _Never_ directly free @dev after calling this function, even
 * if it returned an error! Always use ipack_put_device() to give up the
 * reference initialized in this function instead.
 */
int ipack_device_init(struct ipack_device *dev);

/**
 *	ipack_device_add -- Add an IPack device
 * @dev: the new device to add.
 *
 * Add a new IPack device. The call is done by the carrier driver
 * after calling ipack_device_init().
 *
 * Return zero on success or error code on failure.
 *
 * NOTE: _Never_ directly free @dev after calling this function, even
 * if it returned an error! Always use ipack_put_device() to give up the
 * reference initialized in this function instead.
 */
int ipack_device_add(struct ipack_device *dev);
void ipack_device_del(struct ipack_device *dev);

void ipack_get_device(struct ipack_device *dev);
void ipack_put_device(struct ipack_device *dev);

/**
 * DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table
 * @_table: device table name
 *
 * This macro is used to create a struct ipack_device_id array (a device table)
 * in a generic manner.
 */
#define DEFINE_IPACK_DEVICE_TABLE(_table) \
	const struct ipack_device_id _table[]
/**
 * IPACK_DEVICE - macro used to describe a specific IndustryPack device
 * @_format: the format version (currently either 1 or 2, 8 bit value)
 * @vend:    the 8 or 24 bit IndustryPack Vendor ID
 * @dev:     the 8 or 16  bit IndustryPack Device ID
 *
 * This macro is used to create a struct ipack_device_id that matches a specific
 * device.
 */
#define IPACK_DEVICE(_format, vend, dev) \
	 .format = (_format), \
	 .vendor = (vend), \
	 .device = (dev)

/**
 * ipack_get_carrier - it increase the carrier ref. counter of
 *                     the carrier module
 * @dev: mezzanine device which wants to get the carrier
 */
static inline int ipack_get_carrier(struct ipack_device *dev)
{
	return try_module_get(dev->bus->owner);
}

/**
 * ipack_get_carrier - it decrease the carrier ref. counter of
 *                     the carrier module
 * @dev: mezzanine device which wants to get the carrier
 */
static inline void ipack_put_carrier(struct ipack_device *dev)
{
	module_put(dev->bus->owner);
}