xref: /illumos-gate/usr/src/uts/sun4u/io/i2c/clients/pic16f819.c (revision ddb365bfc9e868ad24ccdcb0dc91af18b10df082)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include <sys/stat.h>		/* ddi_create_minor_node S_IFCHR */
27 #include <sys/modctl.h>		/* for modldrv */
28 #include <sys/open.h>		/* for open params.	 */
29 #include <sys/types.h>
30 #include <sys/kmem.h>
31 #include <sys/sunddi.h>
32 #include <sys/conf.h>		/* req. by dev_ops flags MTSAFE etc. */
33 #include <sys/ddi.h>
34 #include <sys/file.h>
35 #include <sys/note.h>
36 
37 #include <sys/i2c/clients/pic16f819_impl.h>
38 
39 static void *pic16f819soft_statep;
40 
41 static int pic16f819_set(struct pic16f819_unit *, int, uchar_t);
42 static int pic16f819_get(struct pic16f819_unit *, int, uchar_t *, int);
43 
44 
45 static int pic16f819_do_attach(dev_info_t *);
46 static int pic16f819_do_detach(dev_info_t *);
47 static int pic16f819_do_resume(void);
48 static int pic16f819_do_suspend(void);
49 
50 /*
51  * cb ops (only need ioctl)
52  */
53 static int pic16f819_open(dev_t *, int, int, cred_t *);
54 static int pic16f819_close(dev_t, int, int, cred_t *);
55 static int pic16f819_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
56 
57 static struct cb_ops pic16f819_cbops = {
58 	pic16f819_open,			/* open  */
59 	pic16f819_close,			/* close */
60 	nodev,				/* strategy */
61 	nodev,				/* print */
62 	nodev,				/* dump */
63 	nodev,				/* read */
64 	nodev,				/* write */
65 	pic16f819_ioctl,			/* ioctl */
66 	nodev,				/* devmap */
67 	nodev,				/* mmap */
68 	nodev,				/* segmap */
69 	nochpoll,			/* poll */
70 	ddi_prop_op,			/* cb_prop_op */
71 	NULL,				/* streamtab */
72 	D_NEW | D_MP | D_HOTPLUG,	/* Driver compatibility flag */
73 	CB_REV,				/* rev */
74 	nodev,				/* int (*cb_aread)() */
75 	nodev				/* int (*cb_awrite)() */
76 };
77 
78 /*
79  * dev ops
80  */
81 static int pic16f819_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
82 static int pic16f819_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
83 
84 static struct dev_ops pic16f819_ops = {
85 	DEVO_REV,
86 	0,
87 	ddi_no_info,
88 	nulldev,
89 	nulldev,
90 	pic16f819_attach,
91 	pic16f819_detach,
92 	nodev,
93 	&pic16f819_cbops,
94 	NULL,			/* bus ops */
95 	NULL,			/* power */
96 	ddi_quiesce_not_needed,		/* quiesce */
97 };
98 
99 extern struct mod_ops mod_driverops;
100 
101 static struct modldrv pic16f819_modldrv = {
102 	&mod_driverops,			/* type of module - driver */
103 	"PIC16F819 i2c device driver",
104 	&pic16f819_ops
105 };
106 
107 static struct modlinkage pic16f819_modlinkage = {
108 	MODREV_1,
109 	&pic16f819_modldrv,
110 	0
111 };
112 
113 
114 int
115 _init(void)
116 {
117 	int error;
118 
119 	error = mod_install(&pic16f819_modlinkage);
120 
121 	if (!error)
122 		(void) ddi_soft_state_init(&pic16f819soft_statep,
123 		    sizeof (struct pic16f819_unit), 1);
124 	return (error);
125 }
126 
127 int
128 _fini(void)
129 {
130 	int error;
131 
132 	error = mod_remove(&pic16f819_modlinkage);
133 	if (!error)
134 		ddi_soft_state_fini(&pic16f819soft_statep);
135 
136 	return (error);
137 }
138 
139 int
140 _info(struct modinfo *modinfop)
141 {
142 	return (mod_info(&pic16f819_modlinkage, modinfop));
143 }
144 
145 static int
146 pic16f819_get(struct pic16f819_unit *unitp, int reg, uchar_t *byte, int flags)
147 {
148 	i2c_transfer_t		*i2c_tran_pointer;
149 	int			err;
150 
151 	(void) i2c_transfer_alloc(unitp->pic16f819_hdl, &i2c_tran_pointer,
152 	    1, 1, flags);
153 	if (i2c_tran_pointer == NULL) {
154 		return (ENOMEM);
155 	}
156 
157 	i2c_tran_pointer->i2c_flags = I2C_WR_RD;
158 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
159 	err = i2c_transfer(unitp->pic16f819_hdl, i2c_tran_pointer);
160 	if (err) {
161 		D2CMN_ERR((CE_WARN, "%s: pic16f819_get failed reg=%x",
162 		    unitp->pic16f819_name, reg));
163 	} else {
164 		*byte = i2c_tran_pointer->i2c_rbuf[0];
165 	}
166 
167 	i2c_transfer_free(unitp->pic16f819_hdl, i2c_tran_pointer);
168 	return (err);
169 }
170 
171 static int
172 pic16f819_set(struct pic16f819_unit *unitp, int reg, uchar_t byte)
173 {
174 	i2c_transfer_t		*i2c_tran_pointer;
175 	int			err;
176 
177 	(void) i2c_transfer_alloc(unitp->pic16f819_hdl, &i2c_tran_pointer,
178 	    2, 0, I2C_SLEEP);
179 	if (i2c_tran_pointer == NULL) {
180 		D2CMN_ERR((CE_WARN, "%s: Failed in pic16f819_set "
181 		"i2c_tran_pointer not allocated", unitp->pic16f819_name));
182 		return (ENOMEM);
183 	}
184 
185 	i2c_tran_pointer->i2c_flags = I2C_WR;
186 	i2c_tran_pointer->i2c_wbuf[0] = (uchar_t)reg;
187 	i2c_tran_pointer->i2c_wbuf[1] = byte;
188 	D1CMN_ERR((CE_NOTE, "%s: set reg %x to %x",
189 	    unitp->pic16f819_name, reg, byte));
190 
191 	err = i2c_transfer(unitp->pic16f819_hdl, i2c_tran_pointer);
192 	if (err) {
193 		D2CMN_ERR((CE_WARN, "%s: Failed in the pic16f819_set"
194 		    " i2c_transfer routine", unitp->pic16f819_name));
195 	}
196 	i2c_transfer_free(unitp->pic16f819_hdl, i2c_tran_pointer);
197 	return (err);
198 }
199 
200 static int
201 pic16f819_open(dev_t *devp, int flags, int otyp, cred_t *credp)
202 {
203 	_NOTE(ARGUNUSED(credp))
204 
205 	struct pic16f819_unit *unitp;
206 	int instance;
207 	int error = 0;
208 
209 	instance = getminor(*devp);
210 
211 	if (instance < 0) {
212 		return (ENXIO);
213 	}
214 
215 	unitp = (struct pic16f819_unit *)
216 	    ddi_get_soft_state(pic16f819soft_statep, instance);
217 
218 	if (unitp == NULL) {
219 		return (ENXIO);
220 	}
221 
222 	if (otyp != OTYP_CHR) {
223 		return (EINVAL);
224 	}
225 
226 	mutex_enter(&unitp->pic16f819_mutex);
227 
228 	if (flags & FEXCL) {
229 		if (unitp->pic16f819_oflag != 0) {
230 			error = EBUSY;
231 		} else {
232 			unitp->pic16f819_oflag = FEXCL;
233 		}
234 	} else {
235 		if (unitp->pic16f819_oflag == FEXCL) {
236 			error = EBUSY;
237 		} else {
238 			unitp->pic16f819_oflag = FOPEN;
239 		}
240 	}
241 
242 	mutex_exit(&unitp->pic16f819_mutex);
243 
244 	return (error);
245 }
246 
247 static int
248 pic16f819_close(dev_t dev, int flags, int otyp, cred_t *credp)
249 {
250 	_NOTE(ARGUNUSED(flags, otyp, credp))
251 
252 	struct pic16f819_unit *unitp;
253 	int instance;
254 
255 	instance = getminor(dev);
256 
257 	if (instance < 0) {
258 		return (ENXIO);
259 	}
260 
261 	unitp = (struct pic16f819_unit *)
262 	    ddi_get_soft_state(pic16f819soft_statep, instance);
263 
264 	if (unitp == NULL) {
265 		return (ENXIO);
266 	}
267 
268 	mutex_enter(&unitp->pic16f819_mutex);
269 
270 	unitp->pic16f819_oflag = 0;
271 
272 	mutex_exit(&unitp->pic16f819_mutex);
273 	return (DDI_SUCCESS);
274 }
275 
276 static int
277 pic16f819_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
278     cred_t *credp, int *rvalp)
279 {
280 	_NOTE(ARGUNUSED(credp, rvalp))
281 
282 	struct pic16f819_unit	*unitp;
283 	int		instance;
284 	int			err = 0;
285 	i2c_reg_t		ioctl_reg;
286 	uchar_t			val8;
287 
288 	if (arg == (intptr_t)NULL) {
289 		D2CMN_ERR((CE_WARN, "PIC16F819: ioctl: arg passed in to ioctl "
290 		    "= NULL\n"));
291 		err = EINVAL;
292 		return (err);
293 	}
294 	instance = getminor(dev);
295 	unitp = (struct pic16f819_unit *)
296 	    ddi_get_soft_state(pic16f819soft_statep, instance);
297 
298 	mutex_enter(&unitp->pic16f819_mutex);
299 
300 	switch (cmd) {
301 
302 	case I2C_GET_REG:
303 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
304 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
305 			err = EFAULT;
306 			break;
307 		}
308 		err = pic16f819_get(unitp, ioctl_reg.reg_num, &val8,
309 		    I2C_SLEEP);
310 		if (err != I2C_SUCCESS) {
311 			break;
312 		}
313 
314 		ioctl_reg.reg_value = val8;
315 		if (ddi_copyout((caddr_t)&ioctl_reg, (caddr_t)arg,
316 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
317 			err = EFAULT;
318 		}
319 		break;
320 
321 	case I2C_SET_REG:
322 		if (ddi_copyin((caddr_t)arg, (caddr_t)&ioctl_reg,
323 		    sizeof (i2c_reg_t), mode) != DDI_SUCCESS) {
324 			err = EFAULT;
325 			break;
326 		}
327 		err = pic16f819_set(unitp, ioctl_reg.reg_num,
328 		    ioctl_reg.reg_value);
329 		break;
330 	default:
331 		D2CMN_ERR((CE_WARN, "%s: Invalid IOCTL cmd: %x\n",
332 		    unitp->pic16f819_name, cmd));
333 		err = EINVAL;
334 	}
335 
336 	mutex_exit(&unitp->pic16f819_mutex);
337 	return (err);
338 }
339 
340 static int
341 pic16f819_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
342 {
343 	switch (cmd) {
344 	case DDI_ATTACH:
345 		return (pic16f819_do_attach(dip));
346 	case DDI_RESUME:
347 		return (pic16f819_do_resume());
348 	default:
349 		return (DDI_FAILURE);
350 	}
351 }
352 
353 static int
354 pic16f819_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
355 {
356 	switch (cmd) {
357 	case DDI_DETACH:
358 		return (pic16f819_do_detach(dip));
359 	case DDI_SUSPEND:
360 		return (pic16f819_do_suspend());
361 	default:
362 		return (DDI_FAILURE);
363 	}
364 }
365 
366 static int
367 pic16f819_do_attach(dev_info_t *dip)
368 {
369 	struct pic16f819_unit *unitp;
370 	int instance;
371 
372 	instance = ddi_get_instance(dip);
373 
374 	if (ddi_soft_state_zalloc(pic16f819soft_statep, instance) != 0) {
375 		cmn_err(CE_WARN, "%s%d: failed to zalloc softstate\n",
376 		    ddi_get_name(dip), instance);
377 		return (DDI_FAILURE);
378 	}
379 
380 	unitp = ddi_get_soft_state(pic16f819soft_statep, instance);
381 
382 	if (unitp == NULL) {
383 		cmn_err(CE_WARN, "%s%d: unitp not filled\n",
384 		    ddi_get_name(dip), instance);
385 		return (ENOMEM);
386 	}
387 
388 	(void) snprintf(unitp->pic16f819_name, sizeof (unitp->pic16f819_name),
389 	    "%s%d", ddi_node_name(dip), instance);
390 
391 	if (ddi_create_minor_node(dip, "fan_1", S_IFCHR, instance,
392 	    "ddi_i2c:pic", 0) == DDI_FAILURE) {
393 		cmn_err(CE_WARN, "%s ddi_create_minor_node failed for "
394 		    "%s\n", unitp->pic16f819_name, "pic16f819");
395 		ddi_soft_state_free(pic16f819soft_statep, instance);
396 
397 		return (DDI_FAILURE);
398 	}
399 
400 	if (i2c_client_register(dip, &unitp->pic16f819_hdl) != I2C_SUCCESS) {
401 		cmn_err(CE_WARN, "%s i2c_client_register failed\n",
402 		    unitp->pic16f819_name);
403 		ddi_remove_minor_node(dip, NULL);
404 		ddi_soft_state_free(pic16f819soft_statep, instance);
405 
406 		return (DDI_FAILURE);
407 	}
408 
409 	mutex_init(&unitp->pic16f819_mutex, NULL, MUTEX_DRIVER, NULL);
410 
411 	return (DDI_SUCCESS);
412 }
413 
414 static int
415 pic16f819_do_resume()
416 {
417 	int ret = DDI_SUCCESS;
418 
419 	return (ret);
420 }
421 
422 static int
423 pic16f819_do_suspend()
424 {
425 	int ret = DDI_SUCCESS;
426 
427 	return (ret);
428 }
429 
430 static int
431 pic16f819_do_detach(dev_info_t *dip)
432 {
433 	struct pic16f819_unit *unitp;
434 	int instance;
435 
436 	instance = ddi_get_instance(dip);
437 
438 	unitp = ddi_get_soft_state(pic16f819soft_statep, instance);
439 
440 	if (unitp == NULL) {
441 		cmn_err(CE_WARN, "%s%d: unitp not filled\n",
442 		    ddi_get_name(dip), instance);
443 		return (ENOMEM);
444 	}
445 
446 	i2c_client_unregister(unitp->pic16f819_hdl);
447 
448 	ddi_remove_minor_node(dip, NULL);
449 
450 	mutex_destroy(&unitp->pic16f819_mutex);
451 
452 	ddi_soft_state_free(pic16f819soft_statep, instance);
453 
454 	return (DDI_SUCCESS);
455 }
456