1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Freescale i.MX7D ADC driver 4 * 5 * Copyright (C) 2015 Freescale Semiconductor, Inc. 6 */ 7 8 #include <linux/clk.h> 9 #include <linux/completion.h> 10 #include <linux/err.h> 11 #include <linux/interrupt.h> 12 #include <linux/io.h> 13 #include <linux/kernel.h> 14 #include <linux/mod_devicetable.h> 15 #include <linux/module.h> 16 #include <linux/mutex.h> 17 #include <linux/platform_device.h> 18 #include <linux/regulator/consumer.h> 19 20 #include <linux/iio/iio.h> 21 #include <linux/iio/driver.h> 22 #include <linux/iio/sysfs.h> 23 24 /* ADC register */ 25 #define IMX7D_REG_ADC_CH_A_CFG1 0x00 26 #define IMX7D_REG_ADC_CH_A_CFG2 0x10 27 #define IMX7D_REG_ADC_CH_B_CFG1 0x20 28 #define IMX7D_REG_ADC_CH_B_CFG2 0x30 29 #define IMX7D_REG_ADC_CH_C_CFG1 0x40 30 #define IMX7D_REG_ADC_CH_C_CFG2 0x50 31 #define IMX7D_REG_ADC_CH_D_CFG1 0x60 32 #define IMX7D_REG_ADC_CH_D_CFG2 0x70 33 #define IMX7D_REG_ADC_CH_SW_CFG 0x80 34 #define IMX7D_REG_ADC_TIMER_UNIT 0x90 35 #define IMX7D_REG_ADC_DMA_FIFO 0xa0 36 #define IMX7D_REG_ADC_FIFO_STATUS 0xb0 37 #define IMX7D_REG_ADC_INT_SIG_EN 0xc0 38 #define IMX7D_REG_ADC_INT_EN 0xd0 39 #define IMX7D_REG_ADC_INT_STATUS 0xe0 40 #define IMX7D_REG_ADC_CHA_B_CNV_RSLT 0xf0 41 #define IMX7D_REG_ADC_CHC_D_CNV_RSLT 0x100 42 #define IMX7D_REG_ADC_CH_SW_CNV_RSLT 0x110 43 #define IMX7D_REG_ADC_DMA_FIFO_DAT 0x120 44 #define IMX7D_REG_ADC_ADC_CFG 0x130 45 46 #define IMX7D_REG_ADC_CHANNEL_CFG2_BASE 0x10 47 #define IMX7D_EACH_CHANNEL_REG_OFFSET 0x20 48 49 #define IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN (0x1 << 31) 50 #define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE BIT(30) 51 #define IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN BIT(29) 52 #define IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(x) ((x) << 24) 53 54 #define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4 (0x0 << 12) 55 #define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8 (0x1 << 12) 56 #define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16 (0x2 << 12) 57 #define IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32 (0x3 << 12) 58 59 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4 (0x0 << 29) 60 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8 (0x1 << 29) 61 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16 (0x2 << 29) 62 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32 (0x3 << 29) 63 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64 (0x4 << 29) 64 #define IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128 (0x5 << 29) 65 66 #define IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN BIT(31) 67 #define IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN BIT(1) 68 #define IMX7D_REG_ADC_ADC_CFG_ADC_EN BIT(0) 69 70 #define IMX7D_REG_ADC_INT_CHA_COV_INT_EN BIT(8) 71 #define IMX7D_REG_ADC_INT_CHB_COV_INT_EN BIT(9) 72 #define IMX7D_REG_ADC_INT_CHC_COV_INT_EN BIT(10) 73 #define IMX7D_REG_ADC_INT_CHD_COV_INT_EN BIT(11) 74 #define IMX7D_REG_ADC_INT_CHANNEL_INT_EN \ 75 (IMX7D_REG_ADC_INT_CHA_COV_INT_EN | \ 76 IMX7D_REG_ADC_INT_CHB_COV_INT_EN | \ 77 IMX7D_REG_ADC_INT_CHC_COV_INT_EN | \ 78 IMX7D_REG_ADC_INT_CHD_COV_INT_EN) 79 #define IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS 0xf00 80 #define IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT 0xf0000 81 82 #define IMX7D_ADC_TIMEOUT msecs_to_jiffies(100) 83 #define IMX7D_ADC_INPUT_CLK 24000000 84 85 enum imx7d_adc_clk_pre_div { 86 IMX7D_ADC_ANALOG_CLK_PRE_DIV_4, 87 IMX7D_ADC_ANALOG_CLK_PRE_DIV_8, 88 IMX7D_ADC_ANALOG_CLK_PRE_DIV_16, 89 IMX7D_ADC_ANALOG_CLK_PRE_DIV_32, 90 IMX7D_ADC_ANALOG_CLK_PRE_DIV_64, 91 IMX7D_ADC_ANALOG_CLK_PRE_DIV_128, 92 }; 93 94 enum imx7d_adc_average_num { 95 IMX7D_ADC_AVERAGE_NUM_4, 96 IMX7D_ADC_AVERAGE_NUM_8, 97 IMX7D_ADC_AVERAGE_NUM_16, 98 IMX7D_ADC_AVERAGE_NUM_32, 99 }; 100 101 struct imx7d_adc_feature { 102 enum imx7d_adc_clk_pre_div clk_pre_div; 103 enum imx7d_adc_average_num avg_num; 104 105 u32 core_time_unit; /* impact the sample rate */ 106 }; 107 108 struct imx7d_adc { 109 struct device *dev; 110 void __iomem *regs; 111 struct clk *clk; 112 /* lock to protect against multiple access to the device */ 113 struct mutex lock; 114 u32 vref_uv; 115 u32 value; 116 u32 channel; 117 u32 pre_div_num; 118 119 struct regulator *vref; 120 struct imx7d_adc_feature adc_feature; 121 122 struct completion completion; 123 }; 124 125 struct imx7d_adc_analogue_core_clk { 126 u32 pre_div; 127 u32 reg_config; 128 }; 129 130 #define IMX7D_ADC_ANALOGUE_CLK_CONFIG(_pre_div, _reg_conf) { \ 131 .pre_div = (_pre_div), \ 132 .reg_config = (_reg_conf), \ 133 } 134 135 static const struct imx7d_adc_analogue_core_clk imx7d_adc_analogue_clk[] = { 136 IMX7D_ADC_ANALOGUE_CLK_CONFIG(4, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_4), 137 IMX7D_ADC_ANALOGUE_CLK_CONFIG(8, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_8), 138 IMX7D_ADC_ANALOGUE_CLK_CONFIG(16, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_16), 139 IMX7D_ADC_ANALOGUE_CLK_CONFIG(32, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_32), 140 IMX7D_ADC_ANALOGUE_CLK_CONFIG(64, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_64), 141 IMX7D_ADC_ANALOGUE_CLK_CONFIG(128, IMX7D_REG_ADC_TIMER_UNIT_PRE_DIV_128), 142 }; 143 144 #define IMX7D_ADC_CHAN(_idx) { \ 145 .type = IIO_VOLTAGE, \ 146 .indexed = 1, \ 147 .channel = (_idx), \ 148 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ 149 .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 150 BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 151 } 152 153 static const struct iio_chan_spec imx7d_adc_iio_channels[] = { 154 IMX7D_ADC_CHAN(0), 155 IMX7D_ADC_CHAN(1), 156 IMX7D_ADC_CHAN(2), 157 IMX7D_ADC_CHAN(3), 158 IMX7D_ADC_CHAN(4), 159 IMX7D_ADC_CHAN(5), 160 IMX7D_ADC_CHAN(6), 161 IMX7D_ADC_CHAN(7), 162 IMX7D_ADC_CHAN(8), 163 IMX7D_ADC_CHAN(9), 164 IMX7D_ADC_CHAN(10), 165 IMX7D_ADC_CHAN(11), 166 IMX7D_ADC_CHAN(12), 167 IMX7D_ADC_CHAN(13), 168 IMX7D_ADC_CHAN(14), 169 IMX7D_ADC_CHAN(15), 170 }; 171 172 static const u32 imx7d_adc_average_num[] = { 173 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_4, 174 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_8, 175 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_16, 176 IMX7D_REG_ADC_CH_CFG2_AVG_NUM_32, 177 }; 178 179 static void imx7d_adc_feature_config(struct imx7d_adc *info) 180 { 181 info->adc_feature.clk_pre_div = IMX7D_ADC_ANALOG_CLK_PRE_DIV_4; 182 info->adc_feature.avg_num = IMX7D_ADC_AVERAGE_NUM_32; 183 info->adc_feature.core_time_unit = 1; 184 } 185 186 static void imx7d_adc_sample_rate_set(struct imx7d_adc *info) 187 { 188 struct imx7d_adc_feature *adc_feature = &info->adc_feature; 189 struct imx7d_adc_analogue_core_clk adc_analogure_clk; 190 u32 i; 191 u32 tmp_cfg1; 192 u32 sample_rate = 0; 193 194 /* 195 * Before sample set, disable channel A,B,C,D. Here we 196 * clear the bit 31 of register REG_ADC_CH_A\B\C\D_CFG1. 197 */ 198 for (i = 0; i < 4; i++) { 199 tmp_cfg1 = 200 readl(info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET); 201 tmp_cfg1 &= ~IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN; 202 writel(tmp_cfg1, 203 info->regs + i * IMX7D_EACH_CHANNEL_REG_OFFSET); 204 } 205 206 adc_analogure_clk = imx7d_adc_analogue_clk[adc_feature->clk_pre_div]; 207 sample_rate |= adc_analogure_clk.reg_config; 208 info->pre_div_num = adc_analogure_clk.pre_div; 209 210 sample_rate |= adc_feature->core_time_unit; 211 writel(sample_rate, info->regs + IMX7D_REG_ADC_TIMER_UNIT); 212 } 213 214 static void imx7d_adc_hw_init(struct imx7d_adc *info) 215 { 216 u32 cfg; 217 218 /* power up and enable adc analogue core */ 219 cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG); 220 cfg &= ~(IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN | 221 IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN); 222 cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_EN; 223 writel(cfg, info->regs + IMX7D_REG_ADC_ADC_CFG); 224 225 /* enable channel A,B,C,D interrupt */ 226 writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN, 227 info->regs + IMX7D_REG_ADC_INT_SIG_EN); 228 writel(IMX7D_REG_ADC_INT_CHANNEL_INT_EN, 229 info->regs + IMX7D_REG_ADC_INT_EN); 230 231 imx7d_adc_sample_rate_set(info); 232 } 233 234 static void imx7d_adc_channel_set(struct imx7d_adc *info) 235 { 236 u32 cfg1 = 0; 237 u32 cfg2; 238 u32 channel; 239 240 channel = info->channel; 241 242 /* the channel choose single conversion, and enable average mode */ 243 cfg1 |= (IMX7D_REG_ADC_CH_CFG1_CHANNEL_EN | 244 IMX7D_REG_ADC_CH_CFG1_CHANNEL_SINGLE | 245 IMX7D_REG_ADC_CH_CFG1_CHANNEL_AVG_EN); 246 247 /* 248 * physical channel 0 chose logical channel A 249 * physical channel 1 chose logical channel B 250 * physical channel 2 chose logical channel C 251 * physical channel 3 chose logical channel D 252 */ 253 cfg1 |= IMX7D_REG_ADC_CH_CFG1_CHANNEL_SEL(channel); 254 255 /* 256 * read register REG_ADC_CH_A\B\C\D_CFG2, according to the 257 * channel chosen 258 */ 259 cfg2 = readl(info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel + 260 IMX7D_REG_ADC_CHANNEL_CFG2_BASE); 261 262 cfg2 |= imx7d_adc_average_num[info->adc_feature.avg_num]; 263 264 /* 265 * write the register REG_ADC_CH_A\B\C\D_CFG2, according to 266 * the channel chosen 267 */ 268 writel(cfg2, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel + 269 IMX7D_REG_ADC_CHANNEL_CFG2_BASE); 270 writel(cfg1, info->regs + IMX7D_EACH_CHANNEL_REG_OFFSET * channel); 271 } 272 273 static u32 imx7d_adc_get_sample_rate(struct imx7d_adc *info) 274 { 275 u32 analogue_core_clk; 276 u32 core_time_unit = info->adc_feature.core_time_unit; 277 u32 tmp; 278 279 analogue_core_clk = IMX7D_ADC_INPUT_CLK / info->pre_div_num; 280 tmp = (core_time_unit + 1) * 6; 281 282 return analogue_core_clk / tmp; 283 } 284 285 static int imx7d_adc_read_raw(struct iio_dev *indio_dev, 286 struct iio_chan_spec const *chan, 287 int *val, 288 int *val2, 289 long mask) 290 { 291 struct imx7d_adc *info = iio_priv(indio_dev); 292 293 u32 channel; 294 long ret; 295 296 switch (mask) { 297 case IIO_CHAN_INFO_RAW: 298 mutex_lock(&info->lock); 299 reinit_completion(&info->completion); 300 301 channel = chan->channel & 0x03; 302 info->channel = channel; 303 imx7d_adc_channel_set(info); 304 305 ret = wait_for_completion_interruptible_timeout 306 (&info->completion, IMX7D_ADC_TIMEOUT); 307 if (ret == 0) { 308 mutex_unlock(&info->lock); 309 return -ETIMEDOUT; 310 } 311 if (ret < 0) { 312 mutex_unlock(&info->lock); 313 return ret; 314 } 315 316 *val = info->value; 317 mutex_unlock(&info->lock); 318 return IIO_VAL_INT; 319 320 case IIO_CHAN_INFO_SCALE: 321 info->vref_uv = regulator_get_voltage(info->vref); 322 *val = info->vref_uv / 1000; 323 *val2 = 12; 324 return IIO_VAL_FRACTIONAL_LOG2; 325 326 case IIO_CHAN_INFO_SAMP_FREQ: 327 *val = imx7d_adc_get_sample_rate(info); 328 return IIO_VAL_INT; 329 330 default: 331 return -EINVAL; 332 } 333 } 334 335 static int imx7d_adc_read_data(struct imx7d_adc *info) 336 { 337 u32 channel; 338 u32 value; 339 340 channel = info->channel & 0x03; 341 342 /* 343 * channel A and B conversion result share one register, 344 * bit[27~16] is the channel B conversion result, 345 * bit[11~0] is the channel A conversion result. 346 * channel C and D is the same. 347 */ 348 if (channel < 2) 349 value = readl(info->regs + IMX7D_REG_ADC_CHA_B_CNV_RSLT); 350 else 351 value = readl(info->regs + IMX7D_REG_ADC_CHC_D_CNV_RSLT); 352 if (channel & 0x1) /* channel B or D */ 353 value = (value >> 16) & 0xFFF; 354 else /* channel A or C */ 355 value &= 0xFFF; 356 357 return value; 358 } 359 360 static irqreturn_t imx7d_adc_isr(int irq, void *dev_id) 361 { 362 struct imx7d_adc *info = dev_id; 363 int status; 364 365 status = readl(info->regs + IMX7D_REG_ADC_INT_STATUS); 366 if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS) { 367 info->value = imx7d_adc_read_data(info); 368 complete(&info->completion); 369 370 /* 371 * The register IMX7D_REG_ADC_INT_STATUS can't clear 372 * itself after read operation, need software to write 373 * 0 to the related bit. Here we clear the channel A/B/C/D 374 * conversion finished flag. 375 */ 376 status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_INT_STATUS; 377 writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS); 378 } 379 380 /* 381 * If the channel A/B/C/D conversion timeout, report it and clear these 382 * timeout flags. 383 */ 384 if (status & IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT) { 385 dev_err(info->dev, 386 "ADC got conversion time out interrupt: 0x%08x\n", 387 status); 388 status &= ~IMX7D_REG_ADC_INT_STATUS_CHANNEL_CONV_TIME_OUT; 389 writel(status, info->regs + IMX7D_REG_ADC_INT_STATUS); 390 } 391 392 return IRQ_HANDLED; 393 } 394 395 static int imx7d_adc_reg_access(struct iio_dev *indio_dev, 396 unsigned reg, unsigned writeval, 397 unsigned *readval) 398 { 399 struct imx7d_adc *info = iio_priv(indio_dev); 400 401 if (!readval || reg % 4 || reg > IMX7D_REG_ADC_ADC_CFG) 402 return -EINVAL; 403 404 *readval = readl(info->regs + reg); 405 406 return 0; 407 } 408 409 static const struct iio_info imx7d_adc_iio_info = { 410 .read_raw = &imx7d_adc_read_raw, 411 .debugfs_reg_access = &imx7d_adc_reg_access, 412 }; 413 414 static const struct of_device_id imx7d_adc_match[] = { 415 { .compatible = "fsl,imx7d-adc", }, 416 { /* sentinel */ } 417 }; 418 MODULE_DEVICE_TABLE(of, imx7d_adc_match); 419 420 static void imx7d_adc_power_down(struct imx7d_adc *info) 421 { 422 u32 adc_cfg; 423 424 adc_cfg = readl(info->regs + IMX7D_REG_ADC_ADC_CFG); 425 adc_cfg |= IMX7D_REG_ADC_ADC_CFG_ADC_CLK_DOWN | 426 IMX7D_REG_ADC_ADC_CFG_ADC_POWER_DOWN; 427 adc_cfg &= ~IMX7D_REG_ADC_ADC_CFG_ADC_EN; 428 writel(adc_cfg, info->regs + IMX7D_REG_ADC_ADC_CFG); 429 } 430 431 static int imx7d_adc_enable(struct device *dev) 432 { 433 struct iio_dev *indio_dev = dev_get_drvdata(dev); 434 struct imx7d_adc *info = iio_priv(indio_dev); 435 int ret; 436 437 ret = regulator_enable(info->vref); 438 if (ret) { 439 dev_err(info->dev, 440 "Can't enable adc reference top voltage, err = %d\n", 441 ret); 442 return ret; 443 } 444 445 ret = clk_prepare_enable(info->clk); 446 if (ret) { 447 dev_err(info->dev, 448 "Could not prepare or enable clock.\n"); 449 regulator_disable(info->vref); 450 return ret; 451 } 452 453 imx7d_adc_hw_init(info); 454 455 return 0; 456 } 457 458 static int imx7d_adc_disable(struct device *dev) 459 { 460 struct iio_dev *indio_dev = dev_get_drvdata(dev); 461 struct imx7d_adc *info = iio_priv(indio_dev); 462 463 imx7d_adc_power_down(info); 464 465 clk_disable_unprepare(info->clk); 466 regulator_disable(info->vref); 467 468 return 0; 469 } 470 471 static void __imx7d_adc_disable(void *data) 472 { 473 imx7d_adc_disable(data); 474 } 475 476 static int imx7d_adc_probe(struct platform_device *pdev) 477 { 478 struct imx7d_adc *info; 479 struct iio_dev *indio_dev; 480 struct device *dev = &pdev->dev; 481 int irq; 482 int ret; 483 484 indio_dev = devm_iio_device_alloc(dev, sizeof(*info)); 485 if (!indio_dev) { 486 dev_err(&pdev->dev, "Failed allocating iio device\n"); 487 return -ENOMEM; 488 } 489 490 info = iio_priv(indio_dev); 491 info->dev = dev; 492 493 info->regs = devm_platform_ioremap_resource(pdev, 0); 494 if (IS_ERR(info->regs)) 495 return PTR_ERR(info->regs); 496 497 irq = platform_get_irq(pdev, 0); 498 if (irq < 0) 499 return dev_err_probe(dev, irq, "Failed getting irq\n"); 500 501 info->clk = devm_clk_get(dev, "adc"); 502 if (IS_ERR(info->clk)) 503 return dev_err_probe(dev, PTR_ERR(info->clk), "Failed getting clock\n"); 504 505 info->vref = devm_regulator_get(dev, "vref"); 506 if (IS_ERR(info->vref)) 507 return dev_err_probe(dev, PTR_ERR(info->vref), 508 "Failed getting reference voltage\n"); 509 510 platform_set_drvdata(pdev, indio_dev); 511 512 init_completion(&info->completion); 513 514 indio_dev->name = dev_name(dev); 515 indio_dev->info = &imx7d_adc_iio_info; 516 indio_dev->modes = INDIO_DIRECT_MODE; 517 indio_dev->channels = imx7d_adc_iio_channels; 518 indio_dev->num_channels = ARRAY_SIZE(imx7d_adc_iio_channels); 519 520 ret = devm_request_irq(dev, irq, imx7d_adc_isr, 0, dev_name(dev), info); 521 if (ret < 0) { 522 dev_err(dev, "Failed requesting irq, irq = %d\n", irq); 523 return ret; 524 } 525 526 imx7d_adc_feature_config(info); 527 528 ret = imx7d_adc_enable(dev); 529 if (ret) 530 return ret; 531 532 ret = devm_add_action_or_reset(dev, __imx7d_adc_disable, dev); 533 if (ret) 534 return ret; 535 536 mutex_init(&info->lock); 537 538 ret = devm_iio_device_register(dev, indio_dev); 539 if (ret) { 540 dev_err(&pdev->dev, "Couldn't register the device.\n"); 541 return ret; 542 } 543 544 return 0; 545 } 546 547 static DEFINE_SIMPLE_DEV_PM_OPS(imx7d_adc_pm_ops, imx7d_adc_disable, 548 imx7d_adc_enable); 549 550 static struct platform_driver imx7d_adc_driver = { 551 .probe = imx7d_adc_probe, 552 .driver = { 553 .name = "imx7d_adc", 554 .of_match_table = imx7d_adc_match, 555 .pm = pm_sleep_ptr(&imx7d_adc_pm_ops), 556 }, 557 }; 558 559 module_platform_driver(imx7d_adc_driver); 560 561 MODULE_AUTHOR("Haibo Chen <haibo.chen@freescale.com>"); 562 MODULE_DESCRIPTION("Freescale IMX7D ADC driver"); 563 MODULE_LICENSE("GPL v2"); 564