18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/drivers/char/ds1620.c: Dallas Semiconductors DS1620 48c2ecf20Sopenharmony_ci * thermometer driver (as used in the Rebel.com NetWinder) 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/miscdevice.h> 88c2ecf20Sopenharmony_ci#include <linux/delay.h> 98c2ecf20Sopenharmony_ci#include <linux/proc_fs.h> 108c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 118c2ecf20Sopenharmony_ci#include <linux/capability.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/mutex.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <mach/hardware.h> 168c2ecf20Sopenharmony_ci#include <asm/mach-types.h> 178c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 188c2ecf20Sopenharmony_ci#include <asm/therm.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#ifdef CONFIG_PROC_FS 218c2ecf20Sopenharmony_ci/* define for /proc interface */ 228c2ecf20Sopenharmony_ci#define THERM_USE_PROC 238c2ecf20Sopenharmony_ci#endif 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Definitions for DS1620 chip */ 268c2ecf20Sopenharmony_ci#define THERM_START_CONVERT 0xee 278c2ecf20Sopenharmony_ci#define THERM_RESET 0xaf 288c2ecf20Sopenharmony_ci#define THERM_READ_CONFIG 0xac 298c2ecf20Sopenharmony_ci#define THERM_READ_TEMP 0xaa 308c2ecf20Sopenharmony_ci#define THERM_READ_TL 0xa2 318c2ecf20Sopenharmony_ci#define THERM_READ_TH 0xa1 328c2ecf20Sopenharmony_ci#define THERM_WRITE_CONFIG 0x0c 338c2ecf20Sopenharmony_ci#define THERM_WRITE_TL 0x02 348c2ecf20Sopenharmony_ci#define THERM_WRITE_TH 0x01 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#define CFG_CPU 2 378c2ecf20Sopenharmony_ci#define CFG_1SHOT 1 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(ds1620_mutex); 408c2ecf20Sopenharmony_cistatic const char *fan_state[] = { "off", "on", "on (hardwired)" }; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* 438c2ecf20Sopenharmony_ci * Start of NetWinder specifics 448c2ecf20Sopenharmony_ci * Note! We have to hold the gpio lock with IRQs disabled over the 458c2ecf20Sopenharmony_ci * whole of our transaction to the Dallas chip, since there is a 468c2ecf20Sopenharmony_ci * chance that the WaveArtist driver could touch these bits to 478c2ecf20Sopenharmony_ci * enable or disable the speaker. 488c2ecf20Sopenharmony_ci */ 498c2ecf20Sopenharmony_ciextern unsigned int system_rev; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic inline void netwinder_ds1620_set_clk(int clk) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_DSCLK, clk ? GPIO_DSCLK : 0); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_cistatic inline void netwinder_ds1620_set_data(int dat) 578c2ecf20Sopenharmony_ci{ 588c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_DATA, dat ? GPIO_DATA : 0); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic inline int netwinder_ds1620_get_data(void) 628c2ecf20Sopenharmony_ci{ 638c2ecf20Sopenharmony_ci return nw_gpio_read() & GPIO_DATA; 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic inline void netwinder_ds1620_set_data_dir(int dir) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci nw_gpio_modify_io(GPIO_DATA, dir ? GPIO_DATA : 0); 698c2ecf20Sopenharmony_ci} 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic inline void netwinder_ds1620_reset(void) 728c2ecf20Sopenharmony_ci{ 738c2ecf20Sopenharmony_ci nw_cpld_modify(CPLD_DS_ENABLE, 0); 748c2ecf20Sopenharmony_ci nw_cpld_modify(CPLD_DS_ENABLE, CPLD_DS_ENABLE); 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic inline void netwinder_lock(unsigned long *flags) 788c2ecf20Sopenharmony_ci{ 798c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, *flags); 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic inline void netwinder_unlock(unsigned long *flags) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, *flags); 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic inline void netwinder_set_fan(int i) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci unsigned long flags; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci raw_spin_lock_irqsave(&nw_gpio_lock, flags); 928c2ecf20Sopenharmony_ci nw_gpio_modify_op(GPIO_FAN, i ? GPIO_FAN : 0); 938c2ecf20Sopenharmony_ci raw_spin_unlock_irqrestore(&nw_gpio_lock, flags); 948c2ecf20Sopenharmony_ci} 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic inline int netwinder_get_fan(void) 978c2ecf20Sopenharmony_ci{ 988c2ecf20Sopenharmony_ci if ((system_rev & 0xf000) == 0x4000) 998c2ecf20Sopenharmony_ci return FAN_ALWAYS_ON; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci return (nw_gpio_read() & GPIO_FAN) ? FAN_ON : FAN_OFF; 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci/* 1058c2ecf20Sopenharmony_ci * End of NetWinder specifics 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_cistatic void ds1620_send_bits(int nr, int value) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int i; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 1138c2ecf20Sopenharmony_ci netwinder_ds1620_set_data(value & 1); 1148c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(0); 1158c2ecf20Sopenharmony_ci udelay(1); 1168c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(1); 1178c2ecf20Sopenharmony_ci udelay(1); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci value >>= 1; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistatic unsigned int ds1620_recv_bits(int nr) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci unsigned int value = 0, mask = 1; 1268c2ecf20Sopenharmony_ci int i; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci netwinder_ds1620_set_data(0); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 1318c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(0); 1328c2ecf20Sopenharmony_ci udelay(1); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (netwinder_ds1620_get_data()) 1358c2ecf20Sopenharmony_ci value |= mask; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci mask <<= 1; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(1); 1408c2ecf20Sopenharmony_ci udelay(1); 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return value; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic void ds1620_out(int cmd, int bits, int value) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci unsigned long flags; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci netwinder_lock(&flags); 1518c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(1); 1528c2ecf20Sopenharmony_ci netwinder_ds1620_set_data_dir(0); 1538c2ecf20Sopenharmony_ci netwinder_ds1620_reset(); 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci udelay(1); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci ds1620_send_bits(8, cmd); 1588c2ecf20Sopenharmony_ci if (bits) 1598c2ecf20Sopenharmony_ci ds1620_send_bits(bits, value); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci udelay(1); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci netwinder_ds1620_reset(); 1648c2ecf20Sopenharmony_ci netwinder_unlock(&flags); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci msleep(20); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic unsigned int ds1620_in(int cmd, int bits) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci unsigned long flags; 1728c2ecf20Sopenharmony_ci unsigned int value; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci netwinder_lock(&flags); 1758c2ecf20Sopenharmony_ci netwinder_ds1620_set_clk(1); 1768c2ecf20Sopenharmony_ci netwinder_ds1620_set_data_dir(0); 1778c2ecf20Sopenharmony_ci netwinder_ds1620_reset(); 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci udelay(1); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci ds1620_send_bits(8, cmd); 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci netwinder_ds1620_set_data_dir(1); 1848c2ecf20Sopenharmony_ci value = ds1620_recv_bits(bits); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci netwinder_ds1620_reset(); 1878c2ecf20Sopenharmony_ci netwinder_unlock(&flags); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return value; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic int cvt_9_to_int(unsigned int val) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci if (val & 0x100) 1958c2ecf20Sopenharmony_ci val |= 0xfffffe00; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci return val; 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_cistatic void ds1620_write_state(struct therm *therm) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); 2038c2ecf20Sopenharmony_ci ds1620_out(THERM_WRITE_TL, 9, therm->lo); 2048c2ecf20Sopenharmony_ci ds1620_out(THERM_WRITE_TH, 9, therm->hi); 2058c2ecf20Sopenharmony_ci ds1620_out(THERM_START_CONVERT, 0, 0); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic void ds1620_read_state(struct therm *therm) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci therm->lo = cvt_9_to_int(ds1620_in(THERM_READ_TL, 9)); 2118c2ecf20Sopenharmony_ci therm->hi = cvt_9_to_int(ds1620_in(THERM_READ_TH, 9)); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_cistatic int ds1620_open(struct inode *inode, struct file *file) 2158c2ecf20Sopenharmony_ci{ 2168c2ecf20Sopenharmony_ci return stream_open(inode, file); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic ssize_t 2208c2ecf20Sopenharmony_cids1620_read(struct file *file, char __user *buf, size_t count, loff_t *ptr) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci signed int cur_temp; 2238c2ecf20Sopenharmony_ci signed char cur_temp_degF; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci cur_temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)) >> 1; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci /* convert to Fahrenheit, as per wdt.c */ 2288c2ecf20Sopenharmony_ci cur_temp_degF = (cur_temp * 9) / 5 + 32; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (copy_to_user(buf, &cur_temp_degF, 1)) 2318c2ecf20Sopenharmony_ci return -EFAULT; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci return 1; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic int 2378c2ecf20Sopenharmony_cids1620_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci struct therm therm; 2408c2ecf20Sopenharmony_ci union { 2418c2ecf20Sopenharmony_ci struct therm __user *therm; 2428c2ecf20Sopenharmony_ci int __user *i; 2438c2ecf20Sopenharmony_ci } uarg; 2448c2ecf20Sopenharmony_ci int i; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci uarg.i = (int __user *)arg; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci switch(cmd) { 2498c2ecf20Sopenharmony_ci case CMD_SET_THERMOSTATE: 2508c2ecf20Sopenharmony_ci case CMD_SET_THERMOSTATE2: 2518c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 2528c2ecf20Sopenharmony_ci return -EPERM; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (cmd == CMD_SET_THERMOSTATE) { 2558c2ecf20Sopenharmony_ci if (get_user(therm.hi, uarg.i)) 2568c2ecf20Sopenharmony_ci return -EFAULT; 2578c2ecf20Sopenharmony_ci therm.lo = therm.hi - 3; 2588c2ecf20Sopenharmony_ci } else { 2598c2ecf20Sopenharmony_ci if (copy_from_user(&therm, uarg.therm, sizeof(therm))) 2608c2ecf20Sopenharmony_ci return -EFAULT; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci therm.lo <<= 1; 2648c2ecf20Sopenharmony_ci therm.hi <<= 1; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci ds1620_write_state(&therm); 2678c2ecf20Sopenharmony_ci break; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci case CMD_GET_THERMOSTATE: 2708c2ecf20Sopenharmony_ci case CMD_GET_THERMOSTATE2: 2718c2ecf20Sopenharmony_ci ds1620_read_state(&therm); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci therm.lo >>= 1; 2748c2ecf20Sopenharmony_ci therm.hi >>= 1; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci if (cmd == CMD_GET_THERMOSTATE) { 2778c2ecf20Sopenharmony_ci if (put_user(therm.hi, uarg.i)) 2788c2ecf20Sopenharmony_ci return -EFAULT; 2798c2ecf20Sopenharmony_ci } else { 2808c2ecf20Sopenharmony_ci if (copy_to_user(uarg.therm, &therm, sizeof(therm))) 2818c2ecf20Sopenharmony_ci return -EFAULT; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci break; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci case CMD_GET_TEMPERATURE: 2868c2ecf20Sopenharmony_ci case CMD_GET_TEMPERATURE2: 2878c2ecf20Sopenharmony_ci i = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (cmd == CMD_GET_TEMPERATURE) 2908c2ecf20Sopenharmony_ci i >>= 1; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci case CMD_GET_STATUS: 2958c2ecf20Sopenharmony_ci i = ds1620_in(THERM_READ_CONFIG, 8) & 0xe3; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci case CMD_GET_FAN: 3008c2ecf20Sopenharmony_ci i = netwinder_get_fan(); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci return put_user(i, uarg.i) ? -EFAULT : 0; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci case CMD_SET_FAN: 3058c2ecf20Sopenharmony_ci if (!capable(CAP_SYS_ADMIN)) 3068c2ecf20Sopenharmony_ci return -EPERM; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (get_user(i, uarg.i)) 3098c2ecf20Sopenharmony_ci return -EFAULT; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci netwinder_set_fan(i); 3128c2ecf20Sopenharmony_ci break; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci default: 3158c2ecf20Sopenharmony_ci return -ENOIOCTLCMD; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic long 3228c2ecf20Sopenharmony_cids1620_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci int ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci mutex_lock(&ds1620_mutex); 3278c2ecf20Sopenharmony_ci ret = ds1620_ioctl(file, cmd, arg); 3288c2ecf20Sopenharmony_ci mutex_unlock(&ds1620_mutex); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#ifdef THERM_USE_PROC 3348c2ecf20Sopenharmony_cistatic int ds1620_proc_therm_show(struct seq_file *m, void *v) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct therm th; 3378c2ecf20Sopenharmony_ci int temp; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ds1620_read_state(&th); 3408c2ecf20Sopenharmony_ci temp = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci seq_printf(m, "Thermostat: HI %i.%i, LOW %i.%i; temperature: %i.%i C, fan %s\n", 3438c2ecf20Sopenharmony_ci th.hi >> 1, th.hi & 1 ? 5 : 0, 3448c2ecf20Sopenharmony_ci th.lo >> 1, th.lo & 1 ? 5 : 0, 3458c2ecf20Sopenharmony_ci temp >> 1, temp & 1 ? 5 : 0, 3468c2ecf20Sopenharmony_ci fan_state[netwinder_get_fan()]); 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci#endif 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_cistatic const struct file_operations ds1620_fops = { 3528c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 3538c2ecf20Sopenharmony_ci .open = ds1620_open, 3548c2ecf20Sopenharmony_ci .read = ds1620_read, 3558c2ecf20Sopenharmony_ci .unlocked_ioctl = ds1620_unlocked_ioctl, 3568c2ecf20Sopenharmony_ci .llseek = no_llseek, 3578c2ecf20Sopenharmony_ci}; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_cistatic struct miscdevice ds1620_miscdev = { 3608c2ecf20Sopenharmony_ci TEMP_MINOR, 3618c2ecf20Sopenharmony_ci "temp", 3628c2ecf20Sopenharmony_ci &ds1620_fops 3638c2ecf20Sopenharmony_ci}; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_cistatic int __init ds1620_init(void) 3668c2ecf20Sopenharmony_ci{ 3678c2ecf20Sopenharmony_ci int ret; 3688c2ecf20Sopenharmony_ci struct therm th, th_start; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (!machine_is_netwinder()) 3718c2ecf20Sopenharmony_ci return -ENODEV; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci ds1620_out(THERM_RESET, 0, 0); 3748c2ecf20Sopenharmony_ci ds1620_out(THERM_WRITE_CONFIG, 8, CFG_CPU); 3758c2ecf20Sopenharmony_ci ds1620_out(THERM_START_CONVERT, 0, 0); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * Trigger the fan to start by setting 3798c2ecf20Sopenharmony_ci * temperature high point low. This kicks 3808c2ecf20Sopenharmony_ci * the fan into action. 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci ds1620_read_state(&th); 3838c2ecf20Sopenharmony_ci th_start.lo = 0; 3848c2ecf20Sopenharmony_ci th_start.hi = 1; 3858c2ecf20Sopenharmony_ci ds1620_write_state(&th_start); 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci msleep(2000); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci ds1620_write_state(&th); 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci ret = misc_register(&ds1620_miscdev); 3928c2ecf20Sopenharmony_ci if (ret < 0) 3938c2ecf20Sopenharmony_ci return ret; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci#ifdef THERM_USE_PROC 3968c2ecf20Sopenharmony_ci if (!proc_create_single("therm", 0, NULL, ds1620_proc_therm_show)) 3978c2ecf20Sopenharmony_ci printk(KERN_ERR "therm: unable to register /proc/therm\n"); 3988c2ecf20Sopenharmony_ci#endif 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci ds1620_read_state(&th); 4018c2ecf20Sopenharmony_ci ret = cvt_9_to_int(ds1620_in(THERM_READ_TEMP, 9)); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci printk(KERN_INFO "Thermostat: high %i.%i, low %i.%i, " 4048c2ecf20Sopenharmony_ci "current %i.%i C, fan %s.\n", 4058c2ecf20Sopenharmony_ci th.hi >> 1, th.hi & 1 ? 5 : 0, 4068c2ecf20Sopenharmony_ci th.lo >> 1, th.lo & 1 ? 5 : 0, 4078c2ecf20Sopenharmony_ci ret >> 1, ret & 1 ? 5 : 0, 4088c2ecf20Sopenharmony_ci fan_state[netwinder_get_fan()]); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return 0; 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic void __exit ds1620_exit(void) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci#ifdef THERM_USE_PROC 4168c2ecf20Sopenharmony_ci remove_proc_entry("therm", NULL); 4178c2ecf20Sopenharmony_ci#endif 4188c2ecf20Sopenharmony_ci misc_deregister(&ds1620_miscdev); 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cimodule_init(ds1620_init); 4228c2ecf20Sopenharmony_cimodule_exit(ds1620_exit); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 425