829 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * max6650.c - Part of lm_sensors, Linux kernel modules for hardware4 * monitoring.5 *6 * (C) 2007 by Hans J. Koch <hjk@hansjkoch.de>7 *8 * based on code written by John Morris <john.morris@spirentcom.com>9 * Copyright (c) 2003 Spirent Communications10 * and Claus Gindhart <claus.gindhart@kontron.com>11 *12 * This module has only been tested with the MAX6650 chip. It should13 * also work with the MAX6651. It does not distinguish max6650 and max665114 * chips.15 *16 * The datasheet was last seen at:17 *18 * http://pdfserv.maxim-ic.com/en/ds/MAX6650-MAX6651.pdf19 */20 21#include <linux/module.h>22#include <linux/init.h>23#include <linux/slab.h>24#include <linux/jiffies.h>25#include <linux/i2c.h>26#include <linux/hwmon.h>27#include <linux/hwmon-sysfs.h>28#include <linux/err.h>29#include <linux/of.h>30#include <linux/thermal.h>31 32/*33 * Insmod parameters34 */35 36/* fan_voltage: 5=5V fan, 12=12V fan, 0=don't change */37static int fan_voltage;38/* prescaler: Possible values are 1, 2, 4, 8, 16 or 0 for don't change */39static int prescaler;40/* clock: The clock frequency of the chip (max6651 can be clocked externally) */41static int clock = 254000;42 43module_param(fan_voltage, int, 0444);44module_param(prescaler, int, 0444);45module_param(clock, int, 0444);46 47/*48 * MAX 6650/6651 registers49 */50 51#define MAX6650_REG_SPEED 0x0052#define MAX6650_REG_CONFIG 0x0253#define MAX6650_REG_GPIO_DEF 0x0454#define MAX6650_REG_DAC 0x0655#define MAX6650_REG_ALARM_EN 0x0856#define MAX6650_REG_ALARM 0x0A57#define MAX6650_REG_TACH0 0x0C58#define MAX6650_REG_TACH1 0x0E59#define MAX6650_REG_TACH2 0x1060#define MAX6650_REG_TACH3 0x1261#define MAX6650_REG_GPIO_STAT 0x1462#define MAX6650_REG_COUNT 0x1663 64/*65 * Config register bits66 */67 68#define MAX6650_CFG_V12 0x0869#define MAX6650_CFG_PRESCALER_MASK 0x0770#define MAX6650_CFG_PRESCALER_2 0x0171#define MAX6650_CFG_PRESCALER_4 0x0272#define MAX6650_CFG_PRESCALER_8 0x0373#define MAX6650_CFG_PRESCALER_16 0x0474#define MAX6650_CFG_MODE_MASK 0x3075#define MAX6650_CFG_MODE_ON 0x0076#define MAX6650_CFG_MODE_OFF 0x1077#define MAX6650_CFG_MODE_CLOSED_LOOP 0x2078#define MAX6650_CFG_MODE_OPEN_LOOP 0x3079#define MAX6650_COUNT_MASK 0x0380 81/*82 * Alarm status register bits83 */84 85#define MAX6650_ALRM_MAX 0x0186#define MAX6650_ALRM_MIN 0x0287#define MAX6650_ALRM_TACH 0x0488#define MAX6650_ALRM_GPIO1 0x0889#define MAX6650_ALRM_GPIO2 0x1090 91/* Minimum and maximum values of the FAN-RPM */92#define FAN_RPM_MIN 24093#define FAN_RPM_MAX 3000094 95#define DIV_FROM_REG(reg) (1 << ((reg) & 7))96#define DAC_LIMIT(v12) ((v12) ? 180 : 76)97 98/*99 * Client data (each client gets its own)100 */101 102struct max6650_data {103 struct i2c_client *client;104 struct mutex update_lock; /* protect alarm register updates */105 int nr_fans;106 bool valid; /* false until following fields are valid */107 unsigned long last_updated; /* in jiffies */108 109 /* register values */110 u8 speed;111 u8 config;112 u8 tach[4];113 u8 count;114 u8 dac;115 u8 alarm;116 u8 alarm_en;117 unsigned long cooling_dev_state;118};119 120static const u8 tach_reg[] = {121 MAX6650_REG_TACH0,122 MAX6650_REG_TACH1,123 MAX6650_REG_TACH2,124 MAX6650_REG_TACH3,125};126 127static const struct of_device_id __maybe_unused max6650_dt_match[] = {128 {129 .compatible = "maxim,max6650",130 .data = (void *)1131 },132 {133 .compatible = "maxim,max6651",134 .data = (void *)4135 },136 { },137};138MODULE_DEVICE_TABLE(of, max6650_dt_match);139 140static int dac_to_pwm(int dac, bool v12)141{142 /*143 * Useful range for dac is 0-180 for 12V fans and 0-76 for 5V fans.144 * Lower DAC values mean higher speeds.145 */146 return clamp_val(255 - (255 * dac) / DAC_LIMIT(v12), 0, 255);147}148 149static u8 pwm_to_dac(unsigned int pwm, bool v12)150{151 int limit = DAC_LIMIT(v12);152 153 return limit - (limit * pwm) / 255;154}155 156static struct max6650_data *max6650_update_device(struct device *dev)157{158 struct max6650_data *data = dev_get_drvdata(dev);159 struct i2c_client *client = data->client;160 int reg, err = 0;161 int i;162 163 mutex_lock(&data->update_lock);164 165 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {166 for (i = 0; i < data->nr_fans; i++) {167 reg = i2c_smbus_read_byte_data(client, tach_reg[i]);168 if (reg < 0) {169 err = reg;170 goto error;171 }172 data->tach[i] = reg;173 }174 175 /*176 * Alarms are cleared on read in case the condition that177 * caused the alarm is removed. Keep the value latched here178 * for providing the register through different alarm files.179 */180 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM);181 if (reg < 0) {182 err = reg;183 goto error;184 }185 data->alarm |= reg;186 data->last_updated = jiffies;187 data->valid = true;188 }189 190error:191 mutex_unlock(&data->update_lock);192 if (err)193 data = ERR_PTR(err);194 return data;195}196 197/*198 * Change the operating mode of the chip (if needed).199 * mode is one of the MAX6650_CFG_MODE_* values.200 */201static int max6650_set_operating_mode(struct max6650_data *data, u8 mode)202{203 int result;204 u8 config = data->config;205 206 if (mode == (config & MAX6650_CFG_MODE_MASK))207 return 0;208 209 config = (config & ~MAX6650_CFG_MODE_MASK) | mode;210 211 result = i2c_smbus_write_byte_data(data->client, MAX6650_REG_CONFIG,212 config);213 if (result < 0)214 return result;215 216 data->config = config;217 218 return 0;219}220 221/*222 * Set the fan speed to the specified RPM (or read back the RPM setting).223 * This works in closed loop mode only. Use pwm1 for open loop speed setting.224 *225 * The MAX6650/1 will automatically control fan speed when in closed loop226 * mode.227 *228 * Assumptions:229 *230 * 1) The MAX6650/1 internal 254kHz clock frequency is set correctly. Use231 * the clock module parameter if you need to fine tune this.232 *233 * 2) The prescaler (low three bits of the config register) has already234 * been set to an appropriate value. Use the prescaler module parameter235 * if your BIOS doesn't initialize the chip properly.236 *237 * The relevant equations are given on pages 21 and 22 of the datasheet.238 *239 * From the datasheet, the relevant equation when in regulation is:240 *241 * [fCLK / (128 x (KTACH + 1))] = 2 x FanSpeed / KSCALE242 *243 * where:244 *245 * fCLK is the oscillator frequency (either the 254kHz internal246 * oscillator or the externally applied clock)247 *248 * KTACH is the value in the speed register249 *250 * FanSpeed is the speed of the fan in rps251 *252 * KSCALE is the prescaler value (1, 2, 4, 8, or 16)253 *254 * When reading, we need to solve for FanSpeed. When writing, we need to255 * solve for KTACH.256 *257 * Note: this tachometer is completely separate from the tachometers258 * used to measure the fan speeds. Only one fan's speed (fan1) is259 * controlled.260 */261 262static int max6650_set_target(struct max6650_data *data, unsigned long rpm)263{264 int kscale, ktach;265 266 if (rpm == 0)267 return max6650_set_operating_mode(data, MAX6650_CFG_MODE_OFF);268 269 rpm = clamp_val(rpm, FAN_RPM_MIN, FAN_RPM_MAX);270 271 /*272 * Divide the required speed by 60 to get from rpm to rps, then273 * use the datasheet equation:274 *275 * KTACH = [(fCLK x KSCALE) / (256 x FanSpeed)] - 1276 */277 278 kscale = DIV_FROM_REG(data->config);279 ktach = ((clock * kscale) / (256 * rpm / 60)) - 1;280 if (ktach < 0)281 ktach = 0;282 if (ktach > 255)283 ktach = 255;284 data->speed = ktach;285 286 return i2c_smbus_write_byte_data(data->client, MAX6650_REG_SPEED,287 data->speed);288}289 290/*291 * Get gpio alarm status:292 * Possible values:293 * 0 = no alarm294 * 1 = alarm295 */296 297static ssize_t alarm_show(struct device *dev,298 struct device_attribute *devattr, char *buf)299{300 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);301 struct max6650_data *data = max6650_update_device(dev);302 bool alarm;303 304 if (IS_ERR(data))305 return PTR_ERR(data);306 307 alarm = data->alarm & attr->index;308 if (alarm) {309 mutex_lock(&data->update_lock);310 data->alarm &= ~attr->index;311 data->valid = false;312 mutex_unlock(&data->update_lock);313 }314 315 return sprintf(buf, "%d\n", alarm);316}317 318static SENSOR_DEVICE_ATTR_RO(gpio1_alarm, alarm, MAX6650_ALRM_GPIO1);319static SENSOR_DEVICE_ATTR_RO(gpio2_alarm, alarm, MAX6650_ALRM_GPIO2);320 321static umode_t max6650_attrs_visible(struct kobject *kobj, struct attribute *a,322 int n)323{324 struct device *dev = kobj_to_dev(kobj);325 struct max6650_data *data = dev_get_drvdata(dev);326 struct device_attribute *devattr;327 328 /*329 * Hide the alarms that have not been enabled by the firmware330 */331 332 devattr = container_of(a, struct device_attribute, attr);333 if (devattr == &sensor_dev_attr_gpio1_alarm.dev_attr ||334 devattr == &sensor_dev_attr_gpio2_alarm.dev_attr) {335 if (!(data->alarm_en & to_sensor_dev_attr(devattr)->index))336 return 0;337 }338 339 return a->mode;340}341 342static struct attribute *max6650_attrs[] = {343 &sensor_dev_attr_gpio1_alarm.dev_attr.attr,344 &sensor_dev_attr_gpio2_alarm.dev_attr.attr,345 NULL346};347 348static const struct attribute_group max6650_group = {349 .attrs = max6650_attrs,350 .is_visible = max6650_attrs_visible,351};352 353static const struct attribute_group *max6650_groups[] = {354 &max6650_group,355 NULL356};357 358static int max6650_init_client(struct max6650_data *data,359 struct i2c_client *client)360{361 struct device *dev = &client->dev;362 int reg;363 int err;364 u32 voltage;365 u32 prescale;366 u32 target_rpm;367 368 if (of_property_read_u32(dev->of_node, "maxim,fan-microvolt",369 &voltage))370 voltage = fan_voltage;371 else372 voltage /= 1000000; /* Microvolts to volts */373 if (of_property_read_u32(dev->of_node, "maxim,fan-prescale",374 &prescale))375 prescale = prescaler;376 377 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_CONFIG);378 if (reg < 0) {379 dev_err(dev, "Error reading config register, aborting.\n");380 return reg;381 }382 383 switch (voltage) {384 case 0:385 break;386 case 5:387 reg &= ~MAX6650_CFG_V12;388 break;389 case 12:390 reg |= MAX6650_CFG_V12;391 break;392 default:393 dev_err(dev, "illegal value for fan_voltage (%d)\n", voltage);394 }395 396 switch (prescale) {397 case 0:398 break;399 case 1:400 reg &= ~MAX6650_CFG_PRESCALER_MASK;401 break;402 case 2:403 reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)404 | MAX6650_CFG_PRESCALER_2;405 break;406 case 4:407 reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)408 | MAX6650_CFG_PRESCALER_4;409 break;410 case 8:411 reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)412 | MAX6650_CFG_PRESCALER_8;413 break;414 case 16:415 reg = (reg & ~MAX6650_CFG_PRESCALER_MASK)416 | MAX6650_CFG_PRESCALER_16;417 break;418 default:419 dev_err(dev, "illegal value for prescaler (%d)\n", prescale);420 }421 422 dev_info(dev, "Fan voltage: %dV, prescaler: %d.\n",423 (reg & MAX6650_CFG_V12) ? 12 : 5,424 1 << (reg & MAX6650_CFG_PRESCALER_MASK));425 426 err = i2c_smbus_write_byte_data(client, MAX6650_REG_CONFIG, reg);427 if (err) {428 dev_err(dev, "Config write error, aborting.\n");429 return err;430 }431 data->config = reg;432 433 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_SPEED);434 if (reg < 0) {435 dev_err(dev, "Failed to read speed register, aborting.\n");436 return reg;437 }438 data->speed = reg;439 440 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_DAC);441 if (reg < 0) {442 dev_err(dev, "Failed to read DAC register, aborting.\n");443 return reg;444 }445 data->dac = reg;446 447 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_COUNT);448 if (reg < 0) {449 dev_err(dev, "Failed to read count register, aborting.\n");450 return reg;451 }452 data->count = reg;453 454 reg = i2c_smbus_read_byte_data(client, MAX6650_REG_ALARM_EN);455 if (reg < 0) {456 dev_err(dev, "Failed to read alarm configuration, aborting.\n");457 return reg;458 }459 data->alarm_en = reg;460 461 if (!of_property_read_u32(client->dev.of_node, "maxim,fan-target-rpm",462 &target_rpm)) {463 max6650_set_target(data, target_rpm);464 max6650_set_operating_mode(data, MAX6650_CFG_MODE_CLOSED_LOOP);465 }466 467 return 0;468}469 470static int max6650_get_max_state(struct thermal_cooling_device *cdev,471 unsigned long *state)472{473 *state = 255;474 475 return 0;476}477 478static int max6650_get_cur_state(struct thermal_cooling_device *cdev,479 unsigned long *state)480{481 struct max6650_data *data = cdev->devdata;482 483 *state = data->cooling_dev_state;484 485 return 0;486}487 488static int max6650_set_cur_state(struct thermal_cooling_device *cdev,489 unsigned long state)490{491 struct max6650_data *data = cdev->devdata;492 struct i2c_client *client = data->client;493 int err;494 495 state = clamp_val(state, 0, 255);496 497 mutex_lock(&data->update_lock);498 499 data->dac = pwm_to_dac(state, data->config & MAX6650_CFG_V12);500 err = i2c_smbus_write_byte_data(client, MAX6650_REG_DAC, data->dac);501 if (!err) {502 max6650_set_operating_mode(data, state ?503 MAX6650_CFG_MODE_OPEN_LOOP :504 MAX6650_CFG_MODE_OFF);505 data->cooling_dev_state = state;506 }507 508 mutex_unlock(&data->update_lock);509 510 return err;511}512 513static const struct thermal_cooling_device_ops max6650_cooling_ops = {514 .get_max_state = max6650_get_max_state,515 .get_cur_state = max6650_get_cur_state,516 .set_cur_state = max6650_set_cur_state,517};518 519static int max6650_read(struct device *dev, enum hwmon_sensor_types type,520 u32 attr, int channel, long *val)521{522 struct max6650_data *data = max6650_update_device(dev);523 int mode;524 525 if (IS_ERR(data))526 return PTR_ERR(data);527 528 switch (type) {529 case hwmon_pwm:530 switch (attr) {531 case hwmon_pwm_input:532 *val = dac_to_pwm(data->dac,533 data->config & MAX6650_CFG_V12);534 break;535 case hwmon_pwm_enable:536 /*537 * Possible values:538 * 0 = Fan always on539 * 1 = Open loop, Voltage is set according to speed,540 * not regulated.541 * 2 = Closed loop, RPM for all fans regulated by fan1542 * tachometer543 * 3 = Fan off544 */545 mode = (data->config & MAX6650_CFG_MODE_MASK) >> 4;546 *val = (4 - mode) & 3; /* {0 1 2 3} -> {0 3 2 1} */547 break;548 default:549 return -EOPNOTSUPP;550 }551 break;552 case hwmon_fan:553 switch (attr) {554 case hwmon_fan_input:555 /*556 * Calculation details:557 *558 * Each tachometer counts over an interval given by the559 * "count" register (0.25, 0.5, 1 or 2 seconds).560 * The driver assumes that the fans produce two pulses561 * per revolution (this seems to be the most common).562 */563 *val = DIV_ROUND_CLOSEST(data->tach[channel] * 120,564 DIV_FROM_REG(data->count));565 break;566 case hwmon_fan_div:567 *val = DIV_FROM_REG(data->count);568 break;569 case hwmon_fan_target:570 /*571 * Use the datasheet equation:572 * FanSpeed = KSCALE x fCLK / [256 x (KTACH + 1)]573 * then multiply by 60 to give rpm.574 */575 *val = 60 * DIV_FROM_REG(data->config) * clock /576 (256 * (data->speed + 1));577 break;578 case hwmon_fan_min_alarm:579 *val = !!(data->alarm & MAX6650_ALRM_MIN);580 data->alarm &= ~MAX6650_ALRM_MIN;581 data->valid = false;582 break;583 case hwmon_fan_max_alarm:584 *val = !!(data->alarm & MAX6650_ALRM_MAX);585 data->alarm &= ~MAX6650_ALRM_MAX;586 data->valid = false;587 break;588 case hwmon_fan_fault:589 *val = !!(data->alarm & MAX6650_ALRM_TACH);590 data->alarm &= ~MAX6650_ALRM_TACH;591 data->valid = false;592 break;593 default:594 return -EOPNOTSUPP;595 }596 break;597 default:598 return -EOPNOTSUPP;599 }600 return 0;601}602 603static const u8 max6650_pwm_modes[] = {604 MAX6650_CFG_MODE_ON,605 MAX6650_CFG_MODE_OPEN_LOOP,606 MAX6650_CFG_MODE_CLOSED_LOOP,607 MAX6650_CFG_MODE_OFF,608};609 610static int max6650_write(struct device *dev, enum hwmon_sensor_types type,611 u32 attr, int channel, long val)612{613 struct max6650_data *data = dev_get_drvdata(dev);614 int ret = 0;615 u8 reg;616 617 mutex_lock(&data->update_lock);618 619 switch (type) {620 case hwmon_pwm:621 switch (attr) {622 case hwmon_pwm_input:623 reg = pwm_to_dac(clamp_val(val, 0, 255),624 data->config & MAX6650_CFG_V12);625 ret = i2c_smbus_write_byte_data(data->client,626 MAX6650_REG_DAC, reg);627 if (ret)628 break;629 data->dac = reg;630 break;631 case hwmon_pwm_enable:632 if (val < 0 || val >= ARRAY_SIZE(max6650_pwm_modes)) {633 ret = -EINVAL;634 break;635 }636 ret = max6650_set_operating_mode(data,637 max6650_pwm_modes[val]);638 break;639 default:640 ret = -EOPNOTSUPP;641 break;642 }643 break;644 case hwmon_fan:645 switch (attr) {646 case hwmon_fan_div:647 switch (val) {648 case 1:649 reg = 0;650 break;651 case 2:652 reg = 1;653 break;654 case 4:655 reg = 2;656 break;657 case 8:658 reg = 3;659 break;660 default:661 ret = -EINVAL;662 goto error;663 }664 ret = i2c_smbus_write_byte_data(data->client,665 MAX6650_REG_COUNT, reg);666 if (ret)667 break;668 data->count = reg;669 break;670 case hwmon_fan_target:671 if (val < 0) {672 ret = -EINVAL;673 break;674 }675 ret = max6650_set_target(data, val);676 break;677 default:678 ret = -EOPNOTSUPP;679 break;680 }681 break;682 default:683 ret = -EOPNOTSUPP;684 break;685 }686 687error:688 mutex_unlock(&data->update_lock);689 return ret;690}691 692static umode_t max6650_is_visible(const void *_data,693 enum hwmon_sensor_types type, u32 attr,694 int channel)695{696 const struct max6650_data *data = _data;697 698 if (channel && (channel >= data->nr_fans || type != hwmon_fan))699 return 0;700 701 switch (type) {702 case hwmon_fan:703 switch (attr) {704 case hwmon_fan_input:705 return 0444;706 case hwmon_fan_target:707 case hwmon_fan_div:708 return 0644;709 case hwmon_fan_min_alarm:710 if (data->alarm_en & MAX6650_ALRM_MIN)711 return 0444;712 break;713 case hwmon_fan_max_alarm:714 if (data->alarm_en & MAX6650_ALRM_MAX)715 return 0444;716 break;717 case hwmon_fan_fault:718 if (data->alarm_en & MAX6650_ALRM_TACH)719 return 0444;720 break;721 default:722 break;723 }724 break;725 case hwmon_pwm:726 switch (attr) {727 case hwmon_pwm_input:728 case hwmon_pwm_enable:729 return 0644;730 default:731 break;732 }733 break;734 default:735 break;736 }737 return 0;738}739 740static const struct hwmon_channel_info * const max6650_info[] = {741 HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT | HWMON_F_TARGET | HWMON_F_DIV |742 HWMON_F_MIN_ALARM | HWMON_F_MAX_ALARM |743 HWMON_F_FAULT,744 HWMON_F_INPUT, HWMON_F_INPUT, HWMON_F_INPUT),745 HWMON_CHANNEL_INFO(pwm, HWMON_PWM_INPUT | HWMON_PWM_ENABLE),746 NULL747};748 749static const struct hwmon_ops max6650_hwmon_ops = {750 .read = max6650_read,751 .write = max6650_write,752 .is_visible = max6650_is_visible,753};754 755static const struct hwmon_chip_info max6650_chip_info = {756 .ops = &max6650_hwmon_ops,757 .info = max6650_info,758};759 760static const struct i2c_device_id max6650_id[];761 762static int max6650_probe(struct i2c_client *client)763{764 struct thermal_cooling_device *cooling_dev;765 struct device *dev = &client->dev;766 struct max6650_data *data;767 struct device *hwmon_dev;768 int err;769 770 data = devm_kzalloc(dev, sizeof(struct max6650_data), GFP_KERNEL);771 if (!data)772 return -ENOMEM;773 774 data->client = client;775 i2c_set_clientdata(client, data);776 mutex_init(&data->update_lock);777 778 data->nr_fans = (uintptr_t)i2c_get_match_data(client);779 780 /*781 * Initialize the max6650 chip782 */783 err = max6650_init_client(data, client);784 if (err)785 return err;786 787 hwmon_dev = devm_hwmon_device_register_with_info(dev,788 client->name, data,789 &max6650_chip_info,790 max6650_groups);791 err = PTR_ERR_OR_ZERO(hwmon_dev);792 if (err)793 return err;794 795 if (IS_ENABLED(CONFIG_THERMAL)) {796 cooling_dev = devm_thermal_of_cooling_device_register(dev,797 dev->of_node, client->name,798 data, &max6650_cooling_ops);799 if (IS_ERR(cooling_dev)) {800 dev_warn(dev, "thermal cooling device register failed: %ld\n",801 PTR_ERR(cooling_dev));802 }803 }804 805 return 0;806}807 808static const struct i2c_device_id max6650_id[] = {809 { "max6650", 1 },810 { "max6651", 4 },811 { }812};813MODULE_DEVICE_TABLE(i2c, max6650_id);814 815static struct i2c_driver max6650_driver = {816 .driver = {817 .name = "max6650",818 .of_match_table = of_match_ptr(max6650_dt_match),819 },820 .probe = max6650_probe,821 .id_table = max6650_id,822};823 824module_i2c_driver(max6650_driver);825 826MODULE_AUTHOR("Hans J. Koch");827MODULE_DESCRIPTION("MAX6650 sensor driver");828MODULE_LICENSE("GPL");829