1 /*-
2  * Copyright (c) 2016 Landon Fuller <[email protected]>
3  * Copyright (c) 2010, Broadcom Corporation.
4  * All rights reserved.
5  *
6  * This file is derived from the siutils.c source distributed with the
7  * Asus RT-N16 firmware source code release.
8  *
9  * Permission to use, copy, modify, and/or distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
16  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  *
21  * $Id: siutils.c,v 1.821.2.48 2011-02-11 20:59:28 Exp $
22  */
23 
24 #include <sys/cdefs.h>
25 #include <sys/param.h>
26 #include <sys/kernel.h>
27 #include <sys/bus.h>
28 #include <sys/limits.h>
29 #include <sys/malloc.h>
30 #include <sys/module.h>
31 #include <sys/systm.h>
32 
33 #include <dev/bhnd/bhnd.h>
34 #include <dev/bhnd/bhndb/bhndb_pcireg.h>
35 
36 #include <dev/bhnd/cores/chipc/chipc.h>
37 #include <dev/bhnd/cores/chipc/chipcreg.h>
38 
39 #include <dev/bhnd/cores/pmu/bhnd_pmuvar.h>
40 #include <dev/bhnd/cores/pmu/bhnd_pmureg.h>
41 
42 #include "bhnd_chipc_if.h"
43 
44 #include "bhnd_pwrctl_private.h"
45 
46 static uint32_t	bhnd_pwrctl_factor6(uint32_t x);
47 
48 /**
49  * Return the factor value corresponding to a given N3M clock control magic
50  * field value (CHIPC_F6_*).
51  */
52 static uint32_t
bhnd_pwrctl_factor6(uint32_t x)53 bhnd_pwrctl_factor6(uint32_t x)
54 {
55 	switch (x) {
56 	case CHIPC_F6_2:
57 		return (2);
58 	case CHIPC_F6_3:
59 		return (3);
60 	case CHIPC_F6_4:
61 		return (4);
62 	case CHIPC_F6_5:
63 		return (5);
64 	case CHIPC_F6_6:
65 		return (6);
66 	case CHIPC_F6_7:
67 		return (7);
68 	default:
69 		return (0);
70 	}
71 }
72 
73 /**
74  * Return the backplane clock's chipc 'M' register offset for a given PLL type,
75  * or 0 if a fixed clock speed should be used.
76  *
77  * @param cid Chip identification.
78  * @param pll_type PLL type (CHIPC_PLL_TYPE*)
79  * @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
80  * speed for this device.
81  */
82 bus_size_t
bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid * cid,uint8_t pll_type,uint32_t * fixed_hz)83 bhnd_pwrctl_si_clkreg_m(const struct bhnd_chipid *cid,
84     uint8_t pll_type, uint32_t *fixed_hz)
85 {
86 	switch (pll_type) {
87 	case CHIPC_PLL_TYPE6:
88 		return (CHIPC_CLKC_M3);
89 	case CHIPC_PLL_TYPE3:
90 		return (CHIPC_CLKC_M2);
91 	default:
92 		return (CHIPC_CLKC_SB);
93 	}
94 }
95 
96 /**
97  * Calculate the backplane clock speed (in Hz) for a given a set of clock
98  * control values.
99  *
100  * @param cid Chip identification.
101  * @param pll_type PLL type (CHIPC_PLL_TYPE*)
102  * @param n clock control N register value.
103  * @param m clock control M register value.
104  */
105 uint32_t
bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid * cid,uint32_t pll_type,uint32_t n,uint32_t m)106 bhnd_pwrctl_si_clock_rate(const struct bhnd_chipid *cid,
107     uint32_t pll_type, uint32_t n, uint32_t m)
108 {
109 	uint32_t rate;
110 
111 	KASSERT(bhnd_pwrctl_si_clkreg_m(cid, pll_type, NULL) != 0,
112 	    ("can't compute clock rate on fixed clock"));
113 
114 	rate = bhnd_pwrctl_clock_rate(pll_type, n, m);
115 	if (pll_type == CHIPC_PLL_TYPE3)
116 		rate /= 2;
117 
118 	return (rate);
119 }
120 
121 /**
122  * Return the CPU clock's chipc 'M' register offset for a given PLL type,
123  * or 0 if a fixed clock speed should be used.
124  *
125  * @param cid Chip identification.
126  * @param pll_type PLL type (CHIPC_PLL_TYPE*)
127  * @param[out] fixed_hz If 0 is returned, will be set to the fixed clock
128  * speed for this device.
129  */
130 bus_size_t
bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid * cid,uint8_t pll_type,uint32_t * fixed_hz)131 bhnd_pwrctl_cpu_clkreg_m(const struct bhnd_chipid *cid,
132     uint8_t pll_type, uint32_t *fixed_hz)
133 {
134 	switch (pll_type) {
135 	case CHIPC_PLL_TYPE2:
136 	case CHIPC_PLL_TYPE4:
137 	case CHIPC_PLL_TYPE6:
138 	case CHIPC_PLL_TYPE7:
139 		return (CHIPC_CLKC_M3);
140 
141 	case CHIPC_PLL_TYPE5:
142 		/* fixed 200MHz */
143 		if (fixed_hz != NULL)
144 			*fixed_hz = 200 * 1000 * 1000;
145 		return (0);
146 
147 	case CHIPC_PLL_TYPE3:
148 		if (cid->chip_id == BHND_CHIPID_BCM5365) {
149 			/* fixed 200MHz */
150 			if (fixed_hz != NULL)
151 				*fixed_hz = 200 * 1000 * 1000;
152 			return (0);
153 		}
154 
155 		return (CHIPC_CLKC_M2);
156 
157 	default:
158 		return (CHIPC_CLKC_SB);
159 	}
160 }
161 
162 /**
163  * Calculate the CPU clock speed (in Hz) for a given a set of clock control
164  * values.
165  *
166  * @param cid Chip identification.
167  * @param pll_type PLL type (CHIPC_PLL_TYPE*)
168  * @param n clock control N register value.
169  * @param m clock control M register value.
170  */
171 uint32_t
bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid * cid,uint32_t pll_type,uint32_t n,uint32_t m)172 bhnd_pwrctl_cpu_clock_rate(const struct bhnd_chipid *cid,
173     uint32_t pll_type, uint32_t n, uint32_t m)
174 {
175 	KASSERT(bhnd_pwrctl_cpu_clkreg_m(cid, pll_type, NULL) != 0,
176 	    ("can't compute clock rate on fixed clock"));
177 
178 	return (bhnd_pwrctl_clock_rate(pll_type, n, m));
179 }
180 
181 /**
182  * Calculate the clock speed (in Hz) for a given a set of clockcontrol
183  * values.
184  *
185  * @param pll_type PLL type (CHIPC_PLL_TYPE*)
186  * @param n clock control N register value.
187  * @param m clock control M register value.
188  */
189 uint32_t
bhnd_pwrctl_clock_rate(uint32_t pll_type,uint32_t n,uint32_t m)190 bhnd_pwrctl_clock_rate(uint32_t pll_type, uint32_t n, uint32_t m)
191 {
192 	uint32_t clk_base;
193 	uint32_t n1, n2, clock, m1, m2, m3, mc;
194 
195 	n1 = CHIPC_GET_BITS(n, CHIPC_CN_N1);
196 	n2 = CHIPC_GET_BITS(n, CHIPC_CN_N2);
197 
198 	switch (pll_type) {
199 	case CHIPC_PLL_TYPE1:
200 	case CHIPC_PLL_TYPE3:
201 	case CHIPC_PLL_TYPE4:
202 	case CHIPC_PLL_TYPE7:
203 		n1 = bhnd_pwrctl_factor6(n1);
204 		n2 += CHIPC_F5_BIAS;
205 		break;
206 
207 	case CHIPC_PLL_TYPE2:
208 		n1 += CHIPC_T2_BIAS;
209 		n2 += CHIPC_T2_BIAS;
210 		KASSERT(n1 >= 2 && n1 <= 7, ("invalid n1 value"));
211 		KASSERT(n2 >= 5 && n2 <= 23, ("invalid n2 value"));
212 		break;
213 
214 	case CHIPC_PLL_TYPE5:
215 		return (100000000);
216 
217 	case CHIPC_PLL_TYPE6:
218 		if (m & CHIPC_T6_MMASK)
219 			return (CHIPC_T6_M1);
220 		else
221 			return (CHIPC_T6_M0);
222 
223 	default:
224 		printf("unsupported PLL type %u\n", pll_type);
225 		return (0);
226 	}
227 
228 	/* PLL types 3 and 7 use BASE2 (25Mhz) */
229 	if (pll_type == CHIPC_PLL_TYPE3 || pll_type == CHIPC_PLL_TYPE7) {
230 		clk_base = CHIPC_CLOCK_BASE2;
231 	} else {
232 		clk_base = CHIPC_CLOCK_BASE1;
233 	}
234 
235 	clock = clk_base * n1 * n2;
236 
237 	if (clock == 0)
238 		return (0);
239 
240 	m1 = CHIPC_GET_BITS(m, CHIPC_M1);
241 	m2 = CHIPC_GET_BITS(m, CHIPC_M2);
242 	m3 = CHIPC_GET_BITS(m, CHIPC_M3);
243 	mc = CHIPC_GET_BITS(m, CHIPC_MC);
244 
245 	switch (pll_type) {
246 	case CHIPC_PLL_TYPE1:
247 	case CHIPC_PLL_TYPE3:
248 	case CHIPC_PLL_TYPE4:
249 	case CHIPC_PLL_TYPE7:
250 		m1 = bhnd_pwrctl_factor6(m1);
251 		if (pll_type == CHIPC_PLL_TYPE1 || pll_type == CHIPC_PLL_TYPE3)
252 			m2 += CHIPC_F5_BIAS;
253 		else
254 			m2 = bhnd_pwrctl_factor6(m2);
255 
256 		m3 = bhnd_pwrctl_factor6(m3);
257 
258 		switch (mc) {
259 		case CHIPC_MC_BYPASS:
260 			return (clock);
261 		case CHIPC_MC_M1:
262 			return (clock / m1);
263 		case CHIPC_MC_M1M2:
264 			return (clock / (m1 * m2));
265 		case CHIPC_MC_M1M2M3:
266 			return (clock / (m1 * m2 * m3));
267 		case CHIPC_MC_M1M3:
268 			return (clock / (m1 * m3));
269 		default:
270 			printf("unsupported pwrctl mc %#x\n", mc);
271 			return (0);
272 		}
273 	case CHIPC_PLL_TYPE2:
274 		m1 += CHIPC_T2_BIAS;
275 		m2 += CHIPC_T2M2_BIAS;
276 		m3 += CHIPC_T2_BIAS;
277 		KASSERT(m1 >= 2 && m1 <= 7, ("invalid m1 value"));
278 		KASSERT(m2 >= 3 && m2 <= 10, ("invalid m2 value"));
279 		KASSERT(m3 >= 2 && m3 <= 7, ("invalid m3 value"));
280 
281 		if ((mc & CHIPC_T2MC_M1BYP) == 0)
282 			clock /= m1;
283 		if ((mc & CHIPC_T2MC_M2BYP) == 0)
284 			clock /= m2;
285 		if ((mc & CHIPC_T2MC_M3BYP) == 0)
286 			clock /= m3;
287 
288 		return (clock);
289 	default:
290 		panic("unhandled PLL type %u\n", pll_type);
291 	}
292 }
293 
294 /**
295  * Return the backplane clock speed in Hz.
296  *
297  * @param sc driver instance state.
298  */
299 uint32_t
bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc * sc)300 bhnd_pwrctl_getclk_speed(struct bhnd_pwrctl_softc *sc)
301 {
302 	const struct bhnd_chipid	*cid;
303 	struct chipc_caps		*ccaps;
304 	bus_size_t			 creg;
305 	uint32_t 			 n, m;
306 	uint32_t 			 rate;
307 
308 	PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
309 
310 	cid = bhnd_get_chipid(sc->chipc_dev);
311 	ccaps = BHND_CHIPC_GET_CAPS(sc->chipc_dev);
312 
313 	n = bhnd_bus_read_4(sc->res, CHIPC_CLKC_N);
314 
315 	/* Get M register offset */
316 	creg = bhnd_pwrctl_si_clkreg_m(cid, ccaps->pll_type, &rate);
317 	if (creg == 0) /* fixed rate */
318 		return (rate);
319 
320 	/* calculate rate */
321 	m = bhnd_bus_read_4(sc->res, creg);
322 	return (bhnd_pwrctl_si_clock_rate(cid, ccaps->pll_type, n, m));
323 }
324 
325 /* return the slow clock source */
326 static bhnd_clksrc
bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc * sc)327 bhnd_pwrctl_slowclk_src(struct bhnd_pwrctl_softc *sc)
328 {
329 	uint32_t clkreg;
330 	uint32_t clksrc;
331 
332 	/* Fetch clock source */
333 	if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
334 		return (bhnd_pwrctl_hostb_get_clksrc(sc->chipc_dev,
335 		    BHND_CLOCK_ILP));
336 	} else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
337 		clkreg = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
338 		clksrc = clkreg & CHIPC_SCC_SS_MASK;
339 	} else {
340 		/* Instaclock */
341 		clksrc = CHIPC_SCC_SS_XTAL;
342 	}
343 
344 	/* Map to bhnd_clksrc */
345 	switch (clksrc) {
346 	case CHIPC_SCC_SS_PCI:
347 		return (BHND_CLKSRC_PCI);
348 	case CHIPC_SCC_SS_LPO:
349 		return (BHND_CLKSRC_LPO);
350 	case CHIPC_SCC_SS_XTAL:
351 		return (BHND_CLKSRC_XTAL);
352 	default:
353 		return (BHND_CLKSRC_UNKNOWN);
354 	}
355 }
356 
357 /* return the ILP (slowclock) min or max frequency */
358 static uint32_t
bhnd_pwrctl_slowclk_freq(struct bhnd_pwrctl_softc * sc,bool max_freq)359 bhnd_pwrctl_slowclk_freq(struct bhnd_pwrctl_softc *sc, bool max_freq)
360 {
361 	bhnd_clksrc	slowclk;
362 	uint32_t	div;
363 	uint32_t	hz;
364 
365 	slowclk = bhnd_pwrctl_slowclk_src(sc);
366 
367 	/* Determine clock divisor */
368 	if (PWRCTL_QUIRK(sc, PCICLK_CTL)) {
369 		if (slowclk == BHND_CLKSRC_PCI)
370 			div = 64;
371 		else
372 			div = 32;
373 	} else if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
374 		div = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
375 		div = CHIPC_GET_BITS(div, CHIPC_SCC_CD);
376 		div = 4 * (div + 1);
377 	} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
378 		if (max_freq) {
379 			div = 1;
380 		} else {
381 			div = bhnd_bus_read_4(sc->res, CHIPC_SYS_CLK_CTL);
382 			div = CHIPC_GET_BITS(div, CHIPC_SYCC_CD);
383 			div = 4 * (div + 1);
384 		}
385 	} else {
386 		device_printf(sc->dev, "unknown device type\n");
387 		return (0);
388 	}
389 
390 	/* Determine clock frequency */
391 	switch (slowclk) {
392 	case BHND_CLKSRC_LPO:
393 		hz = max_freq ? CHIPC_LPOMAXFREQ : CHIPC_LPOMINFREQ;
394 		break;
395 	case BHND_CLKSRC_XTAL:
396 		hz = max_freq ? CHIPC_XTALMAXFREQ : CHIPC_XTALMINFREQ;
397 		break;
398 	case BHND_CLKSRC_PCI:
399 		hz = max_freq ? CHIPC_PCIMAXFREQ : CHIPC_PCIMINFREQ;
400 		break;
401 	default:
402 		device_printf(sc->dev, "unknown slowclk source %#x\n", slowclk);
403 		return (0);
404 	}
405 
406 	return (hz / div);
407 }
408 
409 /**
410  * Initialize power control registers.
411  */
412 int
bhnd_pwrctl_init(struct bhnd_pwrctl_softc * sc)413 bhnd_pwrctl_init(struct bhnd_pwrctl_softc *sc)
414 {
415 	uint32_t	clkctl;
416 	uint32_t	pll_delay, slowclk, slowmaxfreq;
417 	uint32_t 	pll_on_delay, fref_sel_delay;
418 	int		error;
419 
420 	pll_delay = CHIPC_PLL_DELAY;
421 
422 	/* set all Instaclk chip ILP to 1 MHz */
423 	if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
424 		clkctl = (CHIPC_ILP_DIV_1MHZ << CHIPC_SYCC_CD_SHIFT);
425 		clkctl &= CHIPC_SYCC_CD_MASK;
426 		bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, clkctl);
427 	}
428 
429 	/*
430 	 * Initialize PLL/FREF delays.
431 	 *
432 	 * If the slow clock is not sourced by the xtal, include the
433 	 * delay required to bring it up.
434 	 */
435 	slowclk = bhnd_pwrctl_slowclk_src(sc);
436 	if (slowclk != CHIPC_SCC_SS_XTAL)
437 		pll_delay += CHIPC_XTAL_ON_DELAY;
438 
439 	/* Starting with 4318 it is ILP that is used for the delays */
440 	if (PWRCTL_QUIRK(sc, INSTACLK_CTL))
441 		slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, false);
442 	else
443 		slowmaxfreq = bhnd_pwrctl_slowclk_freq(sc, true);
444 
445 	pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
446 	fref_sel_delay = ((slowmaxfreq * CHIPC_FREF_DELAY) + 999999) / 1000000;
447 
448 	bhnd_bus_write_4(sc->res, CHIPC_PLL_ON_DELAY, pll_on_delay);
449 	bhnd_bus_write_4(sc->res, CHIPC_PLL_FREFSEL_DELAY, fref_sel_delay);
450 
451 	/* If required, force HT */
452 	if (PWRCTL_QUIRK(sc, FORCE_HT)) {
453 		if ((error = bhnd_pwrctl_setclk(sc, BHND_CLOCK_HT)))
454 			return (error);
455 	}
456 
457 	return (0);
458 }
459 
460 /* return the value suitable for writing to the dot11 core
461  * FAST_PWRUP_DELAY register */
462 u_int
bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc * sc)463 bhnd_pwrctl_fast_pwrup_delay(struct bhnd_pwrctl_softc *sc)
464 {
465 	u_int pll_on_delay, slowminfreq;
466 	u_int fpdelay;
467 
468 	fpdelay = 0;
469 
470 	slowminfreq = bhnd_pwrctl_slowclk_freq(sc, false);
471 
472 	pll_on_delay = bhnd_bus_read_4(sc->res, CHIPC_PLL_ON_DELAY) + 2;
473 	pll_on_delay *= 1000000;
474 	pll_on_delay += (slowminfreq - 1);
475 	fpdelay = pll_on_delay / slowminfreq;
476 
477 	return (fpdelay);
478 }
479 
480 /**
481  * Distribute @p clock on backplane.
482  *
483  * @param sc Driver instance state.
484  * @param clock Clock to enable.
485  *
486  * @retval 0 success
487  * @retval ENODEV If @p clock is unsupported, or if the device does not
488  * 		  support dynamic clock control.
489  */
490 int
bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc * sc,bhnd_clock clock)491 bhnd_pwrctl_setclk(struct bhnd_pwrctl_softc *sc, bhnd_clock clock)
492 {
493 	uint32_t	scc;
494 
495 	PWRCTL_LOCK_ASSERT(sc, MA_OWNED);
496 
497 	/* Is dynamic clock control supported? */
498 	if (PWRCTL_QUIRK(sc, FIXED_CLK))
499 		return (ENODEV);
500 
501 	/* Chips with ccrev 10 are EOL and they don't have SYCC_HR used below */
502 	if (bhnd_get_hwrev(sc->chipc_dev) == 10)
503 		return (ENODEV);
504 
505 	if (PWRCTL_QUIRK(sc, SLOWCLK_CTL))
506 		scc = bhnd_bus_read_4(sc->res, CHIPC_PLL_SLOWCLK_CTL);
507 	else
508 		scc = bhnd_bus_read_4(sc->res, CHIPC_SYS_CLK_CTL);
509 
510 	switch (clock) {
511 	case BHND_CLOCK_HT:
512 		/* fast (pll) clock */
513 		if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
514 			scc &= ~(CHIPC_SCC_XC | CHIPC_SCC_FS | CHIPC_SCC_IP);
515 			scc |= CHIPC_SCC_IP;
516 
517 			/* force xtal back on before clearing SCC_DYN_XTAL.. */
518 			bhnd_pwrctl_hostb_ungate_clock(sc->chipc_dev,
519 			    BHND_CLOCK_HT);
520 		} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
521 			scc |= CHIPC_SYCC_HR;
522 		} else {
523 			return (ENODEV);
524 		}
525 
526 		if (PWRCTL_QUIRK(sc, SLOWCLK_CTL))
527 			bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
528 		else
529 			bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc);
530 		DELAY(CHIPC_PLL_DELAY);
531 
532 		break;
533 
534 	case BHND_CLOCK_DYN:
535 		/* enable dynamic clock control */
536 		if (PWRCTL_QUIRK(sc, SLOWCLK_CTL)) {
537 			scc &= ~(CHIPC_SCC_FS | CHIPC_SCC_IP | CHIPC_SCC_XC);
538 			if ((scc & CHIPC_SCC_SS_MASK) != CHIPC_SCC_SS_XTAL)
539 				scc |= CHIPC_SCC_XC;
540 
541 			bhnd_bus_write_4(sc->res, CHIPC_PLL_SLOWCLK_CTL, scc);
542 
543 			/* for dynamic control, we have to release our xtal_pu
544 			 * "force on" */
545 			if (scc & CHIPC_SCC_XC) {
546 				bhnd_pwrctl_hostb_gate_clock(sc->chipc_dev,
547 				    BHND_CLOCK_HT);
548 			}
549 		} else if (PWRCTL_QUIRK(sc, INSTACLK_CTL)) {
550 			/* Instaclock */
551 			scc &= ~CHIPC_SYCC_HR;
552 			bhnd_bus_write_4(sc->res, CHIPC_SYS_CLK_CTL, scc);
553 		} else {
554 			return (ENODEV);
555 		}
556 
557 		break;
558 
559 	default:
560 		return (ENODEV);
561 	}
562 
563 	return (0);
564 }
565