linux/drivers/hwmon/atxp1.c
<<
>>
Prefs
   1/*
   2 * atxp1.c - kernel module for setting CPU VID and general purpose
   3 *           I/Os using the Attansic ATXP1 chip.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation; either version 2 of the License, or
   8 * (at your option) any later version.
   9 *
  10 * This program is distributed in the hope that it will be useful,
  11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13 * GNU General Public License for more details.
  14 *
  15 * You should have received a copy of the GNU General Public License
  16 * along with this program; if not, write to the Free Software
  17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18 *
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/init.h>
  23#include <linux/module.h>
  24#include <linux/jiffies.h>
  25#include <linux/i2c.h>
  26#include <linux/hwmon.h>
  27#include <linux/hwmon-vid.h>
  28#include <linux/err.h>
  29#include <linux/mutex.h>
  30#include <linux/sysfs.h>
  31#include <linux/slab.h>
  32
  33MODULE_LICENSE("GPL");
  34MODULE_DESCRIPTION("System voltages control via Attansic ATXP1");
  35MODULE_VERSION("0.6.3");
  36MODULE_AUTHOR("Sebastian Witt <se.witt@gmx.net>");
  37
  38#define ATXP1_VID       0x00
  39#define ATXP1_CVID      0x01
  40#define ATXP1_GPIO1     0x06
  41#define ATXP1_GPIO2     0x0a
  42#define ATXP1_VIDENA    0x20
  43#define ATXP1_VIDMASK   0x1f
  44#define ATXP1_GPIO1MASK 0x0f
  45
  46static const unsigned short normal_i2c[] = { 0x37, 0x4e, I2C_CLIENT_END };
  47
  48static int atxp1_probe(struct i2c_client *client,
  49                       const struct i2c_device_id *id);
  50static int atxp1_remove(struct i2c_client *client);
  51static struct atxp1_data *atxp1_update_device(struct device *dev);
  52static int atxp1_detect(struct i2c_client *client, struct i2c_board_info *info);
  53
  54static const struct i2c_device_id atxp1_id[] = {
  55        { "atxp1", 0 },
  56        { }
  57};
  58MODULE_DEVICE_TABLE(i2c, atxp1_id);
  59
  60static struct i2c_driver atxp1_driver = {
  61        .class          = I2C_CLASS_HWMON,
  62        .driver = {
  63                .name   = "atxp1",
  64        },
  65        .probe          = atxp1_probe,
  66        .remove         = atxp1_remove,
  67        .id_table       = atxp1_id,
  68        .detect         = atxp1_detect,
  69        .address_list   = normal_i2c,
  70};
  71
  72struct atxp1_data {
  73        struct device *hwmon_dev;
  74        struct mutex update_lock;
  75        unsigned long last_updated;
  76        u8 valid;
  77        struct {
  78                u8 vid;         /* VID output register */
  79                u8 cpu_vid; /* VID input from CPU */
  80                u8 gpio1;   /* General purpose I/O register 1 */
  81                u8 gpio2;   /* General purpose I/O register 2 */
  82        } reg;
  83        u8 vrm;                 /* Detected CPU VRM */
  84};
  85
  86static struct atxp1_data *atxp1_update_device(struct device *dev)
  87{
  88        struct i2c_client *client;
  89        struct atxp1_data *data;
  90
  91        client = to_i2c_client(dev);
  92        data = i2c_get_clientdata(client);
  93
  94        mutex_lock(&data->update_lock);
  95
  96        if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
  97
  98                /* Update local register data */
  99                data->reg.vid = i2c_smbus_read_byte_data(client, ATXP1_VID);
 100                data->reg.cpu_vid = i2c_smbus_read_byte_data(client,
 101                                                             ATXP1_CVID);
 102                data->reg.gpio1 = i2c_smbus_read_byte_data(client, ATXP1_GPIO1);
 103                data->reg.gpio2 = i2c_smbus_read_byte_data(client, ATXP1_GPIO2);
 104
 105                data->valid = 1;
 106        }
 107
 108        mutex_unlock(&data->update_lock);
 109
 110        return data;
 111}
 112
 113/* sys file functions for cpu0_vid */
 114static ssize_t atxp1_showvcore(struct device *dev,
 115                               struct device_attribute *attr, char *buf)
 116{
 117        int size;
 118        struct atxp1_data *data;
 119
 120        data = atxp1_update_device(dev);
 121
 122        size = sprintf(buf, "%d\n", vid_from_reg(data->reg.vid & ATXP1_VIDMASK,
 123                                                 data->vrm));
 124
 125        return size;
 126}
 127
 128static ssize_t atxp1_storevcore(struct device *dev,
 129                                struct device_attribute *attr,
 130                                const char *buf, size_t count)
 131{
 132        struct atxp1_data *data;
 133        struct i2c_client *client;
 134        int vid, cvid;
 135        unsigned long vcore;
 136        int err;
 137
 138        client = to_i2c_client(dev);
 139        data = atxp1_update_device(dev);
 140
 141        err = kstrtoul(buf, 10, &vcore);
 142        if (err)
 143                return err;
 144
 145        vcore /= 25;
 146        vcore *= 25;
 147
 148        /* Calculate VID */
 149        vid = vid_to_reg(vcore, data->vrm);
 150
 151        if (vid < 0) {
 152                dev_err(dev, "VID calculation failed.\n");
 153                return -1;
 154        }
 155
 156        /*
 157         * If output enabled, use control register value.
 158         * Otherwise original CPU VID
 159         */
 160        if (data->reg.vid & ATXP1_VIDENA)
 161                cvid = data->reg.vid & ATXP1_VIDMASK;
 162        else
 163                cvid = data->reg.cpu_vid;
 164
 165        /* Nothing changed, aborting */
 166        if (vid == cvid)
 167                return count;
 168
 169        dev_dbg(dev, "Setting VCore to %d mV (0x%02x)\n", (int)vcore, vid);
 170
 171        /* Write every 25 mV step to increase stability */
 172        if (cvid > vid) {
 173                for (; cvid >= vid; cvid--)
 174                        i2c_smbus_write_byte_data(client,
 175                                                ATXP1_VID, cvid | ATXP1_VIDENA);
 176        } else {
 177                for (; cvid <= vid; cvid++)
 178                        i2c_smbus_write_byte_data(client,
 179                                                ATXP1_VID, cvid | ATXP1_VIDENA);
 180        }
 181
 182        data->valid = 0;
 183
 184        return count;
 185}
 186
 187/*
 188 * CPU core reference voltage
 189 * unit: millivolt
 190 */
 191static DEVICE_ATTR(cpu0_vid, S_IRUGO | S_IWUSR, atxp1_showvcore,
 192                   atxp1_storevcore);
 193
 194/* sys file functions for GPIO1 */
 195static ssize_t atxp1_showgpio1(struct device *dev,
 196                               struct device_attribute *attr, char *buf)
 197{
 198        int size;
 199        struct atxp1_data *data;
 200
 201        data = atxp1_update_device(dev);
 202
 203        size = sprintf(buf, "0x%02x\n", data->reg.gpio1 & ATXP1_GPIO1MASK);
 204
 205        return size;
 206}
 207
 208static ssize_t atxp1_storegpio1(struct device *dev,
 209                                struct device_attribute *attr, const char *buf,
 210                                size_t count)
 211{
 212        struct atxp1_data *data;
 213        struct i2c_client *client;
 214        unsigned long value;
 215        int err;
 216
 217        client = to_i2c_client(dev);
 218        data = atxp1_update_device(dev);
 219
 220        err = kstrtoul(buf, 16, &value);
 221        if (err)
 222                return err;
 223
 224        value &= ATXP1_GPIO1MASK;
 225
 226        if (value != (data->reg.gpio1 & ATXP1_GPIO1MASK)) {
 227                dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
 228
 229                i2c_smbus_write_byte_data(client, ATXP1_GPIO1, value);
 230
 231                data->valid = 0;
 232        }
 233
 234        return count;
 235}
 236
 237/*
 238 * GPIO1 data register
 239 * unit: Four bit as hex (e.g. 0x0f)
 240 */
 241static DEVICE_ATTR(gpio1, S_IRUGO | S_IWUSR, atxp1_showgpio1, atxp1_storegpio1);
 242
 243/* sys file functions for GPIO2 */
 244static ssize_t atxp1_showgpio2(struct device *dev,
 245                               struct device_attribute *attr, char *buf)
 246{
 247        int size;
 248        struct atxp1_data *data;
 249
 250        data = atxp1_update_device(dev);
 251
 252        size = sprintf(buf, "0x%02x\n", data->reg.gpio2);
 253
 254        return size;
 255}
 256
 257static ssize_t atxp1_storegpio2(struct device *dev,
 258                                struct device_attribute *attr,
 259                                const char *buf, size_t count)
 260{
 261        struct atxp1_data *data = atxp1_update_device(dev);
 262        struct i2c_client *client = to_i2c_client(dev);
 263        unsigned long value;
 264        int err;
 265
 266        err = kstrtoul(buf, 16, &value);
 267        if (err)
 268                return err;
 269        value &= 0xff;
 270
 271        if (value != data->reg.gpio2) {
 272                dev_info(dev, "Writing 0x%x to GPIO1.\n", (unsigned int)value);
 273
 274                i2c_smbus_write_byte_data(client, ATXP1_GPIO2, value);
 275
 276                data->valid = 0;
 277        }
 278
 279        return count;
 280}
 281
 282/*
 283 * GPIO2 data register
 284 * unit: Eight bit as hex (e.g. 0xff)
 285 */
 286static DEVICE_ATTR(gpio2, S_IRUGO | S_IWUSR, atxp1_showgpio2, atxp1_storegpio2);
 287
 288static struct attribute *atxp1_attributes[] = {
 289        &dev_attr_gpio1.attr,
 290        &dev_attr_gpio2.attr,
 291        &dev_attr_cpu0_vid.attr,
 292        NULL
 293};
 294
 295static const struct attribute_group atxp1_group = {
 296        .attrs = atxp1_attributes,
 297};
 298
 299
 300/* Return 0 if detection is successful, -ENODEV otherwise */
 301static int atxp1_detect(struct i2c_client *new_client,
 302                        struct i2c_board_info *info)
 303{
 304        struct i2c_adapter *adapter = new_client->adapter;
 305
 306        u8 temp;
 307
 308        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 309                return -ENODEV;
 310
 311        /* Detect ATXP1, checking if vendor ID registers are all zero */
 312        if (!((i2c_smbus_read_byte_data(new_client, 0x3e) == 0) &&
 313             (i2c_smbus_read_byte_data(new_client, 0x3f) == 0) &&
 314             (i2c_smbus_read_byte_data(new_client, 0xfe) == 0) &&
 315             (i2c_smbus_read_byte_data(new_client, 0xff) == 0)))
 316                return -ENODEV;
 317
 318        /*
 319         * No vendor ID, now checking if registers 0x10,0x11 (non-existent)
 320         * showing the same as register 0x00
 321         */
 322        temp = i2c_smbus_read_byte_data(new_client, 0x00);
 323
 324        if (!((i2c_smbus_read_byte_data(new_client, 0x10) == temp) &&
 325              (i2c_smbus_read_byte_data(new_client, 0x11) == temp)))
 326                return -ENODEV;
 327
 328        /* Get VRM */
 329        temp = vid_which_vrm();
 330
 331        if ((temp != 90) && (temp != 91)) {
 332                dev_err(&adapter->dev, "atxp1: Not supporting VRM %d.%d\n",
 333                                temp / 10, temp % 10);
 334                return -ENODEV;
 335        }
 336
 337        strlcpy(info->type, "atxp1", I2C_NAME_SIZE);
 338
 339        return 0;
 340}
 341
 342static int atxp1_probe(struct i2c_client *new_client,
 343                       const struct i2c_device_id *id)
 344{
 345        struct atxp1_data *data;
 346        int err;
 347
 348        data = devm_kzalloc(&new_client->dev, sizeof(struct atxp1_data),
 349                            GFP_KERNEL);
 350        if (!data)
 351                return -ENOMEM;
 352
 353        /* Get VRM */
 354        data->vrm = vid_which_vrm();
 355
 356        i2c_set_clientdata(new_client, data);
 357        data->valid = 0;
 358
 359        mutex_init(&data->update_lock);
 360
 361        /* Register sysfs hooks */
 362        err = sysfs_create_group(&new_client->dev.kobj, &atxp1_group);
 363        if (err)
 364                return err;
 365
 366        data->hwmon_dev = hwmon_device_register(&new_client->dev);
 367        if (IS_ERR(data->hwmon_dev)) {
 368                err = PTR_ERR(data->hwmon_dev);
 369                goto exit_remove_files;
 370        }
 371
 372        dev_info(&new_client->dev, "Using VRM: %d.%d\n",
 373                         data->vrm / 10, data->vrm % 10);
 374
 375        return 0;
 376
 377exit_remove_files:
 378        sysfs_remove_group(&new_client->dev.kobj, &atxp1_group);
 379        return err;
 380};
 381
 382static int atxp1_remove(struct i2c_client *client)
 383{
 384        struct atxp1_data *data = i2c_get_clientdata(client);
 385
 386        hwmon_device_unregister(data->hwmon_dev);
 387        sysfs_remove_group(&client->dev.kobj, &atxp1_group);
 388
 389        return 0;
 390};
 391
 392module_i2c_driver(atxp1_driver);
 393
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.