162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620 462306a36Sopenharmony_ci * thermometer driver (as used in the Rebel.com NetWinder) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/miscdevice.h> 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/proc_fs.h> 1062306a36Sopenharmony_ci#include <linux/seq_file.h> 1162306a36Sopenharmony_ci#include <linux/capability.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/mutex.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <mach/hardware.h> 1662306a36Sopenharmony_ci#include <asm/mach-types.h> 1762306a36Sopenharmony_ci#include <linux/uaccess.h> 1862306a36Sopenharmony_ci#include <asm/therm.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci#ifdef CONFIG_PROC_FS 2162306a36Sopenharmony_ci/* define for /proc interface */ 2262306a36Sopenharmony_ci#define THERM_USE_PROC 2362306a36Sopenharmony_ci#endif 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci/* Definitions for DS1620 chip */ 2662306a36Sopenharmony_ci#define THERM_START_CONVERT 0xee 2762306a36Sopenharmony_ci#define THERM_RESET 0xaf 2862306a36Sopenharmony_ci#define THERM_READ_CONFIG 0xac 2962306a36Sopenharmony_ci#define THERM_READ_TEMP 0xaa 3062306a36Sopenharmony_ci#define THERM_READ_TL 0xa2 3162306a36Sopenharmony_ci#define THERM_READ_TH 0xa1 3262306a36Sopenharmony_ci#define THERM_WRITE_CONFIG 0x0c 3362306a36Sopenharmony_ci#define THERM_WRITE_TL 0x02 3462306a36Sopenharmony_ci#define THERM_WRITE_TH 0x01 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define CFG_CPU 2 3762306a36Sopenharmony_ci#define CFG_1SHOT 1 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistatic DEFINE_MUTEX(ds1620_mutex); 4062306a36Sopenharmony_cistatic const char *fan_state[] = { "off", "on", "on (hardwired)" }; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * Start of NetWinder specifics 4462306a36Sopenharmony_ci * Note! We have to hold the gpio lock with IRQs disabled over the 4562306a36Sopenharmony_ci * whole of our transaction to the Dallas chip, since there is a 4662306a36Sopenharmony_ci * chance that the WaveArtist driver could touch these bits to 4762306a36Sopenharmony_ci * enable or disable the speaker. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ciextern unsigned int system_rev; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic inline void netwinder_ds1620_set_clk(int clk) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci nw_gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_cistatic inline void netwinder_ds1620_set_data(int dat) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci nw_gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0); 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic inline int netwinder_ds1620_get_data(void) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci return nw_gpio_read() & GPIO_DATA; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic inline void netwinder_ds1620_set_data_dir(int dir) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci nw_gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistatic inline void netwinder_ds1620_reset(void) 7262306a36Sopenharmony_ci{ 7362306a36Sopenharmony_ci nw_cpld_modify(CPLD_DS_ENABLE, 0); 7462306a36Sopenharmony_ci nw_cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE); 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic inline void netwinder_lock(unsigned long *flags) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, *flags); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic inline void netwinder_unlock(unsigned long *flags) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags); 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic inline void netwinder_set_fan(int i) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci unsigned long flags; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 9262306a36Sopenharmony_ci nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); 9362306a36Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic inline int netwinder_get_fan(void) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if ((system_rev & 0xf000) == 0x4000) 9962306a36Sopenharmony_ci return FAN_ALWAYS_ON; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci return (nw_gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF; 10262306a36Sopenharmony_ci} 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci/* 10562306a36Sopenharmony_ci * End of NetWinder specifics 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_cistatic void ds1620_send_bits(int nr, int value) 10962306a36Sopenharmony_ci{ 11062306a36Sopenharmony_ci int i; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 11362306a36Sopenharmony_ci netwinder_ds1620_set_data(value & 1); 11462306a36Sopenharmony_ci netwinder_ds1620_set_clk(0); 11562306a36Sopenharmony_ci udelay(1); 11662306a36Sopenharmony_ci netwinder_ds1620_set_clk(1); 11762306a36Sopenharmony_ci udelay(1); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci value >>= 1; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic unsigned int ds1620_recv_bits(int nr) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci unsigned int value = 0, mask = 1; 12662306a36Sopenharmony_ci int i; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci netwinder_ds1620_set_data(0); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 13162306a36Sopenharmony_ci netwinder_ds1620_set_clk(0); 13262306a36Sopenharmony_ci udelay(1); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci if (netwinder_ds1620_get_data()) 13562306a36Sopenharmony_ci value |= mask; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci mask <<= 1; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci netwinder_ds1620_set_clk(1); 14062306a36Sopenharmony_ci udelay(1); 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci return value; 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_cistatic void ds1620_out(int cmd, int bits, int value) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci unsigned long flags; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci netwinder_lock(&flags); 15162306a36Sopenharmony_ci netwinder_ds1620_set_clk(1); 15262306a36Sopenharmony_ci netwinder_ds1620_set_data_dir(0); 15362306a36Sopenharmony_ci netwinder_ds1620_reset(); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci udelay(1); 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci ds1620_send_bits(8, cmd); 15862306a36Sopenharmony_ci if (bits) 15962306a36Sopenharmony_ci ds1620_send_bits(bits, value); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci udelay(1); 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci netwinder_ds1620_reset(); 16462306a36Sopenharmony_ci netwinder_unlock(&flags); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci msleep(20); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistatic unsigned int ds1620_in(int cmd, int bits) 17062306a36Sopenharmony_ci{ 17162306a36Sopenharmony_ci unsigned long flags; 17262306a36Sopenharmony_ci unsigned int value; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci netwinder_lock(&flags); 17562306a36Sopenharmony_ci netwinder_ds1620_set_clk(1); 17662306a36Sopenharmony_ci netwinder_ds1620_set_data_dir(0); 17762306a36Sopenharmony_ci netwinder_ds1620_reset(); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci udelay(1); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci ds1620_send_bits(8, cmd); 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci netwinder_ds1620_set_data_dir(1); 18462306a36Sopenharmony_ci value = ds1620_recv_bits(bits); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci netwinder_ds1620_reset(); 18762306a36Sopenharmony_ci netwinder_unlock(&flags); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return value; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cistatic int cvt_9_to_int(unsigned int val) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci if (val & 0x100) 19562306a36Sopenharmony_ci val |= 0xfffffe00; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci return val; 19862306a36Sopenharmony_ci} 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistatic void ds1620_write_state(struct therm *therm) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); 20362306a36Sopenharmony_ci ds1620_out(THERM_WRITE_TL, 9, therm->lo); 20462306a36Sopenharmony_ci ds1620_out(THERM_WRITE_TH, 9, therm->hi); 20562306a36Sopenharmony_ci ds1620_out(THERM_START_CONVERT, 0, 0); 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void ds1620_read_state(struct therm *therm) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9)); 21162306a36Sopenharmony_ci therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9)); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic int ds1620_open(struct inode *inode, struct file *file) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci return stream_open(inode, file); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic ssize_t 22062306a36Sopenharmony_cids1620_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci signed int cur_temp; 22362306a36Sopenharmony_ci signed char cur_temp_degF; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* convert to Fahrenheit, as per wdt.c */ 22862306a36Sopenharmony_ci cur_temp_degF = (cur_temp * 9) / 5 + 32; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (copy_to_user(buf, &cur_temp_degF, 1)) 23162306a36Sopenharmony_ci return -EFAULT; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci return 1; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int 23762306a36Sopenharmony_cids1620_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci struct therm therm; 24062306a36Sopenharmony_ci union { 24162306a36Sopenharmony_ci struct therm __user *therm; 24262306a36Sopenharmony_ci int __user *i; 24362306a36Sopenharmony_ci } uarg; 24462306a36Sopenharmony_ci int i; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci uarg.i = (int __user *)arg; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci switch(cmd) { 24962306a36Sopenharmony_ci case CMD_SET_THERMOSTATE: 25062306a36Sopenharmony_ci case CMD_SET_THERMOSTATE2: 25162306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 25262306a36Sopenharmony_ci return -EPERM; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (cmd == CMD_SET_THERMOSTATE) { 25562306a36Sopenharmony_ci if (get_user(therm.hi, uarg.i)) 25662306a36Sopenharmony_ci return -EFAULT; 25762306a36Sopenharmony_ci therm.lo = therm.hi - 3; 25862306a36Sopenharmony_ci } else { 25962306a36Sopenharmony_ci if (copy_from_user(&therm, uarg.therm, sizeof(therm))) 26062306a36Sopenharmony_ci return -EFAULT; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci therm.lo <<= 1; 26462306a36Sopenharmony_ci therm.hi <<= 1; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci ds1620_write_state(&therm); 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci case CMD_GET_THERMOSTATE: 27062306a36Sopenharmony_ci case CMD_GET_THERMOSTATE2: 27162306a36Sopenharmony_ci ds1620_read_state(&therm); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci therm.lo >>= 1; 27462306a36Sopenharmony_ci therm.hi >>= 1; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (cmd == CMD_GET_THERMOSTATE) { 27762306a36Sopenharmony_ci if (put_user(therm.hi, uarg.i)) 27862306a36Sopenharmony_ci return -EFAULT; 27962306a36Sopenharmony_ci } else { 28062306a36Sopenharmony_ci if (copy_to_user(uarg.therm, &therm, sizeof(therm))) 28162306a36Sopenharmony_ci return -EFAULT; 28262306a36Sopenharmony_ci } 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci case CMD_GET_TEMPERATURE: 28662306a36Sopenharmony_ci case CMD_GET_TEMPERATURE2: 28762306a36Sopenharmony_ci i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (cmd == CMD_GET_TEMPERATURE) 29062306a36Sopenharmony_ci i >>= 1; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci case CMD_GET_STATUS: 29562306a36Sopenharmony_ci i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci case CMD_GET_FAN: 30062306a36Sopenharmony_ci i = netwinder_get_fan(); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci case CMD_SET_FAN: 30562306a36Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 30662306a36Sopenharmony_ci return -EPERM; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (get_user(i, uarg.i)) 30962306a36Sopenharmony_ci return -EFAULT; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci netwinder_set_fan(i); 31262306a36Sopenharmony_ci break; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci default: 31562306a36Sopenharmony_ci return -ENOIOCTLCMD; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic long 32262306a36Sopenharmony_cids1620_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci int ret; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci mutex_lock(&ds1620_mutex); 32762306a36Sopenharmony_ci ret = ds1620_ioctl(file, cmd, arg); 32862306a36Sopenharmony_ci mutex_unlock(&ds1620_mutex); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci return ret; 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci#ifdef THERM_USE_PROC 33462306a36Sopenharmony_cistatic int ds1620_proc_therm_show(struct seq_file *m, void *v) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct therm th; 33762306a36Sopenharmony_ci int temp; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ds1620_read_state(&th); 34062306a36Sopenharmony_ci temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci seq_printf(m, "Thermostat: HI %i.%i, LOW %i.%i; temperature: %i.%i C, fan %s\n", 34362306a36Sopenharmony_ci th.hi >> 1, th.hi & 1 ? 5 : 0, 34462306a36Sopenharmony_ci th.lo >> 1, th.lo & 1 ? 5 : 0, 34562306a36Sopenharmony_ci temp >> 1, temp & 1 ? 5 : 0, 34662306a36Sopenharmony_ci fan_state[netwinder_get_fan()]); 34762306a36Sopenharmony_ci return 0; 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci#endif 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic const struct file_operations ds1620_fops = { 35262306a36Sopenharmony_ci .owner = THIS_MODULE, 35362306a36Sopenharmony_ci .open = ds1620_open, 35462306a36Sopenharmony_ci .read = ds1620_read, 35562306a36Sopenharmony_ci .unlocked_ioctl = ds1620_unlocked_ioctl, 35662306a36Sopenharmony_ci .llseek = no_llseek, 35762306a36Sopenharmony_ci}; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_cistatic struct miscdevice ds1620_miscdev = { 36062306a36Sopenharmony_ci TEMP_MINOR, 36162306a36Sopenharmony_ci "temp", 36262306a36Sopenharmony_ci &ds1620_fops 36362306a36Sopenharmony_ci}; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_cistatic int __init ds1620_init(void) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci int ret; 36862306a36Sopenharmony_ci struct therm th, th_start; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci if (!machine_is_netwinder()) 37162306a36Sopenharmony_ci return -ENODEV; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci ds1620_out(THERM_RESET, 0, 0); 37462306a36Sopenharmony_ci ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); 37562306a36Sopenharmony_ci ds1620_out(THERM_START_CONVERT, 0, 0); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * Trigger the fan to start by setting 37962306a36Sopenharmony_ci * temperature high point low. This kicks 38062306a36Sopenharmony_ci * the fan into action. 38162306a36Sopenharmony_ci */ 38262306a36Sopenharmony_ci ds1620_read_state(&th); 38362306a36Sopenharmony_ci th_start.lo = 0; 38462306a36Sopenharmony_ci th_start.hi = 1; 38562306a36Sopenharmony_ci ds1620_write_state(&th_start); 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci msleep(2000); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ds1620_write_state(&th); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci ret = misc_register(&ds1620_miscdev); 39262306a36Sopenharmony_ci if (ret < 0) 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci#ifdef THERM_USE_PROC 39662306a36Sopenharmony_ci if (!proc_create_single("therm", 0, NULL, ds1620_proc_therm_show)) 39762306a36Sopenharmony_ci printk(KERN_ERR "therm: unable to register /proc/therm\n"); 39862306a36Sopenharmony_ci#endif 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ds1620_read_state(&th); 40162306a36Sopenharmony_ci ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, " 40462306a36Sopenharmony_ci "current %i.%i C, fan %s.\n", 40562306a36Sopenharmony_ci th.hi >> 1, th.hi & 1 ? 5 : 0, 40662306a36Sopenharmony_ci th.lo >> 1, th.lo & 1 ? 5 : 0, 40762306a36Sopenharmony_ci ret >> 1, ret & 1 ? 5 : 0, 40862306a36Sopenharmony_ci fan_state[netwinder_get_fan()]); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci return 0; 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void __exit ds1620_exit(void) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci#ifdef THERM_USE_PROC 41662306a36Sopenharmony_ci remove_proc_entry("therm", NULL); 41762306a36Sopenharmony_ci#endif 41862306a36Sopenharmony_ci misc_deregister(&ds1620_miscdev); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cimodule_init(ds1620_init); 42262306a36Sopenharmony_cimodule_exit(ds1620_exit); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 425