//======================================================================
// Driver for the Epson RTC module RX-8130 CE
//
// Copyright(C) SEIKO EPSON CORPORATION 2014. All rights reserved.
//
// Derived from RX-8025 driver:
// Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com>
//
// Copyright (C) 2005 by Digi International Inc.
// All rights reserved.
//
// Modified by fengjh at rising.com.cn
// <http://lists.lm-sensors.org/mailman/listinfo/lm-sensors>
// 2006.11
//
// Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com>
// Converted to new style by Wolfgang Grandegger <wg@grandegger.com>
// Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.com>
//
//
// This driver software is distributed as is, without any warranty of any kind,
// either express or implied as further specified in the GNU Public License. This
// software may be used and distributed according to the terms of the GNU Public
// License, version 2 as published by the Free Software Foundation.
// See the file COPYING in the main directory of this archive for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.
//======================================================================
#if 1
#define DEBUG
#include <linux/device.h>
#undef DEBUG
#endif
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/list.h>
#include <linux/rtc.h>
#include <linux/of_gpio.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/interrupt.h>
#include <linux/input.h>
// RX-8130 Register definitions
#define RX8130_REG_SEC 0x10
#define RX8130_REG_MIN 0x11
#define RX8130_REG_HOUR 0x12
#define RX8130_REG_WDAY 0x13
#define RX8130_REG_MDAY 0x14
#define RX8130_REG_MONTH 0x15
#define RX8130_REG_YEAR 0x16
#define RX8130_REG_ALMIN 0x17
#define RX8130_REG_ALHOUR 0x18
#define RX8130_REG_ALWDAY 0x19
#define RX8130_REG_TCOUNT0 0x1A
#define RX8130_REG_TCOUNT1 0x1B
#define RX8130_REG_EXT 0x1C
#define RX8130_REG_FLAG 0x1D
#define RX8130_REG_CTRL0 0x1E
#define RX8130_REG_CTRL1 0x1F
#define RX8130_REG_END 0x23
// Extension Register (1Ch) bit positions
#define RX8130_BIT_EXT_TSEL (7 << 0)
#define RX8130_BIT_EXT_WADA (1 << 3)
#define RX8130_BIT_EXT_TE (1 << 4)
#define RX8130_BIT_EXT_USEL (1 << 5)
#define RX8130_BIT_EXT_FSEL (3 << 6)
// Flag Register (1Dh) bit positions
#define RX8130_BIT_FLAG_VLF (1 << 1)
#define RX8130_BIT_FLAG_AF (1 << 3)
#define RX8130_BIT_FLAG_TF (1 << 4)
#define RX8130_BIT_FLAG_UF (1 << 5)
// Control 0 Register (1Еh) bit positions
#define RX8130_BIT_CTRL_TSTP (1 << 2)
#define RX8130_BIT_CTRL_AIE (1 << 3)
#define RX8130_BIT_CTRL_TIE (1 << 4)
#define RX8130_BIT_CTRL_UIE (1 << 5)
#define RX8130_BIT_CTRL_STOP (1 << 6)
#define RX8130_BIT_CTRL_TEST (1 << 7)
static const struct i2c_device_id rx8130_id[] = {
{ "rx8130", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rx8130_id);
struct rx8130_data {
struct i2c_client *client;
struct rtc_device *rtc;
struct work_struct work;
u8 ctrlreg;
unsigned exiting:1;
};
typedef struct {
u8 number;
u8 value;
}reg_data;
#define SE_RTC_REG_READ _IOWR('p', 0x20, reg_data)
#define SE_RTC_REG_WRITE _IOW('p', 0x21, reg_data)
//----------------------------------------------------------------------
// rx8130_read_reg()
// reads a rx8130 register (see Register defines)
// See also rx8130_read_regs() to read multiple registers.
//
//----------------------------------------------------------------------
static int rx8130_read_reg(struct i2c_client *client, int number, u8 *value)
{
int ret = i2c_smbus_read_byte_data(client, number) ;
//check for error
if (ret < 0) {
dev_err(&client->dev, "Unable to read register #%d\n", number);
return ret;
}
*value = ret;
return 0;
}
//----------------------------------------------------------------------
// rx8130_read_regs()
// reads a specified number of rx8130 registers (see Register defines)
// See also rx8130_read_reg() to read single register.
//
//----------------------------------------------------------------------
static int rx8130_read_regs(struct i2c_client *client, int number, u8 length, u8 *values)
{
int ret = i2c_smbus_read_i2c_block_data(client, number, length, values);
//check for length error
if (ret != length) {
dev_err(&client->dev, "Unable to read registers #%d..#%d\n", number, number + length - 1);
return ret < 0 ? ret : -EIO;
}
return 0;
}
//----------------------------------------------------------------------
// rx8130_write_reg()
// writes a rx8130 register (see Register defines)
// See also rx8130_write_regs() to write multiple registers.
//
//----------------------------------------------------------------------
static int rx8130_write_reg(struct i2c_client *client, int number, u8 value)
{
int ret = i2c_smbus_write_byte_data(client, number, value);
//check for error
if (ret)
dev_err(&client->dev, "Unable to write register #%d\n", number);
return ret;
}
//----------------------------------------------------------------------
// rx8130_write_regs()
// writes a specified number of rx8130 registers (see Register defines)
// See also rx8130_write_reg() to write a single register.
//
//----------------------------------------------------------------------
static int rx8130_write_regs(struct i2c_client *client, int number, u8 length, u8 *values)
{
int ret = i2c_smbus_write_i2c_block_data(client, number, length, values);
//check for error
if (ret)
dev_err(&client->dev, "Unable to write registers #%d..#%d\n", number, number + length - 1);
return ret;
}
//----------------------------------------------------------------------
// rx8130_irq()
// irq handler
//
//----------------------------------------------------------------------
static irqreturn_t rx8130_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct rx8130_data *rx8130 = i2c_get_clientdata(client);
disable_irq_nosync(irq);
schedule_work(&rx8130->work);
return IRQ_HANDLED;
}
//----------------------------------------------------------------------
// rx8130_work()
//
//----------------------------------------------------------------------
static void rx8130_work(struct work_struct *work)
{
struct rx8130_data *rx8130 = container_of(work, struct rx8130_data, work);
struct i2c_client *client = rx8130->client;
struct mutex *lock = &rx8130->rtc->ops_lock;
u8 status;
mutex_lock(lock);
if (rx8130_read_reg(client, RX8130_REG_FLAG, &status))
goto out;
// check VLF
if ((status & RX8130_BIT_FLAG_VLF))
dev_warn(&client->dev, "Frequency stop was detected, probably due to a supply voltage drop\n");
dev_dbg(&client->dev, "%s: RX8130_REG_FLAG: %xh\n", __func__, status);
// periodic "fixed-cycle" timer
if (status & RX8130_BIT_FLAG_TF) {
status &= ~RX8130_BIT_FLAG_TF;
local_irq_disable();
rtc_update_irq(rx8130->rtc, 1, RTC_PF | RTC_IRQF);
local_irq_enable();
}
// alarm function
if (status & RX8130_BIT_FLAG_AF) {
status &= ~RX8130_BIT_FLAG_AF;
local_irq_disable();
rtc_update_irq(rx8130->rtc, 1, RTC_AF | RTC_IRQF);
local_irq_enable();
}
// time update function
if (status & RX8130_BIT_FLAG_UF) {
status &= ~RX8130_BIT_FLAG_UF;
local_irq_disable();
rtc_update_irq(rx8130->rtc, 1, RTC_UF | RTC_IRQF);
local_irq_enable();
}
// acknowledge IRQ
rx8130_write_reg(client, RX8130_REG_FLAG, status); //clear flags
out:
if (!rx8130->exiting)
enable_irq(client->irq);
mutex_unlock(lock);
}
//----------------------------------------------------------------------
// rx8130_get_time()
// gets the current time from the rx8130 registers
//
//----------------------------------------------------------------------
static int rx8130_get_time(struct device *dev, struct rtc_time *dt)
{
struct rx8130_data *rx8130 = dev_get_drvdata(dev);
u8 date[7];
int err;
er