📄 ds1337.c
字号:
/* * linux/drivers/i2c/chips/ds1337.c * * Driver for Dallas Semiconductor DS1337 and DS1339 real time clock chip */#include <linux/module.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/i2c.h>#include <linux/i2c-sensor.h>#include <linux/string.h>#include <linux/rtc.h> /* get the user-level API */#include <linux/bcd.h>#include <linux/list.h>#include <linux/interrupt.h>#include <asm/arch/io_registers.h>#include <asm/irq.h>#include <asm/arch/gio.h>#include <asm/arch/gios.h>#include <asm/arch/irqs.h>#include <linux/fb.h>#include <asm/uaccess.h>#include "ds1337.h"#undef dev_dbg #undef dev_err#define dev_printk(level, dev, format, arg...) \ printk(level "%s %s: " format , (dev)->driver->name , (dev)->bus_id , ## arg)#define dev_dbg(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg)#define dev_err(dev, format, arg...) \ dev_printk(KERN_DEBUG , dev , format , ## arg)#define MOD_DESC "MAXIM DS1337 I2C serial real-time clock"MODULE_DESCRIPTION(MOD_DESC);MODULE_AUTHOR("Envision");MODULE_LICENSE("GPL");//Variables declarestatic u32 ds1337_opened = 0;static const char * pname = "DS1337:";/* * Functions declaration */static unsigned short normal_i2c[] = { 0x68,0x69, I2C_CLIENT_END };static unsigned int normal_isa[] = { I2C_CLIENT_ISA_END };static unsigned short normal_i2c_range[] = { I2C_CLIENT_END };static unsigned int normal_isa_range[] = { I2C_CLIENT_ISA_END };//I2C_CLIENT_INSMOD;SENSORS_INSMOD_1(ds1337);static int ds1337_attach_adapter(struct i2c_adapter *adapter);static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind);static void ds1337_init_client(struct i2c_client *client);static int ds1337_detach_client(struct i2c_client *client);static irqreturn_t ds1337_isr(int irq, void *data, struct pt_regs *regs);/* * Driver data (common to all clients) */static struct i2c_driver ds1337_driver = { .owner = THIS_MODULE, .name = "ds1337", .flags = I2C_DF_NOTIFY, .attach_adapter = ds1337_attach_adapter, .detach_client = ds1337_detach_client,};/* * Client data (each client gets its own) */struct ds1337_data { struct i2c_client client; struct list_head list;};static struct i2c_client *ds1337_client; /* * Internal variables */static LIST_HEAD(ds1337_clients);//interrupt service program#define DS1337_DISABLE_IRQS \ outw(inw(IO_GIO_IRQPORT) & ~(1 << GIO_RTC_INTA), IO_GIO_IRQPORT);#define DS1337_ENABLE_IRQS \ outw(inw(IO_GIO_IRQPORT) |(1 << GIO_RTC_INTA), IO_GIO_IRQPORT);static irqreturn_t ds1337_isr(int irq, void *data, struct pt_regs *regs){ DS1337_DISABLE_IRQS; //interrupt service program printk("**********************************************\n"); printk("**********************************************\n"); printk("**********************************************\n"); DS1337_ENABLE_IRQS; return IRQ_HANDLED;}static inline int ds1337_read(struct i2c_client *client, u8 reg, u8 *value){ s32 tmp = i2c_smbus_read_byte_data(client, reg); if (tmp < 0) return -EIO; *value = tmp; return 0;}static int ds1337_attach_adapter(struct i2c_adapter *adapter){ return i2c_detect(adapter, &addr_data, ds1337_detect);}/* * The following function does more than just detection. If detection * succeeds, it also registers the new chip. */static int ds1337_detect(struct i2c_adapter *adapter, int address, int kind){ struct i2c_client *new_client; struct ds1337_data *data; int err = 0; const char *name = ""; /* if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_I2C)) goto exit;*/ if (!(data = kmalloc(sizeof(struct ds1337_data), GFP_KERNEL))) { err = -ENOMEM; goto exit; } memset(data, 0, sizeof(struct ds1337_data)); INIT_LIST_HEAD(&data->list); /* The common I2C client data is placed right before the * DS1337-specific data. */ new_client = &data->client; i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &ds1337_driver; new_client->flags = 0; /* * Now we do the remaining detection. A negative kind means that * the driver was loaded with no force parameter (default), so we * must both detect and identify the chip. A zero kind means that * the driver was loaded with the force parameter, the detection * step shall be skipped. A positive kind means that the driver * was loaded with the force parameter and a given kind of chip is * requested, so both the detection and the identification steps * are skipped. * * For detection, we read registers that are most likely to cause * detection failure, i.e. those that have more bits with fixed * or reserved values. */ /* Default to an DS1337 if forced */ if (kind == 0) kind = ds1337; if (kind < 0) { /* detection and identification */ u8 data; /* Check that status register bits 6-2 are zero */ if ((ds1337_read(new_client, DS1337_REG_STATUS, &data) < 0) || (data & 0x7c)) goto exit_free; /* Check for a valid day register value */if ((ds1337_read(new_client, DS1337_REG_DAY, &data) < 0) || (data == 0) || (data & 0xf8)) goto exit_free; /* Check for a valid date register value */ if ((ds1337_read(new_client, DS1337_REG_DATE, &data) < 0) || (data == 0) || (data & 0xc0) || ((data & 0x0f) > 9) || (data >= 0x32)) goto exit_free; /* Check for a valid month register value */ if ((ds1337_read(new_client, DS1337_REG_MONTH, &data) < 0) || (data == 0) || (data & 0x60) || ((data & 0x0f) > 9) || ((data >= 0x13) && (data <= 0x19))) goto exit_free; /* Check that control register bits 6-5 are zero */ if ((ds1337_read(new_client, DS1337_REG_CONTROL, &data) < 0) || (data & 0x60)) goto exit_free; kind = ds1337; } if (kind == ds1337) name = "ds1337"; /* We can fill in the remaining client fields */ strlcpy(new_client->name, name, I2C_NAME_SIZE); /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) goto exit_free; /* Initialize the DS1337 chip */ ds1337_init_client(new_client); /* Add client to local list */ list_add(&data->list, &ds1337_clients); ds1337_client = new_client; return 0;exit_free: kfree(data);exit: return err;}static void ds1337_init_client(struct i2c_client *client){ s32 val; /* Ensure that device is set in 24-hour mode */ val = i2c_smbus_read_byte_data(client, DS1337_REG_HOUR); // printk("DS1337_REG_HOUR = 0x%x.\n", val); if ((val >= 0) && (val & (1 << 6))) i2c_smbus_write_byte_data(client, DS1337_REG_HOUR, val & 0x3f);//initial values (for date-time register are 0,0,0,1,1,1,0)//initial alarms values are uncertain./* u8 buf[7]; memset( buf, 0, sizeof(buf)); ds1337_read( ds1337_client, DS1337_REG_SECOND, &buf[0]); ds1337_read( ds1337_client, DS1337_REG_MINUTE, &buf[1]); ds1337_read( ds1337_client, DS1337_REG_HOUR, &buf[2]); ds1337_read( ds1337_client, DS1337_REG_DAY, &buf[3]); ds1337_read( ds1337_client, DS1337_REG_DATE, &buf[4]); ds1337_read( ds1337_client, DS1337_REG_MONTH, &buf[5]); ds1337_read( ds1337_client, DS1337_REG_YEAR, &buf[6]);printk(" %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]); */ //init the registers //the initial time and date are 2005,01,01,00:00/* i2c_smbus_write_byte_data(client, DS1337_REG_SECOND, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_MINUTE, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_HOUR, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_DAY, 0x06); i2c_smbus_write_byte_data(client, DS1337_REG_DATE, 0x01); i2c_smbus_write_byte_data(client, DS1337_REG_MONTH, 0x01); i2c_smbus_write_byte_data(client, DS1337_REG_YEAR, 0x05);*/ //the alarm 1 //match day,hour,min,sec,the alarm produces INT/* i2c_smbus_write_byte_data(client, DS1337_REG_A1M_SECOND, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_A1M_MINUTE, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_A1M_HOUR, 0x00); //the day matches month i2c_smbus_write_byte_data(client, DS1337_REG_A1M_DAY_DATE, 0x00); //the alarm2 //match day,hour,min,the alarm produces INT i2c_smbus_write_byte_data(client, DS1337_REG_A2M_MINUTE, 0x00); i2c_smbus_write_byte_data(client, DS1337_REG_A2M_HOUR, 0x00); //the day matches month i2c_smbus_write_byte_data(client, DS1337_REG_A2M_DAY_DATE, 0x00); //control register //OScillator starts,32.768khz,alarm1 matches ~INTA,alarm2 matchs SQW/~INTB //both alarms do not initiate i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, RS2| RS1 );//initial status register,in order to use alarm function correctly i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, 0 );*/ }static int ds1337_detach_client(struct i2c_client *client){ int err; struct ds1337_data *data = i2c_get_clientdata(client); if ((err = i2c_detach_client(client))) { dev_err(&client->dev, "Client deregistration failed, " "client not detached.\n"); return err; } list_del(&data->list); kfree(data); return 0;}/* Start File Ops */static int ds1337_open(struct inode * inode, struct file * file){ if (ds1337_opened) return -EBUSY; file->private_data = (void*)ds1337_client; ds1337_opened = 1; return 0;}static int ds1337_release(struct inode * inode, struct file * file){ if (!ds1337_opened) return -ERESTARTSYS; ds1337_opened = 0; file->private_data = NULL; return 0;}static int ds1337_ioctl(struct inode * inode, struct file * file,unsigned int cmd, unsigned long arg){ int arg_size, ret = 0; if (_IOC_TYPE(cmd) != DS1337_IOC_MAGIC) return -EINVAL; if (_IOC_NR(cmd) > DS1337_IOC_MAXNR) return -EINVAL; arg_size = _IOC_SIZE(cmd); if (_IOC_DIR(cmd) & _IOC_READ) ret = !access_ok(VERIFY_WRITE, (void *)arg, arg_size); else if (_IOC_DIR(cmd) & _IOC_WRITE) ret = !access_ok(VERIFY_READ, (void *)arg, arg_size); if (ret) return ret; switch (cmd) { case DS1337_SET_TIME: { u8 buf[7]; struct date_time dt; // u8 hour; copy_from_user(&dt, (void*) arg, sizeof(struct date_time)); //check parameters if(DS1337_REG_SECOND & 0x80) { printk("the second register is invalid\n"); goto out; } if(DS1337_REG_MINUTE & 0x80) { printk("the minute register is invalid\n"); goto out; } if(DS1337_REG_HOUR & 0x80) { printk("the hour register is invalid\n"); goto out; } if(DS1337_REG_DATE & 0xf8) { printk("the date register is invalid\n"); goto out; } if(DS1337_REG_DAY & 0xc0) { printk("the day register is invalid\n"); goto out; } if(DS1337_REG_MONTH & 0x60) { printk("the MONTH register is invalid\n"); goto out; } buf[0] = BIN2BCD(dt.tm_sec); buf[1] = BIN2BCD(dt.tm_min); buf[2] = BIN2BCD(dt.tm_hour); // ds1337_read( ds1337_client, DS1337_REG_HOUR, &hour); buf[3] = BIN2BCD(dt.tm_wday); buf[4] = BIN2BCD(dt.tm_mday); buf[5] = BIN2BCD(dt.tm_mon); if(dt.tm_year >=100) { buf[5]|=(1<<7); dt.tm_year -=100; } buf[6] = BIN2BCD(dt.tm_year); //write registers i2c_smbus_write_byte_data(ds1337_client, DS1337_REG_SECOND, buf[0]); i2c_smbus_write_byte_data(ds1337_client, DS1337_REG_MINUTE, buf[1]); i2c_smbus_write_byte_data(ds1337_client, DS1337_REG_HOUR, buf[2]); i2c_smbus_write_byte_data(ds1337_client, DS1337_REG_DAY, buf[3]); i2c_smbus_write_byte_data(ds1337_client, DS1337_REG_DATE, buf[4]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -