aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/88pm800.c
diff options
context:
space:
mode:
authorQiao Zhou <zhouqiao@marvell.com>2012-07-09 02:37:32 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-07-09 09:12:51 -0400
commit70c6cce040661204986ebbf22224cb24bd77ea71 (patch)
treefe60851749c386e65735818e397850f2b3bd7d3e /drivers/mfd/88pm800.c
parent49003a68926e073fc71062d210c6f9febc8665a2 (diff)
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management. Hardware designer can use them together or only one of them according to requirement. 88pm80x.c provides common i2c driver handling for both 800 and 805, such as i2c_driver init, regmap init, read/write api etc. 88pm800.c handles specifically for 800, such as chip init, irq init/handle, mfd device register, including rtc, onkey, regulator( to be add later) etc. besides that, 800 has three i2c device, one regular i2c client, two other i2c dummy for gpadc and power purpose. 88pm805.c handles specifically for 805, such as chip init, irq init/handle, mfd device register, including codec, headset/mic detect etc. the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c exported a group of r/w bulk r/w and bits set API for facility. Signed-off-by: Qiao Zhou <zhouqiao@marvell.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/88pm800.c')
-rw-r--r--drivers/mfd/88pm800.c593
1 files changed, 593 insertions, 0 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
new file mode 100644
index 000000000000..fe479ccfaa19
--- /dev/null
+++ b/drivers/mfd/88pm800.c
@@ -0,0 +1,593 @@
1/*
2 * Base driver for Marvell 88PM800
3 *
4 * Copyright (C) 2012 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 * Joseph(Yossi) Hanin <yhanin@marvell.com>
7 * Qiao Zhou <zhouqiao@marvell.com>
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/i2c.h>
26#include <linux/mfd/core.h>
27#include <linux/mfd/88pm80x.h>
28#include <linux/slab.h>
29
30#define PM800_CHIP_ID (0x00)
31
32/* Interrupt Registers */
33#define PM800_INT_STATUS1 (0x05)
34#define PM800_ONKEY_INT_STS1 (1 << 0)
35#define PM800_EXTON_INT_STS1 (1 << 1)
36#define PM800_CHG_INT_STS1 (1 << 2)
37#define PM800_BAT_INT_STS1 (1 << 3)
38#define PM800_RTC_INT_STS1 (1 << 4)
39#define PM800_CLASSD_OC_INT_STS1 (1 << 5)
40
41#define PM800_INT_STATUS2 (0x06)
42#define PM800_VBAT_INT_STS2 (1 << 0)
43#define PM800_VSYS_INT_STS2 (1 << 1)
44#define PM800_VCHG_INT_STS2 (1 << 2)
45#define PM800_TINT_INT_STS2 (1 << 3)
46#define PM800_GPADC0_INT_STS2 (1 << 4)
47#define PM800_TBAT_INT_STS2 (1 << 5)
48#define PM800_GPADC2_INT_STS2 (1 << 6)
49#define PM800_GPADC3_INT_STS2 (1 << 7)
50
51#define PM800_INT_STATUS3 (0x07)
52
53#define PM800_INT_STATUS4 (0x08)
54#define PM800_GPIO0_INT_STS4 (1 << 0)
55#define PM800_GPIO1_INT_STS4 (1 << 1)
56#define PM800_GPIO2_INT_STS4 (1 << 2)
57#define PM800_GPIO3_INT_STS4 (1 << 3)
58#define PM800_GPIO4_INT_STS4 (1 << 4)
59
60#define PM800_INT_ENA_1 (0x09)
61#define PM800_ONKEY_INT_ENA1 (1 << 0)
62#define PM800_EXTON_INT_ENA1 (1 << 1)
63#define PM800_CHG_INT_ENA1 (1 << 2)
64#define PM800_BAT_INT_ENA1 (1 << 3)
65#define PM800_RTC_INT_ENA1 (1 << 4)
66#define PM800_CLASSD_OC_INT_ENA1 (1 << 5)
67
68#define PM800_INT_ENA_2 (0x0A)
69#define PM800_VBAT_INT_ENA2 (1 << 0)
70#define PM800_VSYS_INT_ENA2 (1 << 1)
71#define PM800_VCHG_INT_ENA2 (1 << 2)
72#define PM800_TINT_INT_ENA2 (1 << 3)
73
74#define PM800_INT_ENA_3 (0x0B)
75#define PM800_GPADC0_INT_ENA3 (1 << 0)
76#define PM800_GPADC1_INT_ENA3 (1 << 1)
77#define PM800_GPADC2_INT_ENA3 (1 << 2)
78#define PM800_GPADC3_INT_ENA3 (1 << 3)
79#define PM800_GPADC4_INT_ENA3 (1 << 4)
80
81#define PM800_INT_ENA_4 (0x0C)
82#define PM800_GPIO0_INT_ENA4 (1 << 0)
83#define PM800_GPIO1_INT_ENA4 (1 << 1)
84#define PM800_GPIO2_INT_ENA4 (1 << 2)
85#define PM800_GPIO3_INT_ENA4 (1 << 3)
86#define PM800_GPIO4_INT_ENA4 (1 << 4)
87
88/* number of INT_ENA & INT_STATUS regs */
89#define PM800_INT_REG_NUM (4)
90
91/* Interrupt Number in 88PM800 */
92enum {
93 PM800_IRQ_ONKEY, /*EN1b0 *//*0 */
94 PM800_IRQ_EXTON, /*EN1b1 */
95 PM800_IRQ_CHG, /*EN1b2 */
96 PM800_IRQ_BAT, /*EN1b3 */
97 PM800_IRQ_RTC, /*EN1b4 */
98 PM800_IRQ_CLASSD, /*EN1b5 *//*5 */
99 PM800_IRQ_VBAT, /*EN2b0 */
100 PM800_IRQ_VSYS, /*EN2b1 */
101 PM800_IRQ_VCHG, /*EN2b2 */
102 PM800_IRQ_TINT, /*EN2b3 */
103 PM800_IRQ_GPADC0, /*EN3b0 *//*10 */
104 PM800_IRQ_GPADC1, /*EN3b1 */
105 PM800_IRQ_GPADC2, /*EN3b2 */
106 PM800_IRQ_GPADC3, /*EN3b3 */
107 PM800_IRQ_GPADC4, /*EN3b4 */
108 PM800_IRQ_GPIO0, /*EN4b0 *//*15 */
109 PM800_IRQ_GPIO1, /*EN4b1 */
110 PM800_IRQ_GPIO2, /*EN4b2 */
111 PM800_IRQ_GPIO3, /*EN4b3 */
112 PM800_IRQ_GPIO4, /*EN4b4 *//*19 */
113 PM800_MAX_IRQ,
114};
115
116enum {
117 /* Procida */
118 PM800_CHIP_A0 = 0x60,
119 PM800_CHIP_A1 = 0x61,
120 PM800_CHIP_B0 = 0x62,
121 PM800_CHIP_C0 = 0x63,
122 PM800_CHIP_END = PM800_CHIP_C0,
123
124 /* Make sure to update this to the last stepping */
125 PM8XXX_CHIP_END = PM800_CHIP_END
126};
127
128static const struct i2c_device_id pm80x_id_table[] = {
129 {"88PM800", CHIP_PM800},
130};
131MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
132
133static struct resource rtc_resources[] = {
134 {
135 .name = "88pm80x-rtc",
136 .start = PM800_IRQ_RTC,
137 .end = PM800_IRQ_RTC,
138 .flags = IORESOURCE_IRQ,
139 },
140};
141
142static struct mfd_cell rtc_devs[] = {
143 {
144 .name = "88pm80x-rtc",
145 .num_resources = ARRAY_SIZE(rtc_resources),
146 .resources = &rtc_resources[0],
147 .id = -1,
148 },
149};
150
151static struct resource onkey_resources[] = {
152 {
153 .name = "88pm80x-onkey",
154 .start = PM800_IRQ_ONKEY,
155 .end = PM800_IRQ_ONKEY,
156 .flags = IORESOURCE_IRQ,
157 },
158};
159
160static struct mfd_cell onkey_devs[] = {
161 {
162 .name = "88pm80x-onkey",
163 .num_resources = 1,
164 .resources = &onkey_resources[0],
165 .id = -1,
166 },
167};
168
169static const struct regmap_irq pm800_irqs[] = {
170 /* INT0 */
171 [PM800_IRQ_ONKEY] = {
172 .mask = PM800_ONKEY_INT_ENA1,
173 },
174 [PM800_IRQ_EXTON] = {
175 .mask = PM800_EXTON_INT_ENA1,
176 },
177 [PM800_IRQ_CHG] = {
178 .mask = PM800_CHG_INT_ENA1,
179 },
180 [PM800_IRQ_BAT] = {
181 .mask = PM800_BAT_INT_ENA1,
182 },
183 [PM800_IRQ_RTC] = {
184 .mask = PM800_RTC_INT_ENA1,
185 },
186 [PM800_IRQ_CLASSD] = {
187 .mask = PM800_CLASSD_OC_INT_ENA1,
188 },
189 /* INT1 */
190 [PM800_IRQ_VBAT] = {
191 .reg_offset = 1,
192 .mask = PM800_VBAT_INT_ENA2,
193 },
194 [PM800_IRQ_VSYS] = {
195 .reg_offset = 1,
196 .mask = PM800_VSYS_INT_ENA2,
197 },
198 [PM800_IRQ_VCHG] = {
199 .reg_offset = 1,
200 .mask = PM800_VCHG_INT_ENA2,
201 },
202 [PM800_IRQ_TINT] = {
203 .reg_offset = 1,
204 .mask = PM800_TINT_INT_ENA2,
205 },
206 /* INT2 */
207 [PM800_IRQ_GPADC0] = {
208 .reg_offset = 2,
209 .mask = PM800_GPADC0_INT_ENA3,
210 },
211 [PM800_IRQ_GPADC1] = {
212 .reg_offset = 2,
213 .mask = PM800_GPADC1_INT_ENA3,
214 },
215 [PM800_IRQ_GPADC2] = {
216 .reg_offset = 2,
217 .mask = PM800_GPADC2_INT_ENA3,
218 },
219 [PM800_IRQ_GPADC3] = {
220 .reg_offset = 2,
221 .mask = PM800_GPADC3_INT_ENA3,
222 },
223 [PM800_IRQ_GPADC4] = {
224 .reg_offset = 2,
225 .mask = PM800_GPADC4_INT_ENA3,
226 },
227 /* INT3 */
228 [PM800_IRQ_GPIO0] = {
229 .reg_offset = 3,
230 .mask = PM800_GPIO0_INT_ENA4,
231 },
232 [PM800_IRQ_GPIO1] = {
233 .reg_offset = 3,
234 .mask = PM800_GPIO1_INT_ENA4,
235 },
236 [PM800_IRQ_GPIO2] = {
237 .reg_offset = 3,
238 .mask = PM800_GPIO2_INT_ENA4,
239 },
240 [PM800_IRQ_GPIO3] = {
241 .reg_offset = 3,
242 .mask = PM800_GPIO3_INT_ENA4,
243 },
244 [PM800_IRQ_GPIO4] = {
245 .reg_offset = 3,
246 .mask = PM800_GPIO4_INT_ENA4,
247 },
248};
249
250static int __devinit device_gpadc_init(struct pm80x_chip *chip,
251 struct pm80x_platform_data *pdata)
252{
253 struct pm80x_subchip *subchip = chip->subchip;
254 struct regmap *map = subchip->regmap_gpadc;
255 int data = 0, mask = 0, ret = 0;
256
257 if (!map) {
258 dev_warn(chip->dev,
259 "Warning: gpadc regmap is not available!\n");
260 return -EINVAL;
261 }
262 /*
263 * initialize GPADC without activating it turn on GPADC
264 * measurments
265 */
266 ret = regmap_update_bits(map,
267 PM800_GPADC_MISC_CONFIG2,
268 PM800_GPADC_MISC_GPFSM_EN,
269 PM800_GPADC_MISC_GPFSM_EN);
270 if (ret < 0)
271 goto out;
272 /*
273 * This function configures the ADC as requires for
274 * CP implementation.CP does not "own" the ADC configuration
275 * registers and relies on AP.
276 * Reason: enable automatic ADC measurements needed
277 * for CP to get VBAT and RF temperature readings.
278 */
279 ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN1,
280 PM800_MEAS_EN1_VBAT, PM800_MEAS_EN1_VBAT);
281 if (ret < 0)
282 goto out;
283 ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN2,
284 (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN),
285 (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN));
286 if (ret < 0)
287 goto out;
288
289 /*
290 * the defult of PM800 is GPADC operates at 100Ks/s rate
291 * and Number of GPADC slots with active current bias prior
292 * to GPADC sampling = 1 slot for all GPADCs set for
293 * Temprature mesurmants
294 */
295 mask = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
296 PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
297
298 if (pdata && (pdata->batt_det == 0))
299 data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
300 PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
301 else
302 data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN2 |
303 PM800_GPADC_GP_BIAS_EN3);
304
305 ret = regmap_update_bits(map, PM800_GP_BIAS_ENA1, mask, data);
306 if (ret < 0)
307 goto out;
308
309 dev_info(chip->dev, "pm800 device_gpadc_init: Done\n");
310 return 0;
311
312out:
313 dev_info(chip->dev, "pm800 device_gpadc_init: Failed!\n");
314 return ret;
315}
316
317static int __devinit device_irq_init_800(struct pm80x_chip *chip)
318{
319 struct regmap *map = chip->regmap;
320 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
321 int data, mask, ret = -EINVAL;
322
323 if (!map || !chip->irq) {
324 dev_err(chip->dev, "incorrect parameters\n");
325 return -EINVAL;
326 }
327
328 /*
329 * irq_mode defines the way of clearing interrupt. it's read-clear by
330 * default.
331 */
332 mask =
333 PM800_WAKEUP2_INV_INT | PM800_WAKEUP2_INT_CLEAR |
334 PM800_WAKEUP2_INT_MASK;
335
336 data = PM800_WAKEUP2_INT_CLEAR;
337 ret = regmap_update_bits(map, PM800_WAKEUP2, mask, data);
338
339 if (ret < 0)
340 goto out;
341
342 ret =
343 regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
344 chip->regmap_irq_chip, &chip->irq_data);
345
346out:
347 return ret;
348}
349
350static void device_irq_exit_800(struct pm80x_chip *chip)
351{
352 regmap_del_irq_chip(chip->irq, chip->irq_data);
353}
354
355static struct regmap_irq_chip pm800_irq_chip = {
356 .name = "88pm800",
357 .irqs = pm800_irqs,
358 .num_irqs = ARRAY_SIZE(pm800_irqs),
359
360 .num_regs = 4,
361 .status_base = PM800_INT_STATUS1,
362 .mask_base = PM800_INT_ENA_1,
363 .ack_base = PM800_INT_STATUS1,
364};
365
366static int pm800_pages_init(struct pm80x_chip *chip)
367{
368 struct pm80x_subchip *subchip;
369 struct i2c_client *client = chip->client;
370
371 subchip = chip->subchip;
372 /* PM800 block power: i2c addr 0x31 */
373 if (subchip->power_page_addr) {
374 subchip->power_page =
375 i2c_new_dummy(client->adapter, subchip->power_page_addr);
376 subchip->regmap_power =
377 devm_regmap_init_i2c(subchip->power_page,
378 &pm80x_regmap_config);
379 i2c_set_clientdata(subchip->power_page, chip);
380 } else
381 dev_info(chip->dev,
382 "PM800 block power 0x31: No power_page_addr\n");
383
384 /* PM800 block GPADC: i2c addr 0x32 */
385 if (subchip->gpadc_page_addr) {
386 subchip->gpadc_page = i2c_new_dummy(client->adapter,
387 subchip->gpadc_page_addr);
388 subchip->regmap_gpadc =
389 devm_regmap_init_i2c(subchip->gpadc_page,
390 &pm80x_regmap_config);
391 i2c_set_clientdata(subchip->gpadc_page, chip);
392 } else
393 dev_info(chip->dev,
394 "PM800 block GPADC 0x32: No gpadc_page_addr\n");
395
396 return 0;
397}
398
399static void pm800_pages_exit(struct pm80x_chip *chip)
400{
401 struct pm80x_subchip *subchip;
402
403 regmap_exit(chip->regmap);
404 i2c_unregister_device(chip->client);
405
406 subchip = chip->subchip;
407 if (subchip->power_page) {
408 regmap_exit(subchip->regmap_power);
409 i2c_unregister_device(subchip->power_page);
410 }
411 if (subchip->gpadc_page) {
412 regmap_exit(subchip->regmap_gpadc);
413 i2c_unregister_device(subchip->gpadc_page);
414 }
415}
416
417static int __devinit device_800_init(struct pm80x_chip *chip,
418 struct pm80x_platform_data *pdata)
419{
420 int ret, pmic_id;
421
422 regmap_read(chip->regmap, PM800_CHIP_ID, &ret);
423 if (ret < 0) {
424 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
425 goto out;
426 }
427
428 pmic_id = ret & PM80X_VERSION_MASK;
429
430 if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
431 chip->version = ret;
432 dev_info(chip->dev,
433 "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", ret);
434 } else {
435 dev_err(chip->dev,
436 "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", ret);
437 goto out;
438 }
439
440 /*
441 * alarm wake up bit will be clear in device_irq_init(),
442 * read before that
443 */
444 regmap_read(chip->regmap, PM800_RTC_CONTROL, &ret);
445 if (ret < 0) {
446 dev_err(chip->dev, "Failed to read RTC register: %d\n", ret);
447 goto out;
448 }
449 if (ret & PM800_ALARM_WAKEUP) {
450 if (pdata && pdata->rtc)
451 pdata->rtc->rtc_wakeup = 1;
452 }
453
454 ret = device_gpadc_init(chip, pdata);
455 if (ret < 0) {
456 dev_err(chip->dev, "[%s]Failed to init gpadc\n", __func__);
457 goto out;
458 }
459
460 chip->regmap_irq_chip = &pm800_irq_chip;
461
462 ret = device_irq_init_800(chip);
463 if (ret < 0) {
464 dev_err(chip->dev, "[%s]Failed to init pm800 irq\n", __func__);
465 goto out;
466 }
467
468 ret =
469 mfd_add_devices(chip->dev, 0, &onkey_devs[0],
470 ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0);
471 if (ret < 0) {
472 dev_err(chip->dev, "Failed to add onkey subdev\n");
473 goto out_dev;
474 } else
475 dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
476
477 if (pdata && pdata->rtc) {
478 rtc_devs[0].platform_data = pdata->rtc;
479 rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
480 ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
481 ARRAY_SIZE(rtc_devs), NULL, 0);
482 if (ret < 0) {
483 dev_err(chip->dev, "Failed to add rtc subdev\n");
484 goto out_dev;
485 } else
486 dev_info(chip->dev,
487 "[%s]:Added mfd rtc_devs\n", __func__);
488 }
489
490 return 0;
491out_dev:
492 mfd_remove_devices(chip->dev);
493 device_irq_exit_800(chip);
494out:
495 return ret;
496}
497
498static int __devinit pm800_probe(struct i2c_client *client,
499 const struct i2c_device_id *id)
500{
501 int ret = 0;
502 struct pm80x_chip *chip;
503 struct pm80x_platform_data *pdata = client->dev.platform_data;
504 struct pm80x_subchip *subchip;
505
506 ret = pm80x_init(client, id);
507 if (ret) {
508 dev_err(&client->dev, "pm800_init fail\n");
509 goto out_init;
510 }
511
512 chip = i2c_get_clientdata(client);
513
514 /* init subchip for PM800 */
515 subchip =
516 devm_kzalloc(&client->dev, sizeof(struct pm80x_subchip),
517 GFP_KERNEL);
518 if (!subchip) {
519 ret = -ENOMEM;
520 goto err_subchip_alloc;
521 }
522
523 subchip->power_page_addr = pdata->power_page_addr;
524 subchip->gpadc_page_addr = pdata->gpadc_page_addr;
525 chip->subchip = subchip;
526
527 ret = device_800_init(chip, pdata);
528 if (ret) {
529 dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
530 goto err_800_init;
531 }
532
533 ret = pm800_pages_init(chip);
534 if (ret) {
535 dev_err(&client->dev, "pm800_pages_init failed!\n");
536 goto err_page_init;
537 }
538
539 if (pdata->plat_config)
540 pdata->plat_config(chip, pdata);
541
542err_page_init:
543 mfd_remove_devices(chip->dev);
544 device_irq_exit_800(chip);
545err_800_init:
546 devm_kfree(&client->dev, subchip);
547err_subchip_alloc:
548 pm80x_deinit(client);
549out_init:
550 return ret;
551}
552
553static int __devexit pm800_remove(struct i2c_client *client)
554{
555 struct pm80x_chip *chip = i2c_get_clientdata(client);
556
557 mfd_remove_devices(chip->dev);
558 device_irq_exit_800(chip);
559
560 pm800_pages_exit(chip);
561 devm_kfree(&client->dev, chip->subchip);
562
563 pm80x_deinit(client);
564
565 return 0;
566}
567
568static struct i2c_driver pm800_driver = {
569 .driver = {
570 .name = "88PM80X",
571 .owner = THIS_MODULE,
572 .pm = &pm80x_pm_ops,
573 },
574 .probe = pm800_probe,
575 .remove = __devexit_p(pm800_remove),
576 .id_table = pm80x_id_table,
577};
578
579static int __init pm800_i2c_init(void)
580{
581 return i2c_add_driver(&pm800_driver);
582}
583subsys_initcall(pm800_i2c_init);
584
585static void __exit pm800_i2c_exit(void)
586{
587 i2c_del_driver(&pm800_driver);
588}
589module_exit(pm800_i2c_exit);
590
591MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM800");
592MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
593MODULE_LICENSE("GPL");