0001
0002
0003
0004
0005
0006 #include <linux/module.h>
0007 #include <linux/miscdevice.h>
0008 #include <linux/delay.h>
0009 #include <linux/proc_fs.h>
0010 #include <linux/seq_file.h>
0011 #include <linux/capability.h>
0012 #include <linux/init.h>
0013 #include <linux/mutex.h>
0014
0015 #include <mach/hardware.h>
0016 #include <asm/mach-types.h>
0017 #include <linux/uaccess.h>
0018 #include <asm/therm.h>
0019
0020 #ifdef CONFIG_PROC_FS
0021
0022 #define THERM_USE_PROC
0023 #endif
0024
0025
0026 #define THERM_START_CONVERT 0xee
0027 #define THERM_RESET 0xaf
0028 #define THERM_READ_CONFIG 0xac
0029 #define THERM_READ_TEMP 0xaa
0030 #define THERM_READ_TL 0xa2
0031 #define THERM_READ_TH 0xa1
0032 #define THERM_WRITE_CONFIG 0x0c
0033 #define THERM_WRITE_TL 0x02
0034 #define THERM_WRITE_TH 0x01
0035
0036 #define CFG_CPU 2
0037 #define CFG_1SHOT 1
0038
0039 static DEFINE_MUTEX(ds1620_mutex);
0040 static const char *fan_state[] = { "off", "on", "on (hardwired)" };
0041
0042
0043
0044
0045
0046
0047
0048
0049 extern unsigned int system_rev;
0050
0051 static inline void netwinder_ds1620_set_clk(int clk)
0052 {
0053 nw_gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0);
0054 }
0055
0056 static inline void netwinder_ds1620_set_data(int dat)
0057 {
0058 nw_gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0);
0059 }
0060
0061 static inline int netwinder_ds1620_get_data(void)
0062 {
0063 return nw_gpio_read() & GPIO_DATA;
0064 }
0065
0066 static inline void netwinder_ds1620_set_data_dir(int dir)
0067 {
0068 nw_gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0);
0069 }
0070
0071 static inline void netwinder_ds1620_reset(void)
0072 {
0073 nw_cpld_modify(CPLD_DS_ENABLE, 0);
0074 nw_cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE);
0075 }
0076
0077 static inline void netwinder_lock(unsigned long *flags)
0078 {
0079 raw_spin_lock_irqsave(&nw_gpio_lock, *flags);
0080 }
0081
0082 static inline void netwinder_unlock(unsigned long *flags)
0083 {
0084 raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags);
0085 }
0086
0087 static inline void netwinder_set_fan(int i)
0088 {
0089 unsigned long flags;
0090
0091 raw_spin_lock_irqsave(&nw_gpio_lock, flags);
0092 nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0);
0093 raw_spin_unlock_irqrestore(&nw_gpio_lock, flags);
0094 }
0095
0096 static inline int netwinder_get_fan(void)
0097 {
0098 if ((system_rev & 0xf000) == 0x4000)
0099 return FAN_ALWAYS_ON;
0100
0101 return (nw_gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF;
0102 }
0103
0104
0105
0106
0107
0108 static void ds1620_send_bits(int nr, int value)
0109 {
0110 int i;
0111
0112 for (i = 0; i < nr; i++) {
0113 netwinder_ds1620_set_data(value & 1);
0114 netwinder_ds1620_set_clk(0);
0115 udelay(1);
0116 netwinder_ds1620_set_clk(1);
0117 udelay(1);
0118
0119 value >>= 1;
0120 }
0121 }
0122
0123 static unsigned int ds1620_recv_bits(int nr)
0124 {
0125 unsigned int value = 0, mask = 1;
0126 int i;
0127
0128 netwinder_ds1620_set_data(0);
0129
0130 for (i = 0; i < nr; i++) {
0131 netwinder_ds1620_set_clk(0);
0132 udelay(1);
0133
0134 if (netwinder_ds1620_get_data())
0135 value |= mask;
0136
0137 mask <<= 1;
0138
0139 netwinder_ds1620_set_clk(1);
0140 udelay(1);
0141 }
0142
0143 return value;
0144 }
0145
0146 static void ds1620_out(int cmd, int bits, int value)
0147 {
0148 unsigned long flags;
0149
0150 netwinder_lock(&flags);
0151 netwinder_ds1620_set_clk(1);
0152 netwinder_ds1620_set_data_dir(0);
0153 netwinder_ds1620_reset();
0154
0155 udelay(1);
0156
0157 ds1620_send_bits(8, cmd);
0158 if (bits)
0159 ds1620_send_bits(bits, value);
0160
0161 udelay(1);
0162
0163 netwinder_ds1620_reset();
0164 netwinder_unlock(&flags);
0165
0166 msleep(20);
0167 }
0168
0169 static unsigned int ds1620_in(int cmd, int bits)
0170 {
0171 unsigned long flags;
0172 unsigned int value;
0173
0174 netwinder_lock(&flags);
0175 netwinder_ds1620_set_clk(1);
0176 netwinder_ds1620_set_data_dir(0);
0177 netwinder_ds1620_reset();
0178
0179 udelay(1);
0180
0181 ds1620_send_bits(8, cmd);
0182
0183 netwinder_ds1620_set_data_dir(1);
0184 value = ds1620_recv_bits(bits);
0185
0186 netwinder_ds1620_reset();
0187 netwinder_unlock(&flags);
0188
0189 return value;
0190 }
0191
0192 static int cvt_9_to_int(unsigned int val)
0193 {
0194 if (val & 0x100)
0195 val |= 0xfffffe00;
0196
0197 return val;
0198 }
0199
0200 static void ds1620_write_state(struct therm *therm)
0201 {
0202 ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
0203 ds1620_out(THERM_WRITE_TL, 9, therm->lo);
0204 ds1620_out(THERM_WRITE_TH, 9, therm->hi);
0205 ds1620_out(THERM_START_CONVERT, 0, 0);
0206 }
0207
0208 static void ds1620_read_state(struct therm *therm)
0209 {
0210 therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9));
0211 therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9));
0212 }
0213
0214 static int ds1620_open(struct inode *inode, struct file *file)
0215 {
0216 return stream_open(inode, file);
0217 }
0218
0219 static ssize_t
0220 ds1620_read(struct file *file, char __user *buf, size_t count, loff_t *ptr)
0221 {
0222 signed int cur_temp;
0223 signed char cur_temp_degF;
0224
0225 cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1;
0226
0227
0228 cur_temp_degF = (cur_temp * 9) / 5 + 32;
0229
0230 if (copy_to_user(buf, &cur_temp_degF, 1))
0231 return -EFAULT;
0232
0233 return 1;
0234 }
0235
0236 static int
0237 ds1620_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0238 {
0239 struct therm therm;
0240 union {
0241 struct therm __user *therm;
0242 int __user *i;
0243 } uarg;
0244 int i;
0245
0246 uarg.i = (int __user *)arg;
0247
0248 switch(cmd) {
0249 case CMD_SET_THERMOSTATE:
0250 case CMD_SET_THERMOSTATE2:
0251 if (!capable(CAP_SYS_ADMIN))
0252 return -EPERM;
0253
0254 if (cmd == CMD_SET_THERMOSTATE) {
0255 if (get_user(therm.hi, uarg.i))
0256 return -EFAULT;
0257 therm.lo = therm.hi - 3;
0258 } else {
0259 if (copy_from_user(&therm, uarg.therm, sizeof(therm)))
0260 return -EFAULT;
0261 }
0262
0263 therm.lo <<= 1;
0264 therm.hi <<= 1;
0265
0266 ds1620_write_state(&therm);
0267 break;
0268
0269 case CMD_GET_THERMOSTATE:
0270 case CMD_GET_THERMOSTATE2:
0271 ds1620_read_state(&therm);
0272
0273 therm.lo >>= 1;
0274 therm.hi >>= 1;
0275
0276 if (cmd == CMD_GET_THERMOSTATE) {
0277 if (put_user(therm.hi, uarg.i))
0278 return -EFAULT;
0279 } else {
0280 if (copy_to_user(uarg.therm, &therm, sizeof(therm)))
0281 return -EFAULT;
0282 }
0283 break;
0284
0285 case CMD_GET_TEMPERATURE:
0286 case CMD_GET_TEMPERATURE2:
0287 i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
0288
0289 if (cmd == CMD_GET_TEMPERATURE)
0290 i >>= 1;
0291
0292 return put_user(i, uarg.i) ? -EFAULT : 0;
0293
0294 case CMD_GET_STATUS:
0295 i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3;
0296
0297 return put_user(i, uarg.i) ? -EFAULT : 0;
0298
0299 case CMD_GET_FAN:
0300 i = netwinder_get_fan();
0301
0302 return put_user(i, uarg.i) ? -EFAULT : 0;
0303
0304 case CMD_SET_FAN:
0305 if (!capable(CAP_SYS_ADMIN))
0306 return -EPERM;
0307
0308 if (get_user(i, uarg.i))
0309 return -EFAULT;
0310
0311 netwinder_set_fan(i);
0312 break;
0313
0314 default:
0315 return -ENOIOCTLCMD;
0316 }
0317
0318 return 0;
0319 }
0320
0321 static long
0322 ds1620_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0323 {
0324 int ret;
0325
0326 mutex_lock(&ds1620_mutex);
0327 ret = ds1620_ioctl(file, cmd, arg);
0328 mutex_unlock(&ds1620_mutex);
0329
0330 return ret;
0331 }
0332
0333 #ifdef THERM_USE_PROC
0334 static int ds1620_proc_therm_show(struct seq_file *m, void *v)
0335 {
0336 struct therm th;
0337 int temp;
0338
0339 ds1620_read_state(&th);
0340 temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
0341
0342 seq_printf(m, "Thermostat: HI %i.%i, LOW %i.%i; temperature: %i.%i C, fan %s\n",
0343 th.hi >> 1, th.hi & 1 ? 5 : 0,
0344 th.lo >> 1, th.lo & 1 ? 5 : 0,
0345 temp >> 1, temp & 1 ? 5 : 0,
0346 fan_state[netwinder_get_fan()]);
0347 return 0;
0348 }
0349 #endif
0350
0351 static const struct file_operations ds1620_fops = {
0352 .owner = THIS_MODULE,
0353 .open = ds1620_open,
0354 .read = ds1620_read,
0355 .unlocked_ioctl = ds1620_unlocked_ioctl,
0356 .llseek = no_llseek,
0357 };
0358
0359 static struct miscdevice ds1620_miscdev = {
0360 TEMP_MINOR,
0361 "temp",
0362 &ds1620_fops
0363 };
0364
0365 static int __init ds1620_init(void)
0366 {
0367 int ret;
0368 struct therm th, th_start;
0369
0370 if (!machine_is_netwinder())
0371 return -ENODEV;
0372
0373 ds1620_out(THERM_RESET, 0, 0);
0374 ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU);
0375 ds1620_out(THERM_START_CONVERT, 0, 0);
0376
0377
0378
0379
0380
0381
0382 ds1620_read_state(&th);
0383 th_start.lo = 0;
0384 th_start.hi = 1;
0385 ds1620_write_state(&th_start);
0386
0387 msleep(2000);
0388
0389 ds1620_write_state(&th);
0390
0391 ret = misc_register(&ds1620_miscdev);
0392 if (ret < 0)
0393 return ret;
0394
0395 #ifdef THERM_USE_PROC
0396 if (!proc_create_single("therm", 0, NULL, ds1620_proc_therm_show))
0397 printk(KERN_ERR "therm: unable to register /proc/therm\n");
0398 #endif
0399
0400 ds1620_read_state(&th);
0401 ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9));
0402
0403 printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, "
0404 "current %i.%i C, fan %s.\n",
0405 th.hi >> 1, th.hi & 1 ? 5 : 0,
0406 th.lo >> 1, th.lo & 1 ? 5 : 0,
0407 ret >> 1, ret & 1 ? 5 : 0,
0408 fan_state[netwinder_get_fan()]);
0409
0410 return 0;
0411 }
0412
0413 static void __exit ds1620_exit(void)
0414 {
0415 #ifdef THERM_USE_PROC
0416 remove_proc_entry("therm", NULL);
0417 #endif
0418 misc_deregister(&ds1620_miscdev);
0419 }
0420
0421 module_init(ds1620_init);
0422 module_exit(ds1620_exit);
0423
0424 MODULE_LICENSE("GPL");