Linux-libre 5.4.49-gnu
[librecmc/linux-libre.git] / drivers / mfd / madera-core.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Core MFD support for Cirrus Logic Madera codecs
4  *
5  * Copyright (C) 2015-2018 Cirrus Logic
6  */
7
8 #include <linux/device.h>
9 #include <linux/delay.h>
10 #include <linux/err.h>
11 #include <linux/gpio.h>
12 #include <linux/mfd/core.h>
13 #include <linux/module.h>
14 #include <linux/mutex.h>
15 #include <linux/notifier.h>
16 #include <linux/of.h>
17 #include <linux/of_gpio.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/regulator/consumer.h>
22 #include <linux/regulator/machine.h>
23 #include <linux/regulator/of_regulator.h>
24
25 #include <linux/mfd/madera/core.h>
26 #include <linux/mfd/madera/registers.h>
27
28 #include "madera.h"
29
30 #define CS47L15_SILICON_ID      0x6370
31 #define CS47L35_SILICON_ID      0x6360
32 #define CS47L85_SILICON_ID      0x6338
33 #define CS47L90_SILICON_ID      0x6364
34 #define CS47L92_SILICON_ID      0x6371
35
36 #define MADERA_32KZ_MCLK2       1
37
38 static const char * const madera_core_supplies[] = {
39         "AVDD",
40         "DBVDD1",
41 };
42
43 static const struct mfd_cell madera_ldo1_devs[] = {
44         { .name = "madera-ldo1" },
45 };
46
47 static const char * const cs47l15_supplies[] = {
48         "MICVDD",
49         "CPVDD1",
50         "SPKVDD",
51 };
52
53 static const struct mfd_cell cs47l15_devs[] = {
54         { .name = "madera-pinctrl", },
55         { .name = "madera-irq" },
56         { .name = "madera-gpio" },
57         {
58                 .name = "madera-extcon",
59                 .parent_supplies = cs47l15_supplies,
60                 .num_parent_supplies = 1, /* We only need MICVDD */
61         },
62         {
63                 .name = "cs47l15-codec",
64                 .parent_supplies = cs47l15_supplies,
65                 .num_parent_supplies = ARRAY_SIZE(cs47l15_supplies),
66         },
67 };
68
69 static const char * const cs47l35_supplies[] = {
70         "MICVDD",
71         "DBVDD2",
72         "CPVDD1",
73         "CPVDD2",
74         "SPKVDD",
75 };
76
77 static const struct mfd_cell cs47l35_devs[] = {
78         { .name = "madera-pinctrl", },
79         { .name = "madera-irq", },
80         { .name = "madera-micsupp", },
81         { .name = "madera-gpio", },
82         {
83                 .name = "madera-extcon",
84                 .parent_supplies = cs47l35_supplies,
85                 .num_parent_supplies = 1, /* We only need MICVDD */
86         },
87         {
88                 .name = "cs47l35-codec",
89                 .parent_supplies = cs47l35_supplies,
90                 .num_parent_supplies = ARRAY_SIZE(cs47l35_supplies),
91         },
92 };
93
94 static const char * const cs47l85_supplies[] = {
95         "MICVDD",
96         "DBVDD2",
97         "DBVDD3",
98         "DBVDD4",
99         "CPVDD1",
100         "CPVDD2",
101         "SPKVDDL",
102         "SPKVDDR",
103 };
104
105 static const struct mfd_cell cs47l85_devs[] = {
106         { .name = "madera-pinctrl", },
107         { .name = "madera-irq", },
108         { .name = "madera-micsupp" },
109         { .name = "madera-gpio", },
110         {
111                 .name = "madera-extcon",
112                 .parent_supplies = cs47l85_supplies,
113                 .num_parent_supplies = 1, /* We only need MICVDD */
114         },
115         {
116                 .name = "cs47l85-codec",
117                 .parent_supplies = cs47l85_supplies,
118                 .num_parent_supplies = ARRAY_SIZE(cs47l85_supplies),
119         },
120 };
121
122 static const char * const cs47l90_supplies[] = {
123         "MICVDD",
124         "DBVDD2",
125         "DBVDD3",
126         "DBVDD4",
127         "CPVDD1",
128         "CPVDD2",
129 };
130
131 static const struct mfd_cell cs47l90_devs[] = {
132         { .name = "madera-pinctrl", },
133         { .name = "madera-irq", },
134         { .name = "madera-micsupp", },
135         { .name = "madera-gpio", },
136         {
137                 .name = "madera-extcon",
138                 .parent_supplies = cs47l90_supplies,
139                 .num_parent_supplies = 1, /* We only need MICVDD */
140         },
141         {
142                 .name = "cs47l90-codec",
143                 .parent_supplies = cs47l90_supplies,
144                 .num_parent_supplies = ARRAY_SIZE(cs47l90_supplies),
145         },
146 };
147
148 static const char * const cs47l92_supplies[] = {
149         "MICVDD",
150         "CPVDD1",
151         "CPVDD2",
152 };
153
154 static const struct mfd_cell cs47l92_devs[] = {
155         { .name = "madera-pinctrl" },
156         { .name = "madera-irq", },
157         { .name = "madera-micsupp", },
158         { .name = "madera-gpio" },
159         {
160                 .name = "madera-extcon",
161                 .parent_supplies = cs47l92_supplies,
162                 .num_parent_supplies = 1, /* We only need MICVDD */
163         },
164         {
165                 .name = "cs47l92-codec",
166                 .parent_supplies = cs47l92_supplies,
167                 .num_parent_supplies = ARRAY_SIZE(cs47l92_supplies),
168         },
169 };
170
171 /* Used by madera-i2c and madera-spi drivers */
172 const char *madera_name_from_type(enum madera_type type)
173 {
174         switch (type) {
175         case CS47L15:
176                 return "CS47L15";
177         case CS47L35:
178                 return "CS47L35";
179         case CS47L85:
180                 return "CS47L85";
181         case CS47L90:
182                 return "CS47L90";
183         case CS47L91:
184                 return "CS47L91";
185         case CS42L92:
186                 return "CS42L92";
187         case CS47L92:
188                 return "CS47L92";
189         case CS47L93:
190                 return "CS47L93";
191         case WM1840:
192                 return "WM1840";
193         default:
194                 return "Unknown";
195         }
196 }
197 EXPORT_SYMBOL_GPL(madera_name_from_type);
198
199 #define MADERA_BOOT_POLL_INTERVAL_USEC          5000
200 #define MADERA_BOOT_POLL_TIMEOUT_USEC           25000
201
202 static int madera_wait_for_boot(struct madera *madera)
203 {
204         ktime_t timeout;
205         unsigned int val = 0;
206         int ret = 0;
207
208         /*
209          * We can't use an interrupt as we need to runtime resume to do so,
210          * so we poll the status bit. This won't race with the interrupt
211          * handler because it will be blocked on runtime resume.
212          * The chip could NAK a read request while it is booting so ignore
213          * errors from regmap_read.
214          */
215         timeout = ktime_add_us(ktime_get(), MADERA_BOOT_POLL_TIMEOUT_USEC);
216         regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
217         while (!(val & MADERA_BOOT_DONE_STS1) &&
218                !ktime_after(ktime_get(), timeout)) {
219                 usleep_range(MADERA_BOOT_POLL_INTERVAL_USEC / 2,
220                              MADERA_BOOT_POLL_INTERVAL_USEC);
221                 regmap_read(madera->regmap, MADERA_IRQ1_RAW_STATUS_1, &val);
222         }
223
224         if (!(val & MADERA_BOOT_DONE_STS1)) {
225                 dev_err(madera->dev, "Polling BOOT_DONE_STS timed out\n");
226                 ret = -ETIMEDOUT;
227         }
228
229         /*
230          * BOOT_DONE defaults to unmasked on boot so we must ack it.
231          * Do this even after a timeout to avoid interrupt storms.
232          */
233         regmap_write(madera->regmap, MADERA_IRQ1_STATUS_1,
234                      MADERA_BOOT_DONE_EINT1);
235
236         pm_runtime_mark_last_busy(madera->dev);
237
238         return ret;
239 }
240
241 static int madera_soft_reset(struct madera *madera)
242 {
243         int ret;
244
245         ret = regmap_write(madera->regmap, MADERA_SOFTWARE_RESET, 0);
246         if (ret != 0) {
247                 dev_err(madera->dev, "Failed to soft reset device: %d\n", ret);
248                 return ret;
249         }
250
251         /* Allow time for internal clocks to startup after reset */
252         usleep_range(1000, 2000);
253
254         return 0;
255 }
256
257 static void madera_enable_hard_reset(struct madera *madera)
258 {
259         if (!madera->pdata.reset)
260                 return;
261
262         /*
263          * There are many existing out-of-tree users of these codecs that we
264          * can't break so preserve the expected behaviour of setting the line
265          * low to assert reset.
266          */
267         gpiod_set_raw_value_cansleep(madera->pdata.reset, 0);
268 }
269
270 static void madera_disable_hard_reset(struct madera *madera)
271 {
272         if (!madera->pdata.reset)
273                 return;
274
275         gpiod_set_raw_value_cansleep(madera->pdata.reset, 1);
276         usleep_range(1000, 2000);
277 }
278
279 static int __maybe_unused madera_runtime_resume(struct device *dev)
280 {
281         struct madera *madera = dev_get_drvdata(dev);
282         int ret;
283
284         dev_dbg(dev, "Leaving sleep mode\n");
285
286         ret = regulator_enable(madera->dcvdd);
287         if (ret) {
288                 dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
289                 return ret;
290         }
291
292         regcache_cache_only(madera->regmap, false);
293         regcache_cache_only(madera->regmap_32bit, false);
294
295         ret = madera_wait_for_boot(madera);
296         if (ret)
297                 goto err;
298
299         ret = regcache_sync(madera->regmap);
300         if (ret) {
301                 dev_err(dev, "Failed to restore 16-bit register cache\n");
302                 goto err;
303         }
304
305         ret = regcache_sync(madera->regmap_32bit);
306         if (ret) {
307                 dev_err(dev, "Failed to restore 32-bit register cache\n");
308                 goto err;
309         }
310
311         return 0;
312
313 err:
314         regcache_cache_only(madera->regmap_32bit, true);
315         regcache_cache_only(madera->regmap, true);
316         regulator_disable(madera->dcvdd);
317
318         return ret;
319 }
320
321 static int __maybe_unused madera_runtime_suspend(struct device *dev)
322 {
323         struct madera *madera = dev_get_drvdata(dev);
324
325         dev_dbg(madera->dev, "Entering sleep mode\n");
326
327         regcache_cache_only(madera->regmap, true);
328         regcache_mark_dirty(madera->regmap);
329         regcache_cache_only(madera->regmap_32bit, true);
330         regcache_mark_dirty(madera->regmap_32bit);
331
332         regulator_disable(madera->dcvdd);
333
334         return 0;
335 }
336
337 const struct dev_pm_ops madera_pm_ops = {
338         SET_RUNTIME_PM_OPS(madera_runtime_suspend,
339                            madera_runtime_resume,
340                            NULL)
341 };
342 EXPORT_SYMBOL_GPL(madera_pm_ops);
343
344 const struct of_device_id madera_of_match[] = {
345         { .compatible = "cirrus,cs47l15", .data = (void *)CS47L15 },
346         { .compatible = "cirrus,cs47l35", .data = (void *)CS47L35 },
347         { .compatible = "cirrus,cs47l85", .data = (void *)CS47L85 },
348         { .compatible = "cirrus,cs47l90", .data = (void *)CS47L90 },
349         { .compatible = "cirrus,cs47l91", .data = (void *)CS47L91 },
350         { .compatible = "cirrus,cs42l92", .data = (void *)CS42L92 },
351         { .compatible = "cirrus,cs47l92", .data = (void *)CS47L92 },
352         { .compatible = "cirrus,cs47l93", .data = (void *)CS47L93 },
353         { .compatible = "cirrus,wm1840", .data = (void *)WM1840 },
354         {}
355 };
356 MODULE_DEVICE_TABLE(of, madera_of_match);
357 EXPORT_SYMBOL_GPL(madera_of_match);
358
359 static int madera_get_reset_gpio(struct madera *madera)
360 {
361         struct gpio_desc *reset;
362         int ret;
363
364         if (madera->pdata.reset)
365                 return 0;
366
367         reset = devm_gpiod_get_optional(madera->dev, "reset", GPIOD_OUT_LOW);
368         if (IS_ERR(reset)) {
369                 ret = PTR_ERR(reset);
370                 if (ret != -EPROBE_DEFER)
371                         dev_err(madera->dev, "Failed to request /RESET: %d\n",
372                                 ret);
373                 return ret;
374         }
375
376         /*
377          * A hard reset is needed for full reset of the chip. We allow running
378          * without hard reset only because it can be useful for early
379          * prototyping and some debugging, but we need to warn it's not ideal.
380          */
381         if (!reset)
382                 dev_warn(madera->dev,
383                          "Running without reset GPIO is not recommended\n");
384
385         madera->pdata.reset = reset;
386
387         return 0;
388 }
389
390 static void madera_set_micbias_info(struct madera *madera)
391 {
392         /*
393          * num_childbias is an array because future codecs can have different
394          * childbiases for each micbias. Unspecified values default to 0.
395          */
396         switch (madera->type) {
397         case CS47L15:
398                 madera->num_micbias = 1;
399                 madera->num_childbias[0] = 3;
400                 return;
401         case CS47L35:
402                 madera->num_micbias = 2;
403                 madera->num_childbias[0] = 2;
404                 madera->num_childbias[1] = 2;
405                 return;
406         case CS47L85:
407         case WM1840:
408                 madera->num_micbias = 4;
409                 /* no child biases */
410                 return;
411         case CS47L90:
412         case CS47L91:
413                 madera->num_micbias = 2;
414                 madera->num_childbias[0] = 4;
415                 madera->num_childbias[1] = 4;
416                 return;
417         case CS42L92:
418         case CS47L92:
419         case CS47L93:
420                 madera->num_micbias = 2;
421                 madera->num_childbias[0] = 4;
422                 madera->num_childbias[1] = 2;
423                 return;
424         default:
425                 return;
426         }
427 }
428
429 int madera_dev_init(struct madera *madera)
430 {
431         struct device *dev = madera->dev;
432         unsigned int hwid;
433         int (*patch_fn)(struct madera *) = NULL;
434         const struct mfd_cell *mfd_devs;
435         int n_devs = 0;
436         int i, ret;
437
438         dev_set_drvdata(madera->dev, madera);
439         BLOCKING_INIT_NOTIFIER_HEAD(&madera->notifier);
440         mutex_init(&madera->dapm_ptr_lock);
441
442         madera_set_micbias_info(madera);
443
444         /*
445          * We need writable hw config info that all children can share.
446          * Simplest to take one shared copy of pdata struct.
447          */
448         if (dev_get_platdata(madera->dev)) {
449                 memcpy(&madera->pdata, dev_get_platdata(madera->dev),
450                        sizeof(madera->pdata));
451         }
452
453         ret = madera_get_reset_gpio(madera);
454         if (ret)
455                 return ret;
456
457         regcache_cache_only(madera->regmap, true);
458         regcache_cache_only(madera->regmap_32bit, true);
459
460         for (i = 0; i < ARRAY_SIZE(madera_core_supplies); i++)
461                 madera->core_supplies[i].supply = madera_core_supplies[i];
462
463         madera->num_core_supplies = ARRAY_SIZE(madera_core_supplies);
464
465         /*
466          * On some codecs DCVDD could be supplied by the internal LDO1.
467          * For those we must add the LDO1 driver before requesting DCVDD
468          * No devm_ because we need to control shutdown order of children.
469          */
470         switch (madera->type) {
471         case CS47L15:
472         case CS47L35:
473         case CS47L90:
474         case CS47L91:
475         case CS42L92:
476         case CS47L92:
477         case CS47L93:
478                 break;
479         case CS47L85:
480         case WM1840:
481                 ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
482                                       madera_ldo1_devs,
483                                       ARRAY_SIZE(madera_ldo1_devs),
484                                       NULL, 0, NULL);
485                 if (ret) {
486                         dev_err(dev, "Failed to add LDO1 child: %d\n", ret);
487                         return ret;
488                 }
489                 break;
490         default:
491                 /* No point continuing if the type is unknown */
492                 dev_err(madera->dev, "Unknown device type %d\n", madera->type);
493                 return -ENODEV;
494         }
495
496         ret = devm_regulator_bulk_get(dev, madera->num_core_supplies,
497                                       madera->core_supplies);
498         if (ret) {
499                 dev_err(dev, "Failed to request core supplies: %d\n", ret);
500                 goto err_devs;
501         }
502
503         /*
504          * Don't use devres here. If the regulator is one of our children it
505          * will already have been removed before devres cleanup on this mfd
506          * driver tries to call put() on it. We need control of shutdown order.
507          */
508         madera->dcvdd = regulator_get(madera->dev, "DCVDD");
509         if (IS_ERR(madera->dcvdd)) {
510                 ret = PTR_ERR(madera->dcvdd);
511                 dev_err(dev, "Failed to request DCVDD: %d\n", ret);
512                 goto err_devs;
513         }
514
515         ret = regulator_bulk_enable(madera->num_core_supplies,
516                                     madera->core_supplies);
517         if (ret) {
518                 dev_err(dev, "Failed to enable core supplies: %d\n", ret);
519                 goto err_dcvdd;
520         }
521
522         ret = regulator_enable(madera->dcvdd);
523         if (ret) {
524                 dev_err(dev, "Failed to enable DCVDD: %d\n", ret);
525                 goto err_enable;
526         }
527
528         madera_disable_hard_reset(madera);
529
530         regcache_cache_only(madera->regmap, false);
531         regcache_cache_only(madera->regmap_32bit, false);
532
533         /*
534          * Now we can power up and verify that this is a chip we know about
535          * before we start doing any writes to its registers.
536          */
537         ret = regmap_read(madera->regmap, MADERA_SOFTWARE_RESET, &hwid);
538         if (ret) {
539                 dev_err(dev, "Failed to read ID register: %d\n", ret);
540                 goto err_reset;
541         }
542
543         switch (hwid) {
544         case CS47L15_SILICON_ID:
545                 if (IS_ENABLED(CONFIG_MFD_CS47L15)) {
546                         switch (madera->type) {
547                         case CS47L15:
548                                 patch_fn = &cs47l15_patch;
549                                 mfd_devs = cs47l15_devs;
550                                 n_devs = ARRAY_SIZE(cs47l15_devs);
551                                 break;
552                         default:
553                                 break;
554                         }
555                 }
556                 break;
557         case CS47L35_SILICON_ID:
558                 if (IS_ENABLED(CONFIG_MFD_CS47L35)) {
559                         switch (madera->type) {
560                         case CS47L35:
561                                 patch_fn = cs47l35_patch;
562                                 mfd_devs = cs47l35_devs;
563                                 n_devs = ARRAY_SIZE(cs47l35_devs);
564                                 break;
565                         default:
566                                 break;
567                         }
568                 }
569                 break;
570         case CS47L85_SILICON_ID:
571                 if (IS_ENABLED(CONFIG_MFD_CS47L85)) {
572                         switch (madera->type) {
573                         case CS47L85:
574                         case WM1840:
575                                 patch_fn = cs47l85_patch;
576                                 mfd_devs = cs47l85_devs;
577                                 n_devs = ARRAY_SIZE(cs47l85_devs);
578                                 break;
579                         default:
580                                 break;
581                         }
582                 }
583                 break;
584         case CS47L90_SILICON_ID:
585                 if (IS_ENABLED(CONFIG_MFD_CS47L90)) {
586                         switch (madera->type) {
587                         case CS47L90:
588                         case CS47L91:
589                                 patch_fn = cs47l90_patch;
590                                 mfd_devs = cs47l90_devs;
591                                 n_devs = ARRAY_SIZE(cs47l90_devs);
592                                 break;
593                         default:
594                                 break;
595                         }
596                 }
597                 break;
598         case CS47L92_SILICON_ID:
599                 if (IS_ENABLED(CONFIG_MFD_CS47L92)) {
600                         switch (madera->type) {
601                         case CS42L92:
602                         case CS47L92:
603                         case CS47L93:
604                                 patch_fn = cs47l92_patch;
605                                 mfd_devs = cs47l92_devs;
606                                 n_devs = ARRAY_SIZE(cs47l92_devs);
607                                 break;
608                         default:
609                                 break;
610                         }
611                 }
612                 break;
613         default:
614                 dev_err(madera->dev, "Unknown device ID: %x\n", hwid);
615                 ret = -EINVAL;
616                 goto err_reset;
617         }
618
619         if (!n_devs) {
620                 dev_err(madera->dev, "Device ID 0x%x not a %s\n", hwid,
621                         madera->type_name);
622                 ret = -ENODEV;
623                 goto err_reset;
624         }
625
626         /*
627          * It looks like a device we support. If we don't have a hard reset
628          * we can now attempt a soft reset.
629          */
630         if (!madera->pdata.reset) {
631                 ret = madera_soft_reset(madera);
632                 if (ret)
633                         goto err_reset;
634         }
635
636         ret = madera_wait_for_boot(madera);
637         if (ret) {
638                 dev_err(madera->dev, "Device failed initial boot: %d\n", ret);
639                 goto err_reset;
640         }
641
642         ret = regmap_read(madera->regmap, MADERA_HARDWARE_REVISION,
643                           &madera->rev);
644         if (ret) {
645                 dev_err(dev, "Failed to read revision register: %d\n", ret);
646                 goto err_reset;
647         }
648         madera->rev &= MADERA_HW_REVISION_MASK;
649
650         dev_info(dev, "%s silicon revision %d\n", madera->type_name,
651                  madera->rev);
652
653         /* Apply hardware patch */
654         if (patch_fn) {
655                 ret = patch_fn(madera);
656                 if (ret) {
657                         dev_err(madera->dev, "Failed to apply patch %d\n", ret);
658                         goto err_reset;
659                 }
660         }
661
662         /* Init 32k clock sourced from MCLK2 */
663         ret = regmap_update_bits(madera->regmap,
664                         MADERA_CLOCK_32K_1,
665                         MADERA_CLK_32K_ENA_MASK | MADERA_CLK_32K_SRC_MASK,
666                         MADERA_CLK_32K_ENA | MADERA_32KZ_MCLK2);
667         if (ret) {
668                 dev_err(madera->dev, "Failed to init 32k clock: %d\n", ret);
669                 goto err_reset;
670         }
671
672         pm_runtime_set_active(madera->dev);
673         pm_runtime_enable(madera->dev);
674         pm_runtime_set_autosuspend_delay(madera->dev, 100);
675         pm_runtime_use_autosuspend(madera->dev);
676
677         /* No devm_ because we need to control shutdown order of children */
678         ret = mfd_add_devices(madera->dev, PLATFORM_DEVID_NONE,
679                               mfd_devs, n_devs,
680                               NULL, 0, NULL);
681         if (ret) {
682                 dev_err(madera->dev, "Failed to add subdevices: %d\n", ret);
683                 goto err_pm_runtime;
684         }
685
686         return 0;
687
688 err_pm_runtime:
689         pm_runtime_disable(madera->dev);
690 err_reset:
691         madera_enable_hard_reset(madera);
692         regulator_disable(madera->dcvdd);
693 err_enable:
694         regulator_bulk_disable(madera->num_core_supplies,
695                                madera->core_supplies);
696 err_dcvdd:
697         regulator_put(madera->dcvdd);
698 err_devs:
699         mfd_remove_devices(dev);
700
701         return ret;
702 }
703 EXPORT_SYMBOL_GPL(madera_dev_init);
704
705 int madera_dev_exit(struct madera *madera)
706 {
707         /* Prevent any IRQs being serviced while we clean up */
708         disable_irq(madera->irq);
709
710         /*
711          * DCVDD could be supplied by a child node, we must disable it before
712          * removing the children, and prevent PM runtime from turning it back on
713          */
714         pm_runtime_disable(madera->dev);
715
716         regulator_disable(madera->dcvdd);
717         regulator_put(madera->dcvdd);
718
719         mfd_remove_devices(madera->dev);
720         madera_enable_hard_reset(madera);
721
722         regulator_bulk_disable(madera->num_core_supplies,
723                                madera->core_supplies);
724         return 0;
725 }
726 EXPORT_SYMBOL_GPL(madera_dev_exit);
727
728 MODULE_DESCRIPTION("Madera core MFD driver");
729 MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
730 MODULE_LICENSE("GPL v2");