xref: /freebsd/sys/arm/ti/twl/twl_clks.c (revision d2ce15bd43b3a1dcce08eecbff8d5d359946d972)
1 /*-
2  * Copyright (c) 2012
3  *	Ben Gray <bgray@freebsd.org>.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 /*
32  * Texas Instruments TWL4030/TWL5030/TWL60x0/TPS659x0 Power Management.
33  *
34  * This driver covers the external clocks, allows for enabling &
35  * disabling their output.
36  *
37  *
38  *
39  * FLATTENED DEVICE TREE (FDT)
40  * Startup override settings can be specified in the FDT, if they are they
41  * should be under the twl parent device and take the following form:
42  *
43  *    external-clocks = "name1", "state1",
44  *                      "name2", "state2",
45  *                      etc;
46  *
47  * Each override should be a pair, the first entry is the name of the clock
48  * the second is the state to set, possible strings are either "on" or "off".
49  *
50  */
51 
52 #include <sys/param.h>
53 #include <sys/systm.h>
54 #include <sys/kernel.h>
55 #include <sys/lock.h>
56 #include <sys/module.h>
57 #include <sys/bus.h>
58 #include <sys/resource.h>
59 #include <sys/rman.h>
60 #include <sys/sysctl.h>
61 #include <sys/sx.h>
62 #include <sys/malloc.h>
63 
64 #include <machine/bus.h>
65 #include <machine/cpu.h>
66 #include <machine/cpufunc.h>
67 #include <machine/frame.h>
68 #include <machine/resource.h>
69 #include <machine/intr.h>
70 
71 #include <dev/ofw/openfirm.h>
72 #include <dev/ofw/ofw_bus.h>
73 
74 #include "twl.h"
75 #include "twl_clks.h"
76 
77 
78 static int twl_clks_debug = 1;
79 
80 
81 /*
82  * Power Groups bits for the 4030 and 6030 devices
83  */
84 #define TWL4030_P3_GRP		0x80	/* Peripherals, power group */
85 #define TWL4030_P2_GRP		0x40	/* Modem power group */
86 #define TWL4030_P1_GRP		0x20	/* Application power group (FreeBSD control) */
87 
88 #define TWL6030_P3_GRP		0x04	/* Modem power group */
89 #define TWL6030_P2_GRP		0x02	/* Connectivity power group */
90 #define TWL6030_P1_GRP		0x01	/* Application power group (FreeBSD control) */
91 
92 /*
93  * Register offsets within a clk regulator register set
94  */
95 #define TWL_CLKS_GRP		0x00	/* Regulator GRP register */
96 #define TWL_CLKS_STATE		0x02	/* TWL6030 only */
97 
98 
99 
100 /**
101  *  Support voltage regulators for the different IC's
102  */
103 struct twl_clock {
104 	const char	*name;
105 	uint8_t		subdev;
106 	uint8_t		regbase;
107 };
108 
109 static const struct twl_clock twl4030_clocks[] = {
110 	{ "32kclkout", 0, 0x8e },
111 	{ NULL, 0, 0x00 }
112 };
113 
114 static const struct twl_clock twl6030_clocks[] = {
115 	{ "clk32kg",     0, 0xbc },
116 	{ "clk32kao",    0, 0xb9 },
117 	{ "clk32kaudio", 0, 0xbf },
118 	{ NULL, 0, 0x00 }
119 };
120 
121 #define TWL_CLKS_MAX_NAMELEN  32
122 
123 struct twl_clk_entry {
124 	LIST_ENTRY(twl_clk_entry) link;
125 	struct sysctl_oid *oid;
126 	char		       name[TWL_CLKS_MAX_NAMELEN];
127 	uint8_t            sub_dev;  /* the sub-device number for the clock */
128 	uint8_t            reg_off;  /* register base address of the clock */
129 };
130 
131 struct twl_clks_softc {
132 	device_t           sc_dev;   /* twl_clk device */
133 	device_t           sc_pdev;  /* parent device (twl) */
134 	struct sx          sc_sx;    /* internal locking */
135 	struct intr_config_hook sc_init_hook;
136 	LIST_HEAD(twl_clk_list, twl_clk_entry) sc_clks_list;
137 };
138 
139 /**
140  *	Macros for driver shared locking
141  */
142 #define TWL_CLKS_XLOCK(_sc)			sx_xlock(&(_sc)->sc_sx)
143 #define	TWL_CLKS_XUNLOCK(_sc)		sx_xunlock(&(_sc)->sc_sx)
144 #define TWL_CLKS_SLOCK(_sc)			sx_slock(&(_sc)->sc_sx)
145 #define	TWL_CLKS_SUNLOCK(_sc)		sx_sunlock(&(_sc)->sc_sx)
146 #define TWL_CLKS_LOCK_INIT(_sc)		sx_init(&(_sc)->sc_sx, "twl_clks")
147 #define TWL_CLKS_LOCK_DESTROY(_sc)	sx_destroy(&(_sc)->sc_sx);
148 
149 #define TWL_CLKS_ASSERT_LOCKED(_sc)	sx_assert(&(_sc)->sc_sx, SA_LOCKED);
150 
151 #define TWL_CLKS_LOCK_UPGRADE(_sc)               \
152 	do {                                         \
153 		while (!sx_try_upgrade(&(_sc)->sc_sx))   \
154 			pause("twl_clks_ex", (hz / 100));    \
155 	} while(0)
156 #define TWL_CLKS_LOCK_DOWNGRADE(_sc)	sx_downgrade(&(_sc)->sc_sx);
157 
158 
159 
160 
161 /**
162  *	twl_clks_read_1 - read single register from the TWL device
163  *	twl_clks_write_1 - writes a single register in the TWL device
164  *	@sc: device context
165  *	@clk: the clock device we're reading from / writing to
166  *	@off: offset within the clock's register set
167  *	@val: the value to write or a pointer to a variable to store the result
168  *
169  *	RETURNS:
170  *	Zero on success or an error code on failure.
171  */
172 static inline int
173 twl_clks_read_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
174 	uint8_t off, uint8_t *val)
175 {
176 	return (twl_read(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, val, 1));
177 }
178 
179 static inline int
180 twl_clks_write_1(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
181 	uint8_t off, uint8_t val)
182 {
183 	return (twl_write(sc->sc_pdev, clk->sub_dev, clk->reg_off + off, &val, 1));
184 }
185 
186 
187 /**
188  *	twl_clks_is_enabled - determines if a clock is enabled
189  *	@dev: TWL CLK device
190  *	@name: the name of the clock
191  *	@enabled: upon return will contain the 'enabled' state
192  *
193  *	LOCKING:
194  *	Internally the function takes and releases the TWL lock.
195  *
196  *	RETURNS:
197  *	Zero on success or a negative error code on failure.
198  */
199 int
200 twl_clks_is_enabled(device_t dev, const char *name, int *enabled)
201 {
202 	struct twl_clks_softc *sc = device_get_softc(dev);
203 	struct twl_clk_entry *clk;
204 	int found = 0;
205 	int err;
206 	uint8_t grp, state;
207 
208 	TWL_CLKS_SLOCK(sc);
209 
210 	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
211 		if (strcmp(clk->name, name) == 0) {
212 			found = 1;
213 			break;
214 		}
215 	}
216 
217 	if (!found) {
218 		TWL_CLKS_SUNLOCK(sc);
219 		return (EINVAL);
220 	}
221 
222 
223 	if (twl_is_4030(sc->sc_pdev)) {
224 
225 		err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
226 		if (!err)
227 			*enabled = (grp & TWL4030_P1_GRP);
228 
229 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
230 
231 		TWL_CLKS_LOCK_UPGRADE(sc);
232 
233 		/* Check the clock is in the application group */
234 		if (twl_is_6030(sc->sc_pdev)) {
235 			err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
236 			if (err) {
237 				TWL_CLKS_LOCK_DOWNGRADE(sc);
238 				goto done;
239 			}
240 
241 			if (!(grp & TWL6030_P1_GRP)) {
242 				TWL_CLKS_LOCK_DOWNGRADE(sc);
243 				*enabled = 0; /* disabled */
244 				goto done;
245 			}
246 		}
247 
248 		/* Read the application mode state and verify it's ON */
249 		err = twl_clks_read_1(sc, clk, TWL_CLKS_STATE, &state);
250 		if (!err)
251 			*enabled = ((state & 0x0C) == 0x04);
252 
253 		TWL_CLKS_LOCK_DOWNGRADE(sc);
254 
255 	} else {
256 		err = EINVAL;
257 	}
258 
259 done:
260 	TWL_CLKS_SUNLOCK(sc);
261 	return (err);
262 }
263 
264 
265 /**
266  *	twl_clks_set_state - enables/disables a clock output
267  *	@sc: device context
268  *	@clk: the clock entry to enable/disable
269  *	@enable: non-zero the clock is enabled, zero the clock is disabled
270  *
271  *	LOCKING:
272  *	The TWL CLK lock must be held before this function is called.
273  *
274  *	RETURNS:
275  *	Zero on success or an error code on failure.
276  */
277 static int
278 twl_clks_set_state(struct twl_clks_softc *sc, struct twl_clk_entry *clk,
279 	int enable)
280 {
281 	int xlocked;
282 	int err;
283 	uint8_t grp;
284 
285 	TWL_CLKS_ASSERT_LOCKED(sc);
286 
287 	/* Upgrade the lock to exclusive because about to perform read-mod-write */
288 	xlocked = sx_xlocked(&sc->sc_sx);
289 	if (!xlocked)
290 		TWL_CLKS_LOCK_UPGRADE(sc);
291 
292 	err = twl_clks_read_1(sc, clk, TWL_CLKS_GRP, &grp);
293 	if (err)
294 		goto done;
295 
296 	if (twl_is_4030(sc->sc_pdev)) {
297 
298 		/* On the TWL4030 we just need to ensure the clock is in the right
299 		 * power domain, don't need to turn on explicitly like TWL6030.
300 		 */
301 		if (enable)
302 			grp |= TWL4030_P1_GRP;
303 		else
304 			grp &= ~(TWL4030_P1_GRP | TWL4030_P2_GRP | TWL4030_P3_GRP);
305 
306 		err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
307 
308 	} else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev)) {
309 
310 		/* Make sure the clock belongs to at least the APP power group */
311 		if (twl_is_6030(sc->sc_pdev) && !(grp & TWL6030_P1_GRP)) {
312 			grp |= TWL6030_P1_GRP;
313 			err = twl_clks_write_1(sc, clk, TWL_CLKS_GRP, grp);
314 			if (err)
315 				goto done;
316 		}
317 
318 		/* On TWL6030 we need to make sure we disable power for all groups */
319 		if (twl_is_6030(sc->sc_pdev))
320 			grp = TWL6030_P1_GRP | TWL6030_P2_GRP | TWL6030_P3_GRP;
321 		else
322 			grp = 0x00;
323 
324 		/* Set the state of the clock */
325 		if (enable)
326 			err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5) | 0x01);
327 		else
328 			err = twl_clks_write_1(sc, clk, TWL_CLKS_STATE, (grp << 5));
329 
330 	} else {
331 
332 		err = EINVAL;
333 	}
334 
335 done:
336 	if (!xlocked)
337 		TWL_CLKS_LOCK_DOWNGRADE(sc);
338 
339 	if ((twl_clks_debug > 1) && !err)
340 		device_printf(sc->sc_dev, "%s : %sabled\n", clk->name,
341 			enable ? "en" : "dis");
342 
343 	return (err);
344 }
345 
346 
347 /**
348  *	twl_clks_disable - disables a clock output
349  *	@dev: TWL clk device
350 *	@name: the name of the clock
351  *
352  *	LOCKING:
353  *	Internally the function takes and releases the TWL lock.
354  *
355  *	RETURNS:
356 *	Zero on success or an error code on failure.
357  */
358 int
359 twl_clks_disable(device_t dev, const char *name)
360 {
361 	struct twl_clks_softc *sc = device_get_softc(dev);
362 	struct twl_clk_entry *clk;
363 	int err = EINVAL;
364 
365 	TWL_CLKS_SLOCK(sc);
366 
367 	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
368 		if (strcmp(clk->name, name) == 0) {
369 			err = twl_clks_set_state(sc, clk, 0);
370 			break;
371 		}
372 	}
373 
374 	TWL_CLKS_SUNLOCK(sc);
375 	return (err);
376 }
377 
378 /**
379  *	twl_clks_enable - enables a clock output
380  *	@dev: TWL clk device
381  *	@name: the name of the clock
382  *
383  *	LOCKING:
384  *	Internally the function takes and releases the TWL CLKS lock.
385  *
386  *	RETURNS:
387  *	Zero on success or an error code on failure.
388  */
389 int
390 twl_clks_enable(device_t dev, const char *name)
391 {
392 	struct twl_clks_softc *sc = device_get_softc(dev);
393 	struct twl_clk_entry *clk;
394 	int err = EINVAL;
395 
396 	TWL_CLKS_SLOCK(sc);
397 
398 	LIST_FOREACH(clk, &sc->sc_clks_list, link) {
399 		if (strcmp(clk->name, name) == 0) {
400 			err = twl_clks_set_state(sc, clk, 1);
401 			break;
402 		}
403 	}
404 
405 	TWL_CLKS_SUNLOCK(sc);
406 	return (err);
407 }
408 
409 /**
410  *	twl_clks_sysctl_clock - reads the state of the clock
411  *	@SYSCTL_HANDLER_ARGS: arguments for the callback
412  *
413  *	Returns the clock status; disabled is zero and enabled is non-zero.
414  *
415  *	LOCKING:
416  *	It's expected the TWL lock is held while this function is called.
417  *
418  *	RETURNS:
419  *	EIO if device is not present, otherwise 0 is returned.
420  */
421 static int
422 twl_clks_sysctl_clock(SYSCTL_HANDLER_ARGS)
423 {
424 	struct twl_clks_softc *sc = (struct twl_clks_softc*)arg1;
425 	int err;
426 	int enabled = 0;
427 
428 	if ((err = twl_clks_is_enabled(sc->sc_dev, oidp->oid_name, &enabled)) != 0)
429 		return err;
430 
431 	return sysctl_handle_int(oidp, &enabled, 0, req);
432 }
433 
434 /**
435  *	twl_clks_add_clock - adds single clock sysctls for the device
436  *	@sc: device soft context
437  *	@name: the name of the regulator
438  *	@nsub: the number of the subdevice
439  *	@regbase: the base address of the clocks registers
440  *
441  *	Adds a single clock to the device and also a sysctl interface for
442  *	querying it's status.
443  *
444  *	LOCKING:
445  *	It's expected the exclusive lock is held while this function is called.
446  *
447  *	RETURNS:
448  *	Pointer to the new clock entry on success, otherwise NULL on failure.
449  */
450 static struct twl_clk_entry*
451 twl_clks_add_clock(struct twl_clks_softc *sc, const char *name,
452 	uint8_t nsub, uint8_t regbase)
453 {
454 	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(sc->sc_dev);
455 	struct sysctl_oid *tree = device_get_sysctl_tree(sc->sc_dev);
456 	struct twl_clk_entry *new;
457 
458 	TWL_CLKS_ASSERT_LOCKED(sc);
459 
460 	new = malloc(sizeof(struct twl_clk_entry), M_DEVBUF, M_NOWAIT | M_ZERO);
461 	if (new == NULL)
462 		return (NULL);
463 
464 
465 	strncpy(new->name, name, TWL_CLKS_MAX_NAMELEN);
466 	new->name[TWL_CLKS_MAX_NAMELEN - 1] = '\0';
467 
468 	new->sub_dev = nsub;
469 	new->reg_off = regbase;
470 
471 
472 
473 	/* Add a sysctl entry for the clock */
474 	new->oid = SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, name,
475 	    CTLTYPE_INT | CTLFLAG_RD, sc, 0,
476 	    twl_clks_sysctl_clock, "I", "external clock");
477 
478 	/* Finally add the regulator to list of supported regulators */
479 	LIST_INSERT_HEAD(&sc->sc_clks_list, new, link);
480 
481 	return (new);
482 }
483 
484 /**
485  *	twl_clks_add_clocks - populates the internal list of clocks
486  *	@sc: device soft context
487  *	@chip: the name of the chip used in the hints
488  *	@clks the list of clocks supported by the device
489  *
490  *	Loops over the list of clocks and adds them to the device context. Also
491  *	scans the FDT to determine if there are any clocks that should be
492  *	enabled/disabled automatically.
493  *
494  *	LOCKING:
495  *	Internally takes the exclusive lock while adding the clocks to the
496  *	device context.
497  *
498  *	RETURNS:
499  *	Always returns 0.
500  */
501 static int
502 twl_clks_add_clocks(struct twl_clks_softc *sc, const struct twl_clock *clks)
503 {
504 	int err;
505 	const struct twl_clock *walker;
506 	struct twl_clk_entry *entry;
507 	phandle_t child;
508 	char rnames[256];
509 	char *name, *state;
510 	int len = 0, prop_len;
511 	int enable;
512 
513 
514 	TWL_CLKS_XLOCK(sc);
515 
516 	/* Add the regulators from the list */
517 	walker = &clks[0];
518 	while (walker->name != NULL) {
519 
520 		/* Add the regulator to the list */
521 		entry = twl_clks_add_clock(sc, walker->name, walker->subdev,
522 		    walker->regbase);
523 		if (entry == NULL)
524 			continue;
525 
526 		walker++;
527 	}
528 
529 	/* Check for any FDT settings that need to be applied */
530 	child = ofw_bus_get_node(sc->sc_pdev);
531 	if (child) {
532 
533 		prop_len = OF_getprop(child, "external-clocks", rnames, sizeof(rnames));
534 		while (len < prop_len) {
535 			name = rnames + len;
536 			len += strlen(name) + 1;
537 			if ((len >= prop_len) || (name[0] == '\0'))
538 				break;
539 
540 			state = rnames + len;
541 			len += strlen(state) + 1;
542 			if (state[0] == '\0')
543 				break;
544 
545 			enable = !strncmp(state, "on", 2);
546 
547 			LIST_FOREACH(entry, &sc->sc_clks_list, link) {
548 				if (strcmp(entry->name, name) == 0) {
549 					twl_clks_set_state(sc, entry, enable);
550 					break;
551 				}
552 			}
553 		}
554 	}
555 
556 	TWL_CLKS_XUNLOCK(sc);
557 
558 
559 	if (twl_clks_debug) {
560 		LIST_FOREACH(entry, &sc->sc_clks_list, link) {
561 			err = twl_clks_is_enabled(sc->sc_dev, entry->name, &enable);
562 			if (!err)
563 				device_printf(sc->sc_dev, "%s : %s\n", entry->name,
564 					enable ? "on" : "off");
565 		}
566 	}
567 
568 	return (0);
569 }
570 
571 /**
572  *	twl_clks_init - initialises the list of clocks
573  *	@dev: the twl_clks device
574  *
575  *	This function is called as an intrhook once interrupts have been enabled,
576  *	this is done so that the driver has the option to enable/disable a clock
577  *	based on settings providied in the FDT.
578  *
579  *	LOCKING:
580  *	May takes the exclusive lock in the function.
581  */
582 static void
583 twl_clks_init(void *dev)
584 {
585 	struct twl_clks_softc *sc;
586 
587 	sc = device_get_softc((device_t)dev);
588 
589 	if (twl_is_4030(sc->sc_pdev))
590 		twl_clks_add_clocks(sc, twl4030_clocks);
591 	else if (twl_is_6030(sc->sc_pdev) || twl_is_6025(sc->sc_pdev))
592 		twl_clks_add_clocks(sc, twl6030_clocks);
593 
594 	config_intrhook_disestablish(&sc->sc_init_hook);
595 }
596 
597 static int
598 twl_clks_probe(device_t dev)
599 {
600 	if (twl_is_4030(device_get_parent(dev)))
601 		device_set_desc(dev, "TI TWL4030 PMIC External Clocks");
602 	else if (twl_is_6025(device_get_parent(dev)) ||
603 	         twl_is_6030(device_get_parent(dev)))
604 		device_set_desc(dev, "TI TWL6025/TWL6030 PMIC External Clocks");
605 	else
606 		return (ENXIO);
607 
608 	return (0);
609 }
610 
611 static int
612 twl_clks_attach(device_t dev)
613 {
614 	struct twl_clks_softc *sc;
615 
616 	sc = device_get_softc(dev);
617 	sc->sc_dev = dev;
618 	sc->sc_pdev = device_get_parent(dev);
619 
620 	TWL_CLKS_LOCK_INIT(sc);
621 
622 	LIST_INIT(&sc->sc_clks_list);
623 
624 
625 	sc->sc_init_hook.ich_func = twl_clks_init;
626 	sc->sc_init_hook.ich_arg = dev;
627 
628 	if (config_intrhook_establish(&sc->sc_init_hook) != 0)
629 		return (ENOMEM);
630 
631 	return (0);
632 }
633 
634 static int
635 twl_clks_detach(device_t dev)
636 {
637 	struct twl_clks_softc *sc;
638 	struct twl_clk_entry *clk;
639 	struct twl_clk_entry *tmp;
640 
641 	sc = device_get_softc(dev);
642 
643 	TWL_CLKS_XLOCK(sc);
644 
645 	LIST_FOREACH_SAFE(clk, &sc->sc_clks_list, link, tmp) {
646 		LIST_REMOVE(clk, link);
647 		sysctl_remove_oid(clk->oid, 1, 0);
648 		free(clk, M_DEVBUF);
649 	}
650 
651 	TWL_CLKS_XUNLOCK(sc);
652 
653 	TWL_CLKS_LOCK_DESTROY(sc);
654 
655 	return (0);
656 }
657 
658 static device_method_t twl_clks_methods[] = {
659 	DEVMETHOD(device_probe,		twl_clks_probe),
660 	DEVMETHOD(device_attach,	twl_clks_attach),
661 	DEVMETHOD(device_detach,	twl_clks_detach),
662 
663 	{0, 0},
664 };
665 
666 static driver_t twl_clks_driver = {
667 	"twl_clks",
668 	twl_clks_methods,
669 	sizeof(struct twl_clks_softc),
670 };
671 
672 static devclass_t twl_clks_devclass;
673 
674 DRIVER_MODULE(twl_clks, twl, twl_clks_driver, twl_clks_devclass, 0, 0);
675 MODULE_VERSION(twl_clks, 1);
676