1 /*
2     comedi/drivers/mpc8260.c
3     driver for digital I/O pins on the MPC 8260 CPM module
4 
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 2000,2001 David A. Schleef <ds@schleef.org>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22 */
23 /*
24 Driver: mpc8260cpm
25 Description: MPC8260 CPM module generic digital I/O lines
26 Devices: [Motorola] MPC8260 CPM (mpc8260cpm)
27 Author: ds
28 Status: experimental
29 Updated: Sat, 16 Mar 2002 17:34:48 -0800
30 
31 This driver is specific to the Motorola MPC8260 processor, allowing
32 you to access the processor's generic digital I/O lines.
33 
34 It is apparently missing some code.
35 */
36 
37 #include "../comedidev.h"
38 
39 extern unsigned long mpc8260_dio_reserved[4];
40 
41 struct mpc8260cpm_private {
42 
43 	int data;
44 
45 };
46 
47 #define devpriv ((struct mpc8260cpm_private *)dev->private)
48 
49 static int mpc8260cpm_attach(struct comedi_device *dev,
50 			     struct comedi_devconfig *it);
51 static int mpc8260cpm_detach(struct comedi_device *dev);
52 static struct comedi_driver driver_mpc8260cpm = {
53 	.driver_name = "mpc8260cpm",
54 	.module = THIS_MODULE,
55 	.attach = mpc8260cpm_attach,
56 	.detach = mpc8260cpm_detach,
57 };
58 
driver_mpc8260cpm_init_module(void)59 static int __init driver_mpc8260cpm_init_module(void)
60 {
61 	return comedi_driver_register(&driver_mpc8260cpm);
62 }
63 
driver_mpc8260cpm_cleanup_module(void)64 static void __exit driver_mpc8260cpm_cleanup_module(void)
65 {
66 	comedi_driver_unregister(&driver_mpc8260cpm);
67 }
68 
69 module_init(driver_mpc8260cpm_init_module);
70 module_exit(driver_mpc8260cpm_cleanup_module);
71 
72 static int mpc8260cpm_dio_config(struct comedi_device *dev,
73 				 struct comedi_subdevice *s,
74 				 struct comedi_insn *insn, unsigned int *data);
75 static int mpc8260cpm_dio_bits(struct comedi_device *dev,
76 			       struct comedi_subdevice *s,
77 			       struct comedi_insn *insn, unsigned int *data);
78 
mpc8260cpm_attach(struct comedi_device * dev,struct comedi_devconfig * it)79 static int mpc8260cpm_attach(struct comedi_device *dev,
80 			     struct comedi_devconfig *it)
81 {
82 	struct comedi_subdevice *s;
83 	int i;
84 
85 	printk("comedi%d: mpc8260cpm: ", dev->minor);
86 
87 	dev->board_ptr = mpc8260cpm_boards + dev->board;
88 
89 	dev->board_name = thisboard->name;
90 
91 	if (alloc_private(dev, sizeof(struct mpc8260cpm_private)) < 0)
92 		return -ENOMEM;
93 
94 	if (alloc_subdevices(dev, 4) < 0)
95 		return -ENOMEM;
96 
97 	for (i = 0; i < 4; i++) {
98 		s = dev->subdevices + i;
99 		s->type = COMEDI_SUBD_DIO;
100 		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
101 		s->n_chan = 32;
102 		s->maxdata = 1;
103 		s->range_table = &range_digital;
104 		s->insn_config = mpc8260cpm_dio_config;
105 		s->insn_bits = mpc8260cpm_dio_bits;
106 	}
107 
108 	return 1;
109 }
110 
mpc8260cpm_detach(struct comedi_device * dev)111 static int mpc8260cpm_detach(struct comedi_device *dev)
112 {
113 	printk("comedi%d: mpc8260cpm: remove\n", dev->minor);
114 
115 	return 0;
116 }
117 
cpm_pdat(int port)118 static unsigned long *cpm_pdat(int port)
119 {
120 	switch (port) {
121 	case 0:
122 		return &io->iop_pdata;
123 	case 1:
124 		return &io->iop_pdatb;
125 	case 2:
126 		return &io->iop_pdatc;
127 	case 3:
128 		return &io->iop_pdatd;
129 	}
130 }
131 
mpc8260cpm_dio_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)132 static int mpc8260cpm_dio_config(struct comedi_device *dev,
133 				 struct comedi_subdevice *s,
134 				 struct comedi_insn *insn, unsigned int *data)
135 {
136 	int n;
137 	unsigned int d;
138 	unsigned int mask;
139 	int port;
140 
141 	port = (int)s->private;
142 	mask = 1 << CR_CHAN(insn->chanspec);
143 	if (mask & cpm_reserved_bits[port]) {
144 		return -EINVAL;
145 	}
146 
147 	switch (data[0]) {
148 	case INSN_CONFIG_DIO_OUTPUT:
149 		s->io_bits |= mask;
150 		break;
151 	case INSN_CONFIG_DIO_INPUT:
152 		s->io_bits &= ~mask;
153 		break;
154 	case INSN_CONFIG_DIO_QUERY:
155 		data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
156 		return insn->n;
157 		break;
158 	default:
159 		return -EINVAL;
160 	}
161 
162 	switch (port) {
163 	case 0:
164 		return &io->iop_pdira;
165 	case 1:
166 		return &io->iop_pdirb;
167 	case 2:
168 		return &io->iop_pdirc;
169 	case 3:
170 		return &io->iop_pdird;
171 	}
172 
173 	return 1;
174 }
175 
mpc8260cpm_dio_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)176 static int mpc8260cpm_dio_bits(struct comedi_device *dev,
177 			       struct comedi_subdevice *s,
178 			       struct comedi_insn *insn, unsigned int *data)
179 {
180 	int port;
181 	unsigned long *p;
182 
183 	p = cpm_pdat((int)s->private);
184 
185 	return 2;
186 }
187