• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * comedi/drivers/dt9812.c
3  *   COMEDI driver for DataTranslation DT9812 USB module
4  *
5  * Copyright (C) 2005 Anders Blomdell <anders.blomdell@control.lth.se>
6  *
7  * COMEDI - Linux Control and Measurement Device Interface
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13 
14  *  This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  */
19 
20 /*
21 Driver: dt9812
22 Description: Data Translation DT9812 USB module
23 Author: anders.blomdell@control.lth.se (Anders Blomdell)
24 Status: in development
25 Devices: [Data Translation] DT9812 (dt9812)
26 Updated: Sun Nov 20 20:18:34 EST 2005
27 
28 This driver works, but bulk transfers not implemented. Might be a starting point
29 for someone else. I found out too late that USB has too high latencies (>1 ms)
30 for my needs.
31 */
32 
33 /*
34  * Nota Bene:
35  *   1. All writes to command pipe has to be 32 bytes (ISP1181B SHRTP=0 ?)
36  *   2. The DDK source (as of sep 2005) is in error regarding the
37  *      input MUX bits (example code says P4, but firmware schematics
38  *      says P1).
39  */
40 
41 #include <linux/kernel.h>
42 #include <linux/module.h>
43 #include <linux/errno.h>
44 #include <linux/uaccess.h>
45 #include <linux/usb.h>
46 
47 #include "../comedidev.h"
48 
49 #define DT9812_DIAGS_BOARD_INFO_ADDR	0xFBFF
50 #define DT9812_MAX_WRITE_CMD_PIPE_SIZE	32
51 #define DT9812_MAX_READ_CMD_PIPE_SIZE	32
52 
53 /* usb_bulk_msg() timout in milliseconds */
54 #define DT9812_USB_TIMEOUT		1000
55 
56 /*
57  * See Silican Laboratories C8051F020/1/2/3 manual
58  */
59 #define F020_SFR_P4			0x84
60 #define F020_SFR_P1			0x90
61 #define F020_SFR_P2			0xa0
62 #define F020_SFR_P3			0xb0
63 #define F020_SFR_AMX0CF			0xba
64 #define F020_SFR_AMX0SL			0xbb
65 #define F020_SFR_ADC0CF			0xbc
66 #define F020_SFR_ADC0L			0xbe
67 #define F020_SFR_ADC0H			0xbf
68 #define F020_SFR_DAC0L			0xd2
69 #define F020_SFR_DAC0H			0xd3
70 #define F020_SFR_DAC0CN			0xd4
71 #define F020_SFR_DAC1L			0xd5
72 #define F020_SFR_DAC1H			0xd6
73 #define F020_SFR_DAC1CN			0xd7
74 #define F020_SFR_ADC0CN			0xe8
75 
76 #define F020_MASK_ADC0CF_AMP0GN0	0x01
77 #define F020_MASK_ADC0CF_AMP0GN1	0x02
78 #define F020_MASK_ADC0CF_AMP0GN2	0x04
79 
80 #define F020_MASK_ADC0CN_AD0EN		0x80
81 #define F020_MASK_ADC0CN_AD0INT		0x20
82 #define F020_MASK_ADC0CN_AD0BUSY	0x10
83 
84 #define F020_MASK_DACxCN_DACxEN		0x80
85 
86 enum {
87 					/* A/D  D/A  DI  DO  CT */
88 	DT9812_DEVID_DT9812_10,		/*  8    2   8   8   1  +/- 10V */
89 	DT9812_DEVID_DT9812_2PT5,	/*  8    2   8   8   1  0-2.44V */
90 };
91 
92 enum dt9812_gain {
93 	DT9812_GAIN_0PT25 = 1,
94 	DT9812_GAIN_0PT5 = 2,
95 	DT9812_GAIN_1 = 4,
96 	DT9812_GAIN_2 = 8,
97 	DT9812_GAIN_4 = 16,
98 	DT9812_GAIN_8 = 32,
99 	DT9812_GAIN_16 = 64,
100 };
101 
102 enum {
103 	DT9812_LEAST_USB_FIRMWARE_CMD_CODE = 0,
104 	/* Write Flash memory */
105 	DT9812_W_FLASH_DATA = 0,
106 	/* Read Flash memory misc config info */
107 	DT9812_R_FLASH_DATA = 1,
108 
109 	/*
110 	 * Register read/write commands for processor
111 	 */
112 
113 	/* Read a single byte of USB memory */
114 	DT9812_R_SINGLE_BYTE_REG = 2,
115 	/* Write a single byte of USB memory */
116 	DT9812_W_SINGLE_BYTE_REG = 3,
117 	/* Multiple Reads of USB memory */
118 	DT9812_R_MULTI_BYTE_REG = 4,
119 	/* Multiple Writes of USB memory */
120 	DT9812_W_MULTI_BYTE_REG = 5,
121 	/* Read, (AND) with mask, OR value, then write (single) */
122 	DT9812_RMW_SINGLE_BYTE_REG = 6,
123 	/* Read, (AND) with mask, OR value, then write (multiple) */
124 	DT9812_RMW_MULTI_BYTE_REG = 7,
125 
126 	/*
127 	 * Register read/write commands for SMBus
128 	 */
129 
130 	/* Read a single byte of SMBus */
131 	DT9812_R_SINGLE_BYTE_SMBUS = 8,
132 	/* Write a single byte of SMBus */
133 	DT9812_W_SINGLE_BYTE_SMBUS = 9,
134 	/* Multiple Reads of SMBus */
135 	DT9812_R_MULTI_BYTE_SMBUS = 10,
136 	/* Multiple Writes of SMBus */
137 	DT9812_W_MULTI_BYTE_SMBUS = 11,
138 
139 	/*
140 	 * Register read/write commands for a device
141 	 */
142 
143 	/* Read a single byte of a device */
144 	DT9812_R_SINGLE_BYTE_DEV = 12,
145 	/* Write a single byte of a device */
146 	DT9812_W_SINGLE_BYTE_DEV = 13,
147 	/* Multiple Reads of a device */
148 	DT9812_R_MULTI_BYTE_DEV = 14,
149 	/* Multiple Writes of a device */
150 	DT9812_W_MULTI_BYTE_DEV = 15,
151 
152 	/* Not sure if we'll need this */
153 	DT9812_W_DAC_THRESHOLD = 16,
154 
155 	/* Set interrupt on change mask */
156 	DT9812_W_INT_ON_CHANGE_MASK = 17,
157 
158 	/* Write (or Clear) the CGL for the ADC */
159 	DT9812_W_CGL = 18,
160 	/* Multiple Reads of USB memory */
161 	DT9812_R_MULTI_BYTE_USBMEM = 19,
162 	/* Multiple Writes to USB memory */
163 	DT9812_W_MULTI_BYTE_USBMEM = 20,
164 
165 	/* Issue a start command to a given subsystem */
166 	DT9812_START_SUBSYSTEM = 21,
167 	/* Issue a stop command to a given subsystem */
168 	DT9812_STOP_SUBSYSTEM = 22,
169 
170 	/* calibrate the board using CAL_POT_CMD */
171 	DT9812_CALIBRATE_POT = 23,
172 	/* set the DAC FIFO size */
173 	DT9812_W_DAC_FIFO_SIZE = 24,
174 	/* Write or Clear the CGL for the DAC */
175 	DT9812_W_CGL_DAC = 25,
176 	/* Read a single value from a subsystem */
177 	DT9812_R_SINGLE_VALUE_CMD = 26,
178 	/* Write a single value to a subsystem */
179 	DT9812_W_SINGLE_VALUE_CMD = 27,
180 	/* Valid DT9812_USB_FIRMWARE_CMD_CODE's will be less than this number */
181 	DT9812_MAX_USB_FIRMWARE_CMD_CODE,
182 };
183 
184 struct dt9812_flash_data {
185 	__le16 numbytes;
186 	__le16 address;
187 };
188 
189 #define DT9812_MAX_NUM_MULTI_BYTE_RDS  \
190 	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / sizeof(u8))
191 
192 struct dt9812_read_multi {
193 	u8 count;
194 	u8 address[DT9812_MAX_NUM_MULTI_BYTE_RDS];
195 };
196 
197 struct dt9812_write_byte {
198 	u8 address;
199 	u8 value;
200 };
201 
202 #define DT9812_MAX_NUM_MULTI_BYTE_WRTS  \
203 	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
204 	 sizeof(struct dt9812_write_byte))
205 
206 struct dt9812_write_multi {
207 	u8 count;
208 	struct dt9812_write_byte write[DT9812_MAX_NUM_MULTI_BYTE_WRTS];
209 };
210 
211 struct dt9812_rmw_byte {
212 	u8 address;
213 	u8 and_mask;
214 	u8 or_value;
215 };
216 
217 #define DT9812_MAX_NUM_MULTI_BYTE_RMWS  \
218 	((DT9812_MAX_WRITE_CMD_PIPE_SIZE - 4 - 1) / \
219 	 sizeof(struct dt9812_rmw_byte))
220 
221 struct dt9812_rmw_multi {
222 	u8 count;
223 	struct dt9812_rmw_byte rmw[DT9812_MAX_NUM_MULTI_BYTE_RMWS];
224 };
225 
226 struct dt9812_usb_cmd {
227 	__le32 cmd;
228 	union {
229 		struct dt9812_flash_data flash_data_info;
230 		struct dt9812_read_multi read_multi_info;
231 		struct dt9812_write_multi write_multi_info;
232 		struct dt9812_rmw_multi rmw_multi_info;
233 	} u;
234 };
235 
236 struct dt9812_private {
237 	struct semaphore sem;
238 	struct {
239 		__u8 addr;
240 		size_t size;
241 	} cmd_wr, cmd_rd;
242 	u16 device;
243 };
244 
dt9812_read_info(struct comedi_device * dev,int offset,void * buf,size_t buf_size)245 static int dt9812_read_info(struct comedi_device *dev,
246 			    int offset, void *buf, size_t buf_size)
247 {
248 	struct usb_device *usb = comedi_to_usb_dev(dev);
249 	struct dt9812_private *devpriv = dev->private;
250 	struct dt9812_usb_cmd cmd;
251 	int count, ret;
252 
253 	cmd.cmd = cpu_to_le32(DT9812_R_FLASH_DATA);
254 	cmd.u.flash_data_info.address =
255 	    cpu_to_le16(DT9812_DIAGS_BOARD_INFO_ADDR + offset);
256 	cmd.u.flash_data_info.numbytes = cpu_to_le16(buf_size);
257 
258 	/* DT9812 only responds to 32 byte writes!! */
259 	ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
260 			   &cmd, 32, &count, DT9812_USB_TIMEOUT);
261 	if (ret)
262 		return ret;
263 
264 	return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
265 			    buf, buf_size, &count, DT9812_USB_TIMEOUT);
266 }
267 
dt9812_read_multiple_registers(struct comedi_device * dev,int reg_count,u8 * address,u8 * value)268 static int dt9812_read_multiple_registers(struct comedi_device *dev,
269 					  int reg_count, u8 *address,
270 					  u8 *value)
271 {
272 	struct usb_device *usb = comedi_to_usb_dev(dev);
273 	struct dt9812_private *devpriv = dev->private;
274 	struct dt9812_usb_cmd cmd;
275 	int i, count, ret;
276 
277 	cmd.cmd = cpu_to_le32(DT9812_R_MULTI_BYTE_REG);
278 	cmd.u.read_multi_info.count = reg_count;
279 	for (i = 0; i < reg_count; i++)
280 		cmd.u.read_multi_info.address[i] = address[i];
281 
282 	/* DT9812 only responds to 32 byte writes!! */
283 	ret = usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
284 			   &cmd, 32, &count, DT9812_USB_TIMEOUT);
285 	if (ret)
286 		return ret;
287 
288 	return usb_bulk_msg(usb, usb_rcvbulkpipe(usb, devpriv->cmd_rd.addr),
289 			    value, reg_count, &count, DT9812_USB_TIMEOUT);
290 }
291 
dt9812_write_multiple_registers(struct comedi_device * dev,int reg_count,u8 * address,u8 * value)292 static int dt9812_write_multiple_registers(struct comedi_device *dev,
293 					   int reg_count, u8 *address,
294 					   u8 *value)
295 {
296 	struct usb_device *usb = comedi_to_usb_dev(dev);
297 	struct dt9812_private *devpriv = dev->private;
298 	struct dt9812_usb_cmd cmd;
299 	int i, count;
300 
301 	cmd.cmd = cpu_to_le32(DT9812_W_MULTI_BYTE_REG);
302 	cmd.u.read_multi_info.count = reg_count;
303 	for (i = 0; i < reg_count; i++) {
304 		cmd.u.write_multi_info.write[i].address = address[i];
305 		cmd.u.write_multi_info.write[i].value = value[i];
306 	}
307 
308 	/* DT9812 only responds to 32 byte writes!! */
309 	return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
310 			    &cmd, 32, &count, DT9812_USB_TIMEOUT);
311 }
312 
dt9812_rmw_multiple_registers(struct comedi_device * dev,int reg_count,struct dt9812_rmw_byte * rmw)313 static int dt9812_rmw_multiple_registers(struct comedi_device *dev,
314 					 int reg_count,
315 					 struct dt9812_rmw_byte *rmw)
316 {
317 	struct usb_device *usb = comedi_to_usb_dev(dev);
318 	struct dt9812_private *devpriv = dev->private;
319 	struct dt9812_usb_cmd cmd;
320 	int i, count;
321 
322 	cmd.cmd = cpu_to_le32(DT9812_RMW_MULTI_BYTE_REG);
323 	cmd.u.rmw_multi_info.count = reg_count;
324 	for (i = 0; i < reg_count; i++)
325 		cmd.u.rmw_multi_info.rmw[i] = rmw[i];
326 
327 	/* DT9812 only responds to 32 byte writes!! */
328 	return usb_bulk_msg(usb, usb_sndbulkpipe(usb, devpriv->cmd_wr.addr),
329 			    &cmd, 32, &count, DT9812_USB_TIMEOUT);
330 }
331 
dt9812_digital_in(struct comedi_device * dev,u8 * bits)332 static int dt9812_digital_in(struct comedi_device *dev, u8 *bits)
333 {
334 	struct dt9812_private *devpriv = dev->private;
335 	u8 reg[2] = { F020_SFR_P3, F020_SFR_P1 };
336 	u8 value[2];
337 	int ret;
338 
339 	down(&devpriv->sem);
340 	ret = dt9812_read_multiple_registers(dev, 2, reg, value);
341 	if (ret == 0) {
342 		/*
343 		 * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital
344 		 * input port bit 3 in F020_SFR_P1 is bit 7 in the
345 		 * digital input port
346 		 */
347 		*bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4);
348 	}
349 	up(&devpriv->sem);
350 
351 	return ret;
352 }
353 
dt9812_digital_out(struct comedi_device * dev,u8 bits)354 static int dt9812_digital_out(struct comedi_device *dev, u8 bits)
355 {
356 	struct dt9812_private *devpriv = dev->private;
357 	u8 reg[1] = { F020_SFR_P2 };
358 	u8 value[1] = { bits };
359 	int ret;
360 
361 	down(&devpriv->sem);
362 	ret = dt9812_write_multiple_registers(dev, 1, reg, value);
363 	up(&devpriv->sem);
364 
365 	return ret;
366 }
367 
dt9812_configure_mux(struct comedi_device * dev,struct dt9812_rmw_byte * rmw,int channel)368 static void dt9812_configure_mux(struct comedi_device *dev,
369 				 struct dt9812_rmw_byte *rmw, int channel)
370 {
371 	struct dt9812_private *devpriv = dev->private;
372 
373 	if (devpriv->device == DT9812_DEVID_DT9812_10) {
374 		/* In the DT9812/10V MUX is selected by P1.5-7 */
375 		rmw->address = F020_SFR_P1;
376 		rmw->and_mask = 0xe0;
377 		rmw->or_value = channel << 5;
378 	} else {
379 		/* In the DT9812/2.5V, internal mux is selected by bits 0:2 */
380 		rmw->address = F020_SFR_AMX0SL;
381 		rmw->and_mask = 0xff;
382 		rmw->or_value = channel & 0x07;
383 	}
384 }
385 
dt9812_configure_gain(struct comedi_device * dev,struct dt9812_rmw_byte * rmw,enum dt9812_gain gain)386 static void dt9812_configure_gain(struct comedi_device *dev,
387 				  struct dt9812_rmw_byte *rmw,
388 				  enum dt9812_gain gain)
389 {
390 	struct dt9812_private *devpriv = dev->private;
391 
392 	/* In the DT9812/10V, there is an external gain of 0.5 */
393 	if (devpriv->device == DT9812_DEVID_DT9812_10)
394 		gain <<= 1;
395 
396 	rmw->address = F020_SFR_ADC0CF;
397 	rmw->and_mask = F020_MASK_ADC0CF_AMP0GN2 |
398 			F020_MASK_ADC0CF_AMP0GN1 |
399 			F020_MASK_ADC0CF_AMP0GN0;
400 
401 	switch (gain) {
402 		/*
403 		 * 000 -> Gain =  1
404 		 * 001 -> Gain =  2
405 		 * 010 -> Gain =  4
406 		 * 011 -> Gain =  8
407 		 * 10x -> Gain = 16
408 		 * 11x -> Gain =  0.5
409 		 */
410 	case DT9812_GAIN_0PT5:
411 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 |
412 				F020_MASK_ADC0CF_AMP0GN1;
413 		break;
414 	default:
415 		/* this should never happen, just use a gain of 1 */
416 	case DT9812_GAIN_1:
417 		rmw->or_value = 0x00;
418 		break;
419 	case DT9812_GAIN_2:
420 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN0;
421 		break;
422 	case DT9812_GAIN_4:
423 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN1;
424 		break;
425 	case DT9812_GAIN_8:
426 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 |
427 				F020_MASK_ADC0CF_AMP0GN0;
428 		break;
429 	case DT9812_GAIN_16:
430 		rmw->or_value = F020_MASK_ADC0CF_AMP0GN2;
431 		break;
432 	}
433 }
434 
dt9812_analog_in(struct comedi_device * dev,int channel,u16 * value,enum dt9812_gain gain)435 static int dt9812_analog_in(struct comedi_device *dev,
436 			    int channel, u16 *value, enum dt9812_gain gain)
437 {
438 	struct dt9812_private *devpriv = dev->private;
439 	struct dt9812_rmw_byte rmw[3];
440 	u8 reg[3] = {
441 		F020_SFR_ADC0CN,
442 		F020_SFR_ADC0H,
443 		F020_SFR_ADC0L
444 	};
445 	u8 val[3];
446 	int ret;
447 
448 	down(&devpriv->sem);
449 
450 	/* 1 select the gain */
451 	dt9812_configure_gain(dev, &rmw[0], gain);
452 
453 	/* 2 set the MUX to select the channel */
454 	dt9812_configure_mux(dev, &rmw[1], channel);
455 
456 	/* 3 start conversion */
457 	rmw[2].address = F020_SFR_ADC0CN;
458 	rmw[2].and_mask = 0xff;
459 	rmw[2].or_value = F020_MASK_ADC0CN_AD0EN | F020_MASK_ADC0CN_AD0BUSY;
460 
461 	ret = dt9812_rmw_multiple_registers(dev, 3, rmw);
462 	if (ret)
463 		goto exit;
464 
465 	/* read the status and ADC */
466 	ret = dt9812_read_multiple_registers(dev, 3, reg, val);
467 	if (ret)
468 		goto exit;
469 
470 	/*
471 	 * An ADC conversion takes 16 SAR clocks cycles, i.e. about 9us.
472 	 * Therefore, between the instant that AD0BUSY was set via
473 	 * dt9812_rmw_multiple_registers and the read of AD0BUSY via
474 	 * dt9812_read_multiple_registers, the conversion should be complete
475 	 * since these two operations require two USB transactions each taking
476 	 * at least a millisecond to complete.  However, lets make sure that
477 	 * conversion is finished.
478 	 */
479 	if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) ==
480 	    F020_MASK_ADC0CN_AD0INT) {
481 		switch (devpriv->device) {
482 		case DT9812_DEVID_DT9812_10:
483 			/*
484 			 * For DT9812-10V the personality module set the
485 			 * encoding to 2's complement. Hence, convert it before
486 			 * returning it
487 			 */
488 			*value = ((val[1] << 8) | val[2]) + 0x800;
489 			break;
490 		case DT9812_DEVID_DT9812_2PT5:
491 			*value = (val[1] << 8) | val[2];
492 			break;
493 		}
494 	}
495 
496 exit:
497 	up(&devpriv->sem);
498 
499 	return ret;
500 }
501 
dt9812_analog_out(struct comedi_device * dev,int channel,u16 value)502 static int dt9812_analog_out(struct comedi_device *dev, int channel, u16 value)
503 {
504 	struct dt9812_private *devpriv = dev->private;
505 	struct dt9812_rmw_byte rmw[3];
506 	int ret;
507 
508 	down(&devpriv->sem);
509 
510 	switch (channel) {
511 	case 0:
512 		/* 1. Set DAC mode */
513 		rmw[0].address = F020_SFR_DAC0CN;
514 		rmw[0].and_mask = 0xff;
515 		rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
516 
517 		/* 2 load low byte of DAC value first */
518 		rmw[1].address = F020_SFR_DAC0L;
519 		rmw[1].and_mask = 0xff;
520 		rmw[1].or_value = value & 0xff;
521 
522 		/* 3 load high byte of DAC value next to latch the
523 			12-bit value */
524 		rmw[2].address = F020_SFR_DAC0H;
525 		rmw[2].and_mask = 0xff;
526 		rmw[2].or_value = (value >> 8) & 0xf;
527 		break;
528 
529 	case 1:
530 		/* 1. Set DAC mode */
531 		rmw[0].address = F020_SFR_DAC1CN;
532 		rmw[0].and_mask = 0xff;
533 		rmw[0].or_value = F020_MASK_DACxCN_DACxEN;
534 
535 		/* 2 load low byte of DAC value first */
536 		rmw[1].address = F020_SFR_DAC1L;
537 		rmw[1].and_mask = 0xff;
538 		rmw[1].or_value = value & 0xff;
539 
540 		/* 3 load high byte of DAC value next to latch the
541 			12-bit value */
542 		rmw[2].address = F020_SFR_DAC1H;
543 		rmw[2].and_mask = 0xff;
544 		rmw[2].or_value = (value >> 8) & 0xf;
545 		break;
546 	}
547 	ret = dt9812_rmw_multiple_registers(dev, 3, rmw);
548 
549 	up(&devpriv->sem);
550 
551 	return ret;
552 }
553 
dt9812_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)554 static int dt9812_di_insn_bits(struct comedi_device *dev,
555 			       struct comedi_subdevice *s,
556 			       struct comedi_insn *insn,
557 			       unsigned int *data)
558 {
559 	u8 bits = 0;
560 	int ret;
561 
562 	ret = dt9812_digital_in(dev, &bits);
563 	if (ret)
564 		return ret;
565 
566 	data[1] = bits;
567 
568 	return insn->n;
569 }
570 
dt9812_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)571 static int dt9812_do_insn_bits(struct comedi_device *dev,
572 			       struct comedi_subdevice *s,
573 			       struct comedi_insn *insn,
574 			       unsigned int *data)
575 {
576 	if (comedi_dio_update_state(s, data))
577 		dt9812_digital_out(dev, s->state);
578 
579 	data[1] = s->state;
580 
581 	return insn->n;
582 }
583 
dt9812_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)584 static int dt9812_ai_insn_read(struct comedi_device *dev,
585 			       struct comedi_subdevice *s,
586 			       struct comedi_insn *insn,
587 			       unsigned int *data)
588 {
589 	unsigned int chan = CR_CHAN(insn->chanspec);
590 	u16 val = 0;
591 	int ret;
592 	int i;
593 
594 	for (i = 0; i < insn->n; i++) {
595 		ret = dt9812_analog_in(dev, chan, &val, DT9812_GAIN_1);
596 		if (ret)
597 			return ret;
598 		data[i] = val;
599 	}
600 
601 	return insn->n;
602 }
603 
dt9812_ao_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)604 static int dt9812_ao_insn_read(struct comedi_device *dev,
605 			       struct comedi_subdevice *s,
606 			       struct comedi_insn *insn,
607 			       unsigned int *data)
608 {
609 	struct dt9812_private *devpriv = dev->private;
610 	int ret;
611 
612 	down(&devpriv->sem);
613 	ret = comedi_readback_insn_read(dev, s, insn, data);
614 	up(&devpriv->sem);
615 
616 	return ret;
617 }
618 
dt9812_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)619 static int dt9812_ao_insn_write(struct comedi_device *dev,
620 				struct comedi_subdevice *s,
621 				struct comedi_insn *insn,
622 				unsigned int *data)
623 {
624 	unsigned int chan = CR_CHAN(insn->chanspec);
625 	int i;
626 
627 	for (i = 0; i < insn->n; i++) {
628 		unsigned int val = data[i];
629 		int ret;
630 
631 		ret = dt9812_analog_out(dev, chan, val);
632 		if (ret)
633 			return ret;
634 
635 		s->readback[chan] = val;
636 	}
637 
638 	return insn->n;
639 }
640 
dt9812_find_endpoints(struct comedi_device * dev)641 static int dt9812_find_endpoints(struct comedi_device *dev)
642 {
643 	struct usb_interface *intf = comedi_to_usb_interface(dev);
644 	struct usb_host_interface *host = intf->cur_altsetting;
645 	struct dt9812_private *devpriv = dev->private;
646 	struct usb_endpoint_descriptor *ep;
647 	int i;
648 
649 	if (host->desc.bNumEndpoints != 5) {
650 		dev_err(dev->class_dev, "Wrong number of endpoints\n");
651 		return -ENODEV;
652 	}
653 
654 	for (i = 0; i < host->desc.bNumEndpoints; ++i) {
655 		int dir = -1;
656 
657 		ep = &host->endpoint[i].desc;
658 		switch (i) {
659 		case 0:
660 			/* unused message pipe */
661 			dir = USB_DIR_IN;
662 			break;
663 		case 1:
664 			dir = USB_DIR_OUT;
665 			devpriv->cmd_wr.addr = ep->bEndpointAddress;
666 			devpriv->cmd_wr.size = le16_to_cpu(ep->wMaxPacketSize);
667 			break;
668 		case 2:
669 			dir = USB_DIR_IN;
670 			devpriv->cmd_rd.addr = ep->bEndpointAddress;
671 			devpriv->cmd_rd.size = le16_to_cpu(ep->wMaxPacketSize);
672 			break;
673 		case 3:
674 			/* unused write stream */
675 			dir = USB_DIR_OUT;
676 			break;
677 		case 4:
678 			/* unused read stream */
679 			dir = USB_DIR_IN;
680 			break;
681 		}
682 		if ((ep->bEndpointAddress & USB_DIR_IN) != dir) {
683 			dev_err(dev->class_dev,
684 				"Endpoint has wrong direction\n");
685 			return -ENODEV;
686 		}
687 	}
688 	return 0;
689 }
690 
dt9812_reset_device(struct comedi_device * dev)691 static int dt9812_reset_device(struct comedi_device *dev)
692 {
693 	struct usb_device *usb = comedi_to_usb_dev(dev);
694 	struct dt9812_private *devpriv = dev->private;
695 	u32 serial;
696 	u16 vendor;
697 	u16 product;
698 	u8 tmp8;
699 	__le16 tmp16;
700 	__le32 tmp32;
701 	int ret;
702 	int i;
703 
704 	ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8));
705 	if (ret) {
706 		/*
707 		 * Seems like a configuration reset is necessary if driver is
708 		 * reloaded while device is attached
709 		 */
710 		usb_reset_configuration(usb);
711 		for (i = 0; i < 10; i++) {
712 			ret = dt9812_read_info(dev, 1, &tmp8, sizeof(tmp8));
713 			if (ret == 0)
714 				break;
715 		}
716 		if (ret) {
717 			dev_err(dev->class_dev,
718 				"unable to reset configuration\n");
719 			return ret;
720 		}
721 	}
722 
723 	ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16));
724 	if (ret) {
725 		dev_err(dev->class_dev, "failed to read vendor id\n");
726 		return ret;
727 	}
728 	vendor = le16_to_cpu(tmp16);
729 
730 	ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16));
731 	if (ret) {
732 		dev_err(dev->class_dev, "failed to read product id\n");
733 		return ret;
734 	}
735 	product = le16_to_cpu(tmp16);
736 
737 	ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16));
738 	if (ret) {
739 		dev_err(dev->class_dev, "failed to read device id\n");
740 		return ret;
741 	}
742 	devpriv->device = le16_to_cpu(tmp16);
743 
744 	ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32));
745 	if (ret) {
746 		dev_err(dev->class_dev, "failed to read serial number\n");
747 		return ret;
748 	}
749 	serial = le32_to_cpu(tmp32);
750 
751 	/* let the user know what node this device is now attached to */
752 	dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n",
753 		 vendor, product, devpriv->device, serial);
754 
755 	if (devpriv->device != DT9812_DEVID_DT9812_10 &&
756 	    devpriv->device != DT9812_DEVID_DT9812_2PT5) {
757 		dev_err(dev->class_dev, "Unsupported device!\n");
758 		return -EINVAL;
759 	}
760 
761 	return 0;
762 }
763 
dt9812_auto_attach(struct comedi_device * dev,unsigned long context)764 static int dt9812_auto_attach(struct comedi_device *dev,
765 			      unsigned long context)
766 {
767 	struct usb_interface *intf = comedi_to_usb_interface(dev);
768 	struct dt9812_private *devpriv;
769 	struct comedi_subdevice *s;
770 	bool is_unipolar;
771 	int ret;
772 	int i;
773 
774 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
775 	if (!devpriv)
776 		return -ENOMEM;
777 
778 	sema_init(&devpriv->sem, 1);
779 	usb_set_intfdata(intf, devpriv);
780 
781 	ret = dt9812_find_endpoints(dev);
782 	if (ret)
783 		return ret;
784 
785 	ret = dt9812_reset_device(dev);
786 	if (ret)
787 		return ret;
788 
789 	is_unipolar = (devpriv->device == DT9812_DEVID_DT9812_2PT5);
790 
791 	ret = comedi_alloc_subdevices(dev, 4);
792 	if (ret)
793 		return ret;
794 
795 	/* Digital Input subdevice */
796 	s = &dev->subdevices[0];
797 	s->type		= COMEDI_SUBD_DI;
798 	s->subdev_flags	= SDF_READABLE;
799 	s->n_chan	= 8;
800 	s->maxdata	= 1;
801 	s->range_table	= &range_digital;
802 	s->insn_bits	= dt9812_di_insn_bits;
803 
804 	/* Digital Output subdevice */
805 	s = &dev->subdevices[1];
806 	s->type		= COMEDI_SUBD_DO;
807 	s->subdev_flags	= SDF_WRITEABLE;
808 	s->n_chan	= 8;
809 	s->maxdata	= 1;
810 	s->range_table	= &range_digital;
811 	s->insn_bits	= dt9812_do_insn_bits;
812 
813 	/* Analog Input subdevice */
814 	s = &dev->subdevices[2];
815 	s->type		= COMEDI_SUBD_AI;
816 	s->subdev_flags	= SDF_READABLE | SDF_GROUND;
817 	s->n_chan	= 8;
818 	s->maxdata	= 0x0fff;
819 	s->range_table	= is_unipolar ? &range_unipolar2_5 : &range_bipolar10;
820 	s->insn_read	= dt9812_ai_insn_read;
821 
822 	/* Analog Output subdevice */
823 	s = &dev->subdevices[3];
824 	s->type		= COMEDI_SUBD_AO;
825 	s->subdev_flags	= SDF_WRITEABLE;
826 	s->n_chan	= 2;
827 	s->maxdata	= 0x0fff;
828 	s->range_table	= is_unipolar ? &range_unipolar2_5 : &range_bipolar10;
829 	s->insn_write	= dt9812_ao_insn_write;
830 	s->insn_read	= dt9812_ao_insn_read;
831 
832 	ret = comedi_alloc_subdev_readback(s);
833 	if (ret)
834 		return ret;
835 
836 	for (i = 0; i < s->n_chan; i++)
837 		s->readback[i] = is_unipolar ? 0x0000 : 0x0800;
838 
839 	return 0;
840 }
841 
dt9812_detach(struct comedi_device * dev)842 static void dt9812_detach(struct comedi_device *dev)
843 {
844 	struct usb_interface *intf = comedi_to_usb_interface(dev);
845 	struct dt9812_private *devpriv = dev->private;
846 
847 	if (!devpriv)
848 		return;
849 
850 	down(&devpriv->sem);
851 
852 	usb_set_intfdata(intf, NULL);
853 
854 	up(&devpriv->sem);
855 }
856 
857 static struct comedi_driver dt9812_driver = {
858 	.driver_name	= "dt9812",
859 	.module		= THIS_MODULE,
860 	.auto_attach	= dt9812_auto_attach,
861 	.detach		= dt9812_detach,
862 };
863 
dt9812_usb_probe(struct usb_interface * intf,const struct usb_device_id * id)864 static int dt9812_usb_probe(struct usb_interface *intf,
865 			    const struct usb_device_id *id)
866 {
867 	return comedi_usb_auto_config(intf, &dt9812_driver, id->driver_info);
868 }
869 
870 static const struct usb_device_id dt9812_usb_table[] = {
871 	{ USB_DEVICE(0x0867, 0x9812) },
872 	{ }
873 };
874 MODULE_DEVICE_TABLE(usb, dt9812_usb_table);
875 
876 static struct usb_driver dt9812_usb_driver = {
877 	.name		= "dt9812",
878 	.id_table	= dt9812_usb_table,
879 	.probe		= dt9812_usb_probe,
880 	.disconnect	= comedi_usb_auto_unconfig,
881 };
882 module_comedi_usb_driver(dt9812_driver, dt9812_usb_driver);
883 
884 MODULE_AUTHOR("Anders Blomdell <anders.blomdell@control.lth.se>");
885 MODULE_DESCRIPTION("Comedi DT9812 driver");
886 MODULE_LICENSE("GPL");
887