add a6, hres_counter drivers from HPalm

This commit is contained in:
James Sullins
2012-02-14 05:18:20 -06:00
parent 95554a56e4
commit e26b264f7a
18 changed files with 8016 additions and 0 deletions

View File

@@ -651,6 +651,11 @@ config QFP_FUSE
to the fuse block. Currently this is supported only
on FSM targets.
config HRES_COUNTER
tristate "High resolution counter"
---help---
Select Y if you want to enable High resolution counter.
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
@@ -658,5 +663,6 @@ source "drivers/misc/iwmc3200top/Kconfig"
source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
source "drivers/misc/a6/Kconfig"
endif # MISC_DEVICES

View File

@@ -68,3 +68,5 @@ obj-$(CONFIG_QFP_FUSE) += qfp_fuse.o
obj-$(CONFIG_KERNEL_LOG) += klog.o
obj-$(CONFIG_HSUART) += hsuart.o
obj-$(CONFIG_USER_PINS) += user-pins.o
obj-$(CONFIG_HRES_COUNTER) += hres_counter.o
obj-$(CONFIG_A6) += a6/

40
drivers/misc/a6/Kconfig Normal file
View File

@@ -0,0 +1,40 @@
menuconfig A6_SUPPORT
tristate "Palm A6 support"
depends on I2C
default y
help
This option enables support for Palm A6 controller.
To compile this driver as a module, choose M here.
if A6_SUPPORT
config A6
tristate "Palm A6 charging controller"
depends on I2C
default y
help
Say Y to include support for the Palm A6 charging controller.
config A6_I2C_SINGLE_BYTE
tristate "Select A6 i2c single byte read"
depends on I2C && A6
default n
help
Say Y to enable single byte i2c read for A6 driver.
config A6_I2C_SINGLE_BYTE_WRITE
tristate "Select A6 i2c single byte write"
depends on I2C && A6
default n
help
Say Y to enable single byte i2c write for A6 driver.
config A6_BATTERY
bool "Palm A6 battery driver"
depends on A6
default y
help
Say Y to include support for the Palm A6 battery.
endif # POWER_SUPPLY

5
drivers/misc/a6/Makefile Normal file
View File

@@ -0,0 +1,5 @@
obj-$(CONFIG_A6) += a6.o
obj-$(CONFIG_A6) += high_level_funcs.o
obj-$(CONFIG_A6) += low_level_funcs.o
obj-$(CONFIG_A6) += jtag_funcs.o
obj-$(CONFIG_A6_BATTERY) += a6_battery.o

4268
drivers/misc/a6/a6.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,832 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/list.h>
#include <linux/wait.h>
#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/ctype.h>
#include <linux/a6_sbw_interface.h>
#include <linux/a6.h>
#ifdef CONFIG_HIGH_RES_TIMERS
#include <linux/hrtimer.h>
#endif
#include <linux/cpufreq.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/uaccess.h>
#include <linux/types.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/poll.h>
#include <asm/io.h>
#include <linux/gpio.h>
#include <linux/debugfs.h>
#include "high_level_funcs.h"
#include <linux/firmware.h>
#include <linux/power_supply.h>
#include <linux/max8903_charger.h>
#ifdef CONFIG_HAS_EARLYSUSPEND
#include <linux/earlysuspend.h>
#include <linux/suspend.h>
#endif
/* page 0x01 */
/* battery (airboard only); interface defined by phone teams */
#define TS2_I2C_BAT_STATUS 0x0100
#define TS2_I2C_BAT_RARC 0x0101
#define TS2_I2C_BAT_RSRC 0x0102
#define TS2_I2C_BAT_AVG_CUR_MSB 0x0103
#define TS2_I2C_BAT_AVG_CUR_LSB 0x0104
#define TS2_I2C_BAT_TEMP_MSB 0x0105
#define TS2_I2C_BAT_TEMP_LSB 0x0106
#define TS2_I2C_BAT_VOLT_MSB 0x0107
#define TS2_I2C_BAT_VOLT_LSB 0x0108
#define TS2_I2C_BAT_CUR_MSB 0x0109
#define TS2_I2C_BAT_CUR_LSB 0x010a
#define TS2_I2C_BAT_COULOMB_MSB 0x010b
#define TS2_I2C_BAT_COULOMB_LSB 0x010c
#define TS2_I2C_BAT_AS 0x010d
#define TS2_I2C_BAT_FULL_MSB 0x010e
#define TS2_I2C_BAT_FULL_LSB 0x010f
#define TS2_I2C_BAT_FULL40_MSB 0x0110
#define TS2_I2C_BAT_FULL40_LSB 0x0111
#define TS2_I2C_BAT_RSNSP 0x0112
#define TS2_I2C_BAT_RAAC_MSB 0x0113
#define TS2_I2C_BAT_RAAC_LSB 0x0114
#define TS2_I2C_BAT_ROMID_0 0x0120
#define TS2_I2C_BAT_ROMID(x) \
(TS2_I2C_BAT_ROMID_0 + (x))
#define TS2_I2C_BAT_COMMAND_STATUS 0x0140
#define TS2_I2C_BAT_COMMAND_AUTH 0x81
#define TS2_I2C_BAT_COMMAND_REFRESH 0x82
#define TS2_I2C_BAT_COMMAND_WAKE 0x83
#define TS2_I2C_BAT_COMMAND_OFF 0xe9
#define TS2_I2C_BAT_STATUS_AUTH_FAIL 0x08
#define TS2_I2C_BAT_STATUS_AUTH_PASS 0x04
#define TS2_I2C_BAT_STATUS_REGS_VALID 0x02
#define TS2_I2C_BAT_STATUS_BUSY 0x01
/* battery configuration (airboard only) */
#define TS2_I2C_BAT_TEMP_LOW_MSB 0x0180
#define TS2_I2C_BAT_TEMP_LOW_LSB 0x0181
#define TS2_I2C_BAT_TEMP_HIGH_MSB 0x0182
#define TS2_I2C_BAT_TEMP_HIGH_LSB 0x0183
#define TS2_I2C_BAT_VOLT_LOW_MSB 0x0184
#define TS2_I2C_BAT_VOLT_LOW_LSB 0x0185
#define TS2_I2C_BAT_RARC_CRIT 0x0186
#define TS2_I2C_BAT_RARC_LOW_2 0x0187
#define TS2_I2C_BAT_RARC_LOW_1 0x0188
#define TS2_I2C_BAT_CHALLENGE_0 0x01e0
#define TS2_I2C_BAT_CHALLENGE(x) \
(TS2_I2C_BAT_CHALLENGE_0 + (x))
#define TS2_I2C_BAT_RESPONSE_0 \
(TS2_I2C_BAT_CHALLENGE_0 + 8)
#define TS2_I2C_BAT_RESPONSE(x) \
(TS2_I2C_BAT_RESPONSE_0 + (x))
#if defined(current)
#undef current
#endif
struct a6_battery_info {
struct i2c_client *client;
struct power_supply battery;
struct delayed_work poll_work;
struct workqueue_struct *poll_workqueue;
#ifdef CONFIG_HAS_EARLYSUSPEND
suspend_state_t pm_state;
struct early_suspend early_suspend;
#endif
int present;
int authentic;
int percentage;
int voltage;
int current;
int temperature;
unsigned int capacity; /* in uAh */
};
static struct a6_battery_info battery_info;
typedef enum {
A6_ERR_OK = 0,
A6_ERROR = -1,
A6_ERR_I2C = -2,
A6_ERR_TIMEOUT = -3,
A6_ERR_NOT_SUPPORTED = -4,
A6_ERR_BUSY = -5,
} a6_err_code;
typedef enum {
A6_CMD_REG_READ ,
A6_CMD_REG_WRITE,
} a6_reg_cmd_code;
enum {
DEVICE_BUSY_BIT = 0,
IS_OPENED,
IS_INITIALIZED_BIT,
BOOTLOAD_ACTIVE_BIT,
FORCE_WAKE_ACTIVE_BIT,
// capabilities
CAP_PERIODIC_WAKE,
#ifdef A6_PQ
STARTING_AID_TASK,
KILLING_AID_TASK,
IS_QUIESCED,
#endif
SIZE_FLAGS
};
struct a6_device_state {
struct i2c_client *i2c_dev;
struct a6_platform_data *plat_data;
struct file_operations fops;
struct miscdevice mdev;
struct mutex dev_mutex;
unsigned int timestamping;
struct timer_list a6_force_wake_timer;
struct work_struct a6_force_wake_work;
struct mutex a6_force_wake_mutex;
wait_queue_head_t dev_busyq;
struct work_struct a6_irq_work;
int32_t cpufreq_hold_flag;
uint32_t cached_rsense_val: 16;
struct workqueue_struct* ka6d_workqueue;
struct workqueue_struct* ka6d_fw_workqueue;
DECLARE_BITMAP(flags, SIZE_FLAGS);
#ifdef A6_PQ
struct completion aq_enq_complete;
struct completion aid_exit_complete;
struct mutex aq_mutex;
struct list_head aq_head;
struct task_struct* ai_dispatch_task;
#ifdef A6_DEBUG
uint32_t dbgflg_kill_raid: 1;
uint8_t debug_restart_aid;
uint8_t debug_flush_aiq;
uint8_t debug_unused_01;
uint8_t debug_unused_02;
#endif
#endif
int cpufreq_hold;
};
struct a6_reg_cmd
{
a6_reg_cmd_code cmd;
uint16_t reg;
uint8_t data;
};
#define CHALLENGE_SIZE 8
#define MAC_SIZE 20
#define R_SENSE r_sense
#define SIGN_EXTEND16(x) ((x)-(((x)&0x8000)?65536:0))
#define CURRENT_VALUE(x) ((SIGN_EXTEND16(x)*3125)/2/R_SENSE) // in uA
#define VOLTAGE_VALUE(x) (4880*((x)>>5)) // in micro volt
#define COULOMB_VALUE(x) ((6250*(x))/R_SENSE)
#define REG_COULOMB_VALUE(x) ((R_SENSE*(x))/6250)
#define CAPACITY_VALUE(x) (1600*(x)) // in micro Ahr
#define CAPACITY_PERCENT(x) (392*x) // in thousands of %
#define BATTERY_DEFAULT_CHALLENGE \
{ 0x74, 0xca, 0x85, 0x99, 0x19, 0xde, 0xd1, 0xb3 }
#define BATTERY_DEFAULT_RESPONSE \
{ 0x87, 0xed, 0x20, 0x89, 0xad, 0x68, 0xa2, 0xcd, 0x6f, 0x93, \
0x13, 0x03, 0x07, 0x5a, 0x29, 0x85, 0xdc, 0x2e, 0xe9, 0x50 }
static int battery_authentic = 0;
static int r_sense = 20;
#define A6_BATTERY_POLLING_DELAY_MS (10)
#define A6_BATTERY_POLLING_TIMEOUT_CNT (20)
void a6_delay(uint32_t delay_ms){
msleep(delay_ms);
}
int32_t a6_i2c_read_reg(struct i2c_client* client, const uint16_t* ids, uint32_t num_ids, uint8_t* out);
int32_t a6_i2c_write_reg(struct i2c_client* client, const uint16_t* ids, uint32_t num_ids, const uint8_t* in);
a6_err_code a6_send_reg_commands(struct a6_reg_cmd *cmdlist, int count)
{
a6_err_code res = A6_ERR_OK;
int i;
struct a6_reg_cmd *p_cmd = cmdlist;
struct a6_device_state* state = i2c_get_clientdata(battery_info.client);
/* return if a6 un-initialized */
if (!test_bit(IS_INITIALIZED_BIT, state->flags)) {
pr_debug("%s: a6 un-initialized: exiting.\n", __func__);
res = A6_ERROR;
return res;
}
/* loop through to send all commands */
for (i = 0; i < count; i++) {
int i2c_res;
if (p_cmd->cmd == A6_CMD_REG_READ ) {
i2c_res = a6_i2c_read_reg(battery_info.client, &(p_cmd->reg), 1, &(p_cmd->data));
if (i2c_res < 0) {
res = A6_ERR_I2C;
}
} else if (p_cmd->cmd == A6_CMD_REG_WRITE) {
i2c_res = a6_i2c_write_reg(battery_info.client, &(p_cmd->reg), 1, &(p_cmd->data));
if (i2c_res < 0) {
res = A6_ERR_I2C;
}
} else {
printk("A6 a6_send_reg_commands : Unknown Cmd %x\n", p_cmd->cmd);
res = A6_ERROR;
}
//Workaround for A6 I2C read issue
//a6_delay(1);
p_cmd++;
}
return res;
}
static a6_err_code a6_battery_wait_busy(uint8_t clear_flags, uint8_t set_flags, uint8_t *p_status) {
int i;
a6_err_code res = A6_ERR_OK;
uint8_t status = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_COMMAND_STATUS,
},
};
for ( i = A6_BATTERY_POLLING_TIMEOUT_CNT; i > 0; i-- ) {
res = a6_send_reg_commands(cmdlist, 1);
if (res != A6_ERR_OK) {
goto a6_battery_wait_busy_exit;
} else {
status = cmdlist[0].data;
}
if ( ( !set_flags || (status & set_flags) != 0) && ( !clear_flags || ((~status) & clear_flags) != 0 )) {
break;
}
a6_delay(A6_BATTERY_POLLING_DELAY_MS);
};
if ( i <= 0 ) {
res = A6_ERROR;
} else if ( p_status ) {
*p_status = status;
}
a6_battery_wait_busy_exit:
return res;
}
//:TODO: Add busy handling - probably return the last value
//:TODO: Add A6 capabilites handling
int battery_get_percentage(void)
{
ushort percentage = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_RARC,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_percentage_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 1)) {
goto battery_get_percentage_exit;
} else {
percentage = cmdlist[0].data;
}
battery_get_percentage_exit:
return percentage;
}
int battery_get_voltage(void)
{
int res = 0;
ushort voltage = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_VOLT_MSB,
},
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_VOLT_LSB,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_voltage_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 2)) {
goto battery_get_voltage_exit;
} else {
voltage = (cmdlist[0].data << 8) | cmdlist[1].data;
res = VOLTAGE_VALUE(voltage);
}
battery_get_voltage_exit :
return res;
}
static int battery_get_r_sense(void)
{
int res = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_RSNSP,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_r_sense_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 1)) {
goto battery_get_r_sense_exit;
} else {
res = 1000 / cmdlist[0].data;
}
battery_get_r_sense_exit :
return res;
}
int battery_get_current(void)
{
int res = 0;
ushort cur;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_CUR_MSB,
},
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_CUR_LSB,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_current_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 2)) {
goto battery_get_current_exit;
} else {
cur = (cmdlist[0].data << 8) | cmdlist[1].data;
res = CURRENT_VALUE(cur);
}
battery_get_current_exit :
return res;
}
/**
* @brief Return the battery temperature.
*
* Temperature value is a 11-bit two's-complement integer with a 1/8
* degrees Centigrade resolution:
* MSB: 7 6 5 4 3 2 1 0 LSB: 7 6 5 4 3 2 1 0
* s i i i i i i i f f f _ _ _ _ _
*
* s: sign
* i: integer part
* f: fraction part
* _: N/A
*
* We discard the fraction and only return the signed integer value.
*/
int battery_get_temperature(void)
{
int res = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_TEMP_MSB,
},
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_TEMP_LSB,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_temperature_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 2)) {
goto battery_get_temperature_exit;
} else {
/* Only return the signed integer value */
res = (int8_t)cmdlist[0].data;
}
battery_get_temperature_exit:
return res;
}
unsigned int battery_get_capacity(void)
{
unsigned int res = 0;
static struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_RAAC_MSB,
},
{
.cmd = A6_CMD_REG_READ,
.reg = TS2_I2C_BAT_RAAC_LSB,
},
};
if ( A6_ERR_OK != a6_battery_wait_busy(0, TS2_I2C_BAT_STATUS_REGS_VALID, NULL)){
goto battery_get_capacity_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(cmdlist, 2)) {
goto battery_get_capacity_exit;
} else {
uint32_t capacity = (cmdlist[0].data << 8) | cmdlist[1].data;
res = CAPACITY_VALUE(capacity);
}
battery_get_capacity_exit:
return res;
}
int battery_is_present(void)
{
int rc = 0;
if (battery_get_voltage() == 0 && battery_get_current() == 0)
{
// We do not have a battery, or best case the battery we have is unusable
rc = -1;
}
return (rc < 0) ? 0 : 1;
}
int battery_reauthenticate(void)
{
int res = 0;
int i;
uint8_t batt_cmd_status = 0;
static int cmd_lists_initiated = 0;
static const uint8_t dc[] = BATTERY_DEFAULT_CHALLENGE;
static const uint8_t dr[] = BATTERY_DEFAULT_RESPONSE;
static struct a6_reg_cmd send_challenge_cmdlist[CHALLENGE_SIZE];
static struct a6_reg_cmd get_response_cmdlist[MAC_SIZE];
static struct a6_reg_cmd authenticate_cmdlist[] = {
{
.cmd = A6_CMD_REG_WRITE,
.reg = TS2_I2C_BAT_COMMAND_STATUS,
.data = TS2_I2C_BAT_COMMAND_AUTH,
},
};
printk("Starting battery authentication...\n");
if ( !cmd_lists_initiated ) {
//Init the challenge a6 cmd list
for ( i = 0; i < CHALLENGE_SIZE; i ++ ) {
send_challenge_cmdlist[i].cmd = A6_CMD_REG_WRITE;
send_challenge_cmdlist[i].reg = TS2_I2C_BAT_CHALLENGE(i);
send_challenge_cmdlist[i].data = dc[i];
}
//Init the response a6 cmd list
for ( i = 0; i < MAC_SIZE; i ++ ) {
get_response_cmdlist[i].cmd = A6_CMD_REG_READ;
get_response_cmdlist[i].reg = TS2_I2C_BAT_RESPONSE(i);
}
cmd_lists_initiated = 1;
}
if ( A6_ERR_OK != a6_battery_wait_busy(TS2_I2C_BAT_STATUS_BUSY, 0, NULL)){
goto battery_reauthenticate_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(send_challenge_cmdlist, CHALLENGE_SIZE)) {
goto battery_reauthenticate_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(authenticate_cmdlist, 1)) {
goto battery_reauthenticate_exit;
}
a6_delay(10);
if ( A6_ERR_OK != a6_battery_wait_busy(TS2_I2C_BAT_STATUS_BUSY, 0, &batt_cmd_status)){
goto battery_reauthenticate_exit;
}
if ( batt_cmd_status & TS2_I2C_BAT_STATUS_AUTH_FAIL ) {
goto battery_reauthenticate_exit;
}
if (A6_ERR_OK != a6_send_reg_commands(get_response_cmdlist, MAC_SIZE)) {
goto battery_reauthenticate_exit;
}
res = 1;
//Validate response
for ( i = 0; i < MAC_SIZE; i++) {
if ( dr[i] != get_response_cmdlist[i].data ) {
res = 0;
break;
}
}
if (0 == res) {
printk("*** Battery Authentication Failure: ***\n");
printk("*** [Expected and actual response dump] ***\n");
for ( i = 0; i < MAC_SIZE; i++) {
printk("exp-resp: 0x%02x act-resp: 0x%02x\n", dr[i], get_response_cmdlist[i].data);
}
} else {
printk("Battery authentication successful.\n");
}
battery_reauthenticate_exit :
battery_authentic = res;
return res;
}
int battery_set_authentic(bool authentic)
{
battery_authentic = authentic;
return battery_authentic;
}
static a6_err_code a6_battery_send_command(uint8_t command)
{
a6_err_code res = A6_ERR_OK;
res = a6_battery_wait_busy(TS2_I2C_BAT_STATUS_BUSY, 0, NULL);
if ( A6_ERR_OK == res ){
struct a6_reg_cmd cmdlist[] = {
{
.cmd = A6_CMD_REG_WRITE,
.reg = TS2_I2C_BAT_COMMAND_STATUS,
.data = command,
}
};
res = a6_send_reg_commands(cmdlist, 1);
}
return res;
}
static a6_err_code battery_refresh_regs(void)
{
a6_err_code res = A6_ERR_OK;
res = a6_battery_send_command(TS2_I2C_BAT_COMMAND_REFRESH);
if ( res == A6_ERR_OK ) {
msleep(20);
}
return res;
}
void battery_startup(void)
{
if ( a6_battery_send_command(TS2_I2C_BAT_COMMAND_WAKE) == A6_ERR_OK ) {
//Wait for 200 ms for battery to be woken up
msleep(200);
//Refresh all the registers
if ( battery_refresh_regs() == A6_ERR_OK ) {
int r_sense_tmp;
r_sense_tmp = battery_get_r_sense();
if ( r_sense_tmp ) {
r_sense = r_sense_tmp;
}
}
}
}
void battery_sleep(void)
{
a6_battery_send_command(TS2_I2C_BAT_COMMAND_OFF);
}
int battery_read(struct a6_battery_info *batt_info)
{
battery_refresh_regs();
batt_info->present = battery_is_present();
if (!batt_info->present) {
return 0;
}
batt_info->authentic = battery_authentic; /* read once on init */
batt_info->percentage = battery_get_percentage();
batt_info->voltage = battery_get_voltage();
batt_info->current = battery_get_current();
batt_info->temperature = battery_get_temperature();
batt_info->capacity = battery_get_capacity();
return 0;
}
static enum power_supply_property a6_battery_props[] = {
POWER_SUPPLY_PROP_STATUS,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_VOLTAGE_NOW,
POWER_SUPPLY_PROP_TEMP,
POWER_SUPPLY_PROP_HEALTH,
POWER_SUPPLY_PROP_TECHNOLOGY,
POWER_SUPPLY_PROP_PRESENT,
};
static void a6_battery_ext_power_changed(struct power_supply *psy)
{
//battery_read(&battery_info);
//pr_debug("%s(%d) : battery_info.percentage = %d, battery_info.voltage = %d, battery_info.current = %d, battery_info.temperature = %d\n",
// __func__, __LINE__, battery_info.percentage, battery_info.voltage, battery_info.current, battery_info.temperature);
//power_supply_changed(psy);
pr_debug("%s(%d): battery_info.pm_state = %d", __func__, __LINE__, battery_info.pm_state);
if (battery_info.pm_state < PM_SUSPEND_MEM) {
if (delayed_work_pending(&(battery_info.poll_work))) {
cancel_delayed_work_sync(&(battery_info.poll_work));
}
queue_delayed_work(battery_info.poll_workqueue , &(battery_info.poll_work), msecs_to_jiffies(10));
}
}
static int a6_battery_get_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
int status, ret = 0;
bool charger_is_charging = false, charger_is_connecting = false;
switch (prop) {
case POWER_SUPPLY_PROP_STATUS:
charger_is_charging = max8903_charger_is_charging();
charger_is_connecting = max8903_charger_is_connecting();
//status
if (!battery_info.present) {
status = POWER_SUPPLY_STATUS_UNKNOWN;
} else {
if ((battery_info.percentage== 100) && charger_is_connecting && !charger_is_charging)
status = POWER_SUPPLY_STATUS_FULL;
else if (charger_is_connecting && !charger_is_charging)
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
else if (!charger_is_connecting)
status = POWER_SUPPLY_STATUS_DISCHARGING;
else
status = POWER_SUPPLY_STATUS_CHARGING;
}
pr_debug("A6_BATTEERY : (%s) (%d) : prop = %d, status = %d, percentage = %d, charger_is_connecting = %d, charger_is_charging = %d\n",
__func__, __LINE__, prop, status, battery_info.percentage, charger_is_connecting, charger_is_charging);
val->intval = status;
break;
case POWER_SUPPLY_PROP_CAPACITY:
//capacity
pr_debug("A6_BATTEERY : (%s) (%d) : prop = %d, capacity = %d\n", __func__, __LINE__, prop, battery_info.percentage);
val->intval = battery_info.percentage;
break;
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
pr_debug("A6_BATTEERY : (%s) (%d) : prop = %d, voltage_mV = %d\n", __func__, __LINE__, prop, battery_info.voltage);
val->intval = battery_info.voltage;
break;
case POWER_SUPPLY_PROP_TEMP:
//temp
pr_debug("A6_BATTEERY : (%s) (%d) : prop = %d, temp_c = %d\n", __func__, __LINE__, prop, battery_info.temperature);
val->intval = battery_info.temperature * 10;
break;
case POWER_SUPPLY_PROP_HEALTH:
val->intval = POWER_SUPPLY_HEALTH_GOOD;
break;
case POWER_SUPPLY_PROP_TECHNOLOGY:
val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
break;
case POWER_SUPPLY_PROP_PRESENT:
val->intval = battery_info.present;
break;
default:
ret = -EINVAL;
}
return ret;
}
void a6_battery_poll_work_handler(struct work_struct *work)
{
battery_read(&battery_info);
pr_debug("%s(%d) : battery_info.percentage = %d, battery_info.voltage = %d, battery_info.current = %d, battery_info.temperature = %d\n",
__func__, __LINE__, battery_info.percentage, battery_info.voltage, battery_info.current, battery_info.temperature);
power_supply_changed(&(battery_info.battery));
queue_delayed_work(battery_info.poll_workqueue , &(battery_info.poll_work), msecs_to_jiffies(10 * 1000));
}
#ifdef CONFIG_HAS_EARLYSUSPEND
void batt_early_suspend(struct early_suspend *h)
{
pr_debug("%s(%d): enter\n", __func__, __LINE__);
if (delayed_work_pending(&(battery_info.poll_work))) {
cancel_delayed_work_sync(&(battery_info.poll_work));
}
battery_info.pm_state = PM_SUSPEND_MEM;
pr_debug("%s: exit\n", __func__);
}
void batt_late_resume(struct early_suspend *h)
{
pr_debug("%s(%d): enter\n", __func__, __LINE__);
if (delayed_work_pending(&(battery_info.poll_work))) {
cancel_delayed_work_sync(&(battery_info.poll_work));
}
queue_delayed_work(battery_info.poll_workqueue , &(battery_info.poll_work), msecs_to_jiffies(1));
battery_info.pm_state = PM_SUSPEND_ON;
pr_debug("%s(%d): exit\n", __func__, __LINE__);
}
#endif
void a6_battery_init(struct i2c_client *a6_i2c_client)
{
battery_info.battery.name = "battery";
battery_info.battery.type = POWER_SUPPLY_TYPE_BATTERY;
battery_info.battery.properties = a6_battery_props;
battery_info.battery.num_properties = ARRAY_SIZE(a6_battery_props);
battery_info.battery.get_property = a6_battery_get_property;
battery_info.battery.external_power_changed = a6_battery_ext_power_changed;
battery_info.client = a6_i2c_client;
#ifdef CONFIG_HAS_EARLYSUSPEND
battery_info.pm_state = PM_SUSPEND_ON;
battery_info.early_suspend.level = EARLY_SUSPEND_LEVEL_BLANK_SCREEN;
battery_info.early_suspend.suspend =batt_early_suspend;
battery_info.early_suspend.resume = batt_late_resume;
register_early_suspend(&battery_info.early_suspend);
#endif
battery_startup();
battery_reauthenticate();
battery_read(&battery_info);
printk("battery_info.percentage = %d, battery_info.voltage = %d, battery_info.current = %d, battery_info.temperature = %d\n",
battery_info.percentage, battery_info.voltage, battery_info.current, battery_info.temperature);
battery_info.poll_workqueue = create_workqueue("a6_battery_poll_workqueue");
INIT_DELAYED_WORK(&(battery_info.poll_work), a6_battery_poll_work_handler);
power_supply_register(&(a6_i2c_client->dev), &(battery_info.battery));
queue_delayed_work(battery_info.poll_workqueue , &(battery_info.poll_work), msecs_to_jiffies(10 * 1000));
}

View File

@@ -0,0 +1,59 @@
#ifndef A6_HOST_ADAPTER_H
#define A6_HOST_ADAPTER_H
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/uaccess.h>
#include <linux/slab.h>
#include <linux/hres_counter.h>
#include <linux/a6_sbw_interface.h>
#include <linux/a6.h>
#ifndef __BYTEWORD__
#define __BYTEWORD__
typedef unsigned short int word;
typedef unsigned char byte;
#endif
//---------------- Should be selected desired option ------------------------
#define ACTIVATE_MAGIC_PATTERN 1
//---------------------------------------------------------------------------
#ifndef __DATAFORMATS__
#define __DATAFORMATS__
#define F_BYTE 8
#define F_WORD 16
#define F_ADDR 20
#define F_LONG 32
#endif
// Constants for runoff status
#define STATUS_ERROR 0 // false
#define STATUS_OK 1 // true
#define STATUS_FUSEBLOWN 2 // GetDevice returns if the security fuse is blown
#define STATUS_ACTIVE 2
#define STATUS_IDLE 3
#define nNOPS {delay(1);} //{ _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); _NOP(); }
/********/
/* Host adapter for the sbw layer */
/********/
// per-target functions (separate implementation per target)
#define DisableInterrupts(flags) (a6_disable_interrupts(flags))
#define EnableInterrupts(flags) (a6_enable_interrupts(flags))
#define MsDelay(milliseconds) {delay(milliseconds * 1000);} // millisecond delay loop
#define usDelay(microseconds) {delay(microseconds);} // microsecond delay loop
#endif

View File

@@ -0,0 +1,527 @@
/****************************************************************************/
/* Includes */
/****************************************************************************/
#include "a6_host_adapter.h" // Maps function calls to host porting-layer implementations
#include "jtag_funcs.h" // Spy-by-wire JTAG functions
#include "low_level_funcs.h" // low level user functions
#define LOCAL_TRACE 0
/****************************************************************************/
/* Global types */
/****************************************************************************/
/****************************************************************************/
/* Main section of Replicator program: User can modify/insert code as needed*/
/****************************************************************************/
/*
Note: All High Level JTAG Functions are applied here.
*/
// definition for current implementation mappings used by the sbw code...
uint16_t (*SetSBWTCK)(void) = NULL;
uint16_t (*ClrSBWTCK)(void) = NULL;
uint16_t (*SetSBWTDIO)(void) = NULL;
uint16_t (*ClrSBWTDIO)(void) = NULL;
uint16_t (*SetInSBWTDIO)(void) = NULL;
uint16_t (*SetOutSBWTDIO)(void) = NULL;
uint16_t (*GetSBWTDIO)(void) = NULL;
uint16_t (*SetSBWAKEUP)(void) = NULL;
uint16_t (*ClrSBWAKEUP)(void) = NULL;
void (*delay)(uint32_t delay_us) = NULL;
//
typedef enum {
SBW_OK = 0,
SBW_TOK,
SBW_EOL,
SBW_EOS,
SBW_SOS,
SBW_EOI,
SBW_STATE_ERROR
} SBW_STATE_CODE;
#define SIZEOF_NEWLINE (1)
static int hexval(char c)
{
if (c >= '0' && c <= '9')
return c - '0';
else if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
else if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return 0;
}
SBW_STATE_CODE sbw_get_token(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
//assert(read_p && read_len_p && write_len_p);
// end-of-line
if (0x0d == *read_p && 0x0a == *(read_p+1)) {
*read_len_p = 2;
*write_len_p = 0;
ret = SBW_EOL;
//printk("<EOL>\n");
}
// end-of-image
else if (('q' == *read_p) || ('Q' == *read_p)) {
*read_len_p = 1;
*write_len_p = 0;
ret = SBW_EOI;
//printk("<EOI>\n");
}
else {
uint32_t val = 0;
// section start
if ('@' == read_p[0]) {
ret = SBW_SOS;
val = hexval(read_p[1 + 0]) << 12;
val |= hexval(read_p[1 +1]) << 8;
val |= hexval(read_p[1 +2]) << 4;
val |= hexval(read_p[1 +3]);
*read_len_p = 1+4+2; //'@' + XXXX + CRLF
*write_len_p = 2; // two bytes written
//printk("<SOS>\n");
}
// data
else {
ret = SBW_TOK;
val = hexval(read_p[0]) << 4;
val |= hexval(read_p[1]);
// handle variation: the last 2-byte value on a line may not include trailing space
*read_len_p = 2+1; //XX + ' '
//*read_len_p = 2 + (' ' == read_p[2]) ? 1 : 0; //XX + ' '
*write_len_p = 1; // one byte written
}
// no target? skip the actual write...
if (write_p) {
//*((uint32_t*)write_p) = val;
write_p[0] = val & 0x000000ff;
write_p[1] = (val >> 8) & 0x000000ff;
write_p[2] = (val >> 16) & 0x000000ff;
write_p[3] = (val >> 24) & 0x000000ff;
}
//printk("%02x ", val);
}
return ret;
}
SBW_STATE_CODE sbw_parse_line(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, val = 0, r_len = 0, w_len = 0;
do {
ret = sbw_get_token(read_p, (uint8_t*)&val, &r_len, &w_len);
// end-of-line; break out of loop
if (SBW_EOL == ret) {
total_read_len += r_len;
*read_len_p = total_read_len;
total_write_len += w_len;
*write_len_p = total_write_len;
}
// regular token; keep looping
else if (SBW_TOK == ret) {
*((uint8_t*)write_p) = (uint8_t)val;
total_read_len += r_len;
read_p += r_len;
total_write_len += w_len;
write_p += w_len;
}
// map start-of-section/end-of-image to end-of-section
else if ((SBW_SOS == ret) || (SBW_EOI == ret)) {
*read_len_p = *write_len_p = 0;
ret = SBW_EOS;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_line]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_TOK == ret);
return ret;
}
SBW_STATE_CODE sbw_parse_section(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, r_len = 0, w_len = 0;
do {
ret = sbw_parse_line(read_p, write_p, &r_len, &w_len);
// end-of-section; break out of loop
if (SBW_EOS == ret){
total_read_len += r_len;
*read_len_p = total_read_len;
total_write_len += w_len;
*write_len_p = total_write_len;
}
// end-of-line; keep looping
else if (SBW_EOL == ret) {
total_read_len += r_len;
read_p += r_len;
total_write_len += w_len;
write_p += w_len;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_section]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_EOL == ret);
return ret;
}
typedef struct {
uint32_t sec_addr[75];
uint32_t sec_len[75];
uint32_t num_sections;
} sec_info_struct;
sec_info_struct sec_info;
int32_t sec_index = 0;
SBW_STATE_CODE sbw_parse_image(uint8_t* read_p, uint8_t* write_p, uint32_t* read_len_p, uint32_t* write_len_p)
{
SBW_STATE_CODE ret;
uint32_t total_read_len = 0, total_write_len = 0, r_len = 0, w_len = 0, val = 0;
memset(&sec_info, 0, sizeof(sec_info));
do {
ret = sbw_get_token(read_p, (uint8_t*)&val, &r_len, &w_len);
if (SBW_SOS != ret) {
if (!sec_info.num_sections) {
printk("SBW_ERROR[sbw_parse_image]: does not start with section; value: %d\n", ret);
return SBW_STATE_ERROR;
}
if (SBW_EOI == ret) {
*read_len_p = total_read_len;
*write_len_p = total_write_len;
ret = SBW_OK;
break;
}
else {
printk("SBW_ERROR[sbw_parse_image]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
break;
}
}
//printk("[Status]: SOS detected; address: %x, r_len: %d, w_len: %d\n", val, r_len, w_len);
total_read_len += r_len;
read_p += r_len;
sec_info.sec_addr[sec_info.num_sections] = val;
ret = sbw_parse_section(read_p, write_p, &r_len, &w_len);
// end-of-section; keep looping
if (SBW_EOS == ret) {
total_read_len += r_len;
read_p += r_len;
if (w_len & 1) {
write_p[w_len] = 0xff;
w_len++;
}
total_write_len += w_len;
write_p += w_len;
// sec_len converted to A6 words (16-bit)
sec_info.sec_len[sec_info.num_sections] = w_len/2;
sec_info.num_sections++;
}
// state mismatch
else {
printk("SBW_ERROR[sbw_parse_image:1]: wrong state returned; state: %d\n", ret);
ret = SBW_STATE_ERROR;
}
} while (SBW_EOS == ret);
if (SBW_OK == ret) {
int idx = 0;
printk("Parsing complete. Read size: %d, Write size: %d. Num sections: %d\n",
*read_len_p, *write_len_p, sec_info.num_sections);
while (idx < (int)sec_info.num_sections) {
printk("Section idx: %d; Addr: 0x%04x; Length: %d\n",
idx, sec_info.sec_addr[idx], sec_info.sec_len[idx]);
idx++;
}
/*
printk("\nDumping converted data:\n");
for (idx = 0; idx < (int)*write_len_p; idx++) {
if (!(idx % 16)) {
printk("\n");
}
printk("%02x ", (write_p-*write_len_p)[idx]);
}
*/
}
return ret;
}
int program_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address)
{
uint32_t read_len = 0, write_len = 0;
SBW_STATE_CODE parse_ret;
int retry = 0, ret_val = 0;
uint16_t addr;
if (read_address & 1) {
printk("program_fw: Please enter an even read address.\n");
return -1;
}
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
parse_ret = sbw_parse_image((uint8_t*)read_address, (uint8_t*)read_address/*write_p*/, &read_len, &write_len);
if (SBW_OK != parse_ret) {
printk("Error in parsing A6 fw file...\n");
return -1;
}
/* TEMP: Workaround for occasional verification failure. Not root-Caused yet but,
empirically, a retry always works. Revisit.*/
retry_0:
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
// Program the boot code
if (!WriteAllSections((const unsigned short*)read_address, (const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections))
{
printk("Error in WriteAllSections(all)\n");
ret_val = -1;
goto err0;
}
if (!VerifyAllSections((const unsigned short*)read_address, (const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections))
{
printk("Error in VerifyAllSections(all)\n");
printk("Retrying...\n\n");
if (retry++ < 15) {
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, ERROR); // set PC to V_RESET contents
ReleaseTarget();
goto retry_0;
}
else {
printk("Failure to write and verify fw file after %d retries\n", retry);
ret_val = -1;
}
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
if (ReleaseDevice(addr, PROGRAM) < 0) { // set PC to V_RESET contents
printk(KERN_ERR "Checksum validation failed post-flashing.\n");
if (retry < 15) {
printk(KERN_ERR "Retrying...\n\n");
retry++;
ReleaseTarget();
goto retry_0;
}
else {
printk(KERN_ERR "Failure to program fw after %d retries.\n", retry);
ret_val = -1;
}
}
// if fail to set JTAG mode
if (ret_val == -1 && retry == 0 ) {
retry++;
ret_val = 0;
goto retry_0;
}
ReleaseTarget();
return ret_val;
}
int verify_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address)
{
uint32_t read_len = 0, write_len = 0;
SBW_STATE_CODE parse_ret;
int ret_val = 0;
uint16_t addr;
if (read_address & 1) {
printk("program_fw: Please enter an even read address.\n");
return -1;
}
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
parse_ret = sbw_parse_image( (uint8_t*)read_address,
(uint8_t*)read_address/*write_p*/,
&read_len, &write_len);
if (SBW_OK != parse_ret) {
printk("Error in parsing A6 fw file...\n");
return -1;
}
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
if (!VerifyAllSections((const unsigned short*)read_address,
(const unsigned long *)&sec_info.sec_addr[0],
(const unsigned long *)&sec_info.sec_len[0], sec_info.num_sections)) {
printk("Error in VerifyAllSections(all)\n");
ret_val = -1;
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, VERIFY); // set PC to V_RESET contents
ReleaseTarget();
return ret_val;
}
int ttf_extract_fw_sbw(struct a6_sbw_interface* sbw_ops)
{
int ret_val = 0;
uint16_t addr;
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
InitTarget();
// Start of SBW access to the Target
if (GetDevice() != STATUS_OK) // Set DeviceId
{
printk("Error in GetDevice()\n"); // stop here if invalid JTAG ID or
// time-out. (error: red LED is ON)
ret_val = -1;
goto err0;
}
if (!TTFExtractAllSections()) {
printk("Error in TTFExtractAllSections\n");
ret_val = -1;
}
err0:
addr = ReadMem_430Xv2(F_WORD, V_RESET);
ReleaseDevice(addr, VERIFY); // set PC to V_RESET contents
ReleaseTarget();
return ret_val;
}
int ttf_image_read(char *buf, size_t count, loff_t *ppos)
{
return TTFImageRead(buf, count, ppos);
}
int ttf_extract_cache_clear(void)
{
TTFExtractCacheClear();
return 0;
}
int get_checksum_data_sbw(struct a6_sbw_interface* sbw_ops, unsigned short* cksum1,
unsigned short* cksum2, unsigned short* cksum_cycles,
unsigned short* cksum_errors)
{
// set up the current mappings for the sbw code...
SetSBWTCK = sbw_ops->a6_per_device_interface.SetSBWTCK;
ClrSBWTCK = sbw_ops->a6_per_device_interface.ClrSBWTCK;
SetSBWTDIO = sbw_ops->a6_per_device_interface.SetSBWTDIO;
ClrSBWTDIO = sbw_ops->a6_per_device_interface.ClrSBWTDIO;
SetInSBWTDIO = sbw_ops->a6_per_device_interface.SetInSBWTDIO;
SetOutSBWTDIO = sbw_ops->a6_per_device_interface.SetOutSBWTDIO;
GetSBWTDIO = sbw_ops->a6_per_device_interface.GetSBWTDIO;
SetSBWAKEUP = sbw_ops->a6_per_device_interface.SetSBWAKEUP;
ClrSBWAKEUP = sbw_ops->a6_per_device_interface.ClrSBWAKEUP;
delay = sbw_ops->a6_per_target_interface.delay;
return GetChecksumData(cksum1, cksum2, cksum_cycles, cksum_errors);
}

View File

@@ -0,0 +1,13 @@
#ifndef _high_level_funcs_h_
#define _high_level_funcs_h_
int program_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address);
int verify_device_sbw(struct a6_sbw_interface* sbw_ops, uint32_t read_address);
int ttf_extract_fw_sbw(struct a6_sbw_interface* sbw_ops);
int ttf_extract_cache_clear(void);
int ttf_image_read(char *buf, size_t count, loff_t *ppos);
int get_checksum_data_sbw(struct a6_sbw_interface* sbw_ops, unsigned short* cksum1,
unsigned short* cksum2, unsigned short* cksum_cycles,
unsigned short* cksum_errors);
#endif

1070
drivers/misc/a6/jtag_funcs.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,126 @@
#ifndef __BYTEWORD__
#define __BYTEWORD__
typedef unsigned int word;
typedef unsigned char byte;
#endif
/****************************************************************************/
/* Define section for constants */
/****************************************************************************/
// Constants for the JTAG instruction register (IR, requires LSB first).
// The MSB has been interchanged with LSB due to use of the same shifting
// function as used for the JTAG data register (DR, requires MSB first).
// Instructions for the JTAG control signal register
#define IR_CNTRL_SIG_16BIT 0xC8 // 0x13 original values
#define IR_CNTRL_SIG_CAPTURE 0x28 // 0x14
#define IR_CNTRL_SIG_RELEASE 0xA8 // 0x15
// Instructions for the JTAG Fuse
#define IR_PREPARE_BLOW 0x44 // 0x22
#define IR_EX_BLOW 0x24 // 0x24
// Instructions for the JTAG data register
#define IR_DATA_16BIT 0x82 // 0x41
#define IR_DATA_QUICK 0xC2 // 0x43
// Instructions for the JTAG PSA mode
#define IR_DATA_PSA 0x22 // 0x44
#define IR_SHIFT_OUT_PSA 0x62 // 0x46
// Instructions for the JTAG address register
#define IR_ADDR_16BIT 0xC1 // 0x83
#define IR_ADDR_CAPTURE 0x21 // 0x84
#define IR_DATA_TO_ADDR 0xA1 // 0x85
// Bypass instruction
#define IR_BYPASS 0xFF // 0xFF
// JTAG identification value for all existing Flash-based MSP430 devices
#define JTAG_ID 0x89
#define JTAG_ID91 0x91
// Jtag 17
#define DEVICE_HAS_JTAG17 1
// additional instructions for JTAG_ID91 architectures
#define IR_COREIP_ID 0xE8 // 0x17
#define IR_DEVICE_ID 0xE1 // 0x87
// Instructions for the JTAG mailbox
#define IR_JMB_EXCHANGE 0x86 // 0x61
#define IR_TEST_REG 0x54 // 0x2A
// Constants for JTAG mailbox data exchange
#define OUT1RDY 0x0008
#define IN0RDY 0x0001
#define JMB32B 0x0010
#define OUTREQ 0x0004
#define INREQ 0x0001
// Constants for data formats, dedicated addresses
#ifndef __DATAFORMATS__
#define __DATAFORMATS__
#define F_BYTE 8
#define F_WORD 16
#define F_ADDR 20
#define F_LONG 32
#endif
#define V_RESET 0xFFFE
#define V_BOR 0x1B08
// Constants for VPP connection at Blow-Fuse
#define VPP_ON_TDI 0
#define VPP_ON_TEST 1
// ReleaseDevice parameters
#define INIT 0 // ReleaseDevice() status
#define ERROR 1 // inc verify error count
#define VERIFY 2 // inc verify pass count
#define PROGRAM 3 // inc reprogram count
/****************************************************************************/
/* Function prototypes */
/****************************************************************************/
// Low level JTAG functions
//static word DR_Shift16(word Data);
//static unsigned long DR_Shift20(unsigned long address);
//static word IR_Shift(byte Instruction);
//static void ResetTAP(void);
//static word ExecutePOR_430Xv2(void);
//static void SetPC_430Xv2(unsigned long Addr);
word VerifyPSA_430Xv2(unsigned long StartAddr, unsigned long Length, word *DataArray);
// High level JTAG functions
word GetDevice_430Xv2(void);
#define GetDevice GetDevice_430Xv2
int ReleaseDevice_430Xv2(unsigned long Addr, byte Stat);
#define ReleaseDevice ReleaseDevice_430Xv2
void WriteMem_430Xv2(word Format, unsigned long Addr, word Data);
#define WriteMem WriteMem_430Xv2
void WriteMemQuick_430Xv2(unsigned long StartAddr, unsigned long Length, word *DataArray);
#define WriteMemQuick WriteMemQuick_430Xv2
word WriteAllSections_430Xv2(const unsigned short *data, const unsigned long *address, const unsigned long *length_of_sections, const unsigned long sections);
#define WriteAllSections WriteAllSections_430Xv2
word VerifyAllSections_430Xv2(const unsigned short *data, const unsigned long *address, const unsigned long *length_of_sections, const unsigned long sections);
#define VerifyAllSections VerifyAllSections_430Xv2
word ReadMem_430Xv2(word Format, unsigned long Addr);
#define ReadMem ReadMem_430Xv2
void ReadMemQuick_430Xv2(unsigned long StartAddr, unsigned long Length, word *DataArray);
#define ReadMemQuick ReadMemQuick_430Xv2
word VerifyMem_430Xv2(unsigned long StartAddr, unsigned long Length, word *DataArray);
#define VerifyMem VerifyMem_430Xv2
typedef int (*extract_conv_fn)( const unsigned short inp_data,
unsigned char* op_data, unsigned int count);
word TTFExtractSection_430Xv2
(const unsigned long sec_addr, const unsigned long sec_len,
unsigned char* sec_databuf, extract_conv_fn ttf_conv,
unsigned long* sec_fmt_len);
#define TTFExtractSection TTFExtractSection_430Xv2
word TTFExtractAllSections_430Xv2(void);
#define TTFExtractAllSections TTFExtractAllSections_430Xv2
word TTFExtractCacheClear_430Xv2(void);
#define TTFExtractCacheClear TTFExtractCacheClear_430Xv2
int TTFImageRead_430Xv2(char *buf, size_t count, loff_t *ppos);
#define TTFImageRead TTFImageRead_430Xv2
int GetChecksumData_430Xv2(unsigned short* cksum1, unsigned short* cksum2,
unsigned short* cksum_cycles, unsigned short* cksum_errors);
#define GetChecksumData GetChecksumData_430Xv2

View File

@@ -0,0 +1,241 @@
#include "a6_host_adapter.h"
#include "low_level_funcs.h"
// declarations for active implementation mappings used by the sbw code...
extern uint16_t (*SetSBWTCK)(void);
extern uint16_t (*ClrSBWTCK)(void);
extern uint16_t (*SetSBWTDIO)(void);
extern uint16_t (*ClrSBWTDIO)(void);
extern uint16_t (*SetInSBWTDIO)(void);
extern uint16_t (*SetOutSBWTDIO)(void);
extern uint16_t (*GetSBWTDIO)(void);
extern uint16_t (*SetSBWAKEUP)(void);
extern uint16_t (*ClrSBWAKEUP)(void);
extern void (*delay)(uint32_t delay_us);
//
byte tdo_bit; //holds the value of TDO-bit
byte TCLK_saved = 1; // holds the last value of TCLK before entering a JTAG sequence
/****************************************************************************/
/* Function declarations which have to be programmed by the user for use */
/* with hosts other than the MSP430F149. */
/* */
/* The following MSP430F149-specific code can be used as a reference as to */
/* how to implement the required JTAG communication on additional hosts. */
/****************************************************************************/
//-------------------------------
// combinations of sbw-cycles (TMS, TDI, TDO)
void TMSL_TDIL(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSL TDIL TDOsbw
EnableInterrupts(flags);
}
//---------------------------------
void TMSH_TDIL(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSH TDIL TDOsbw
EnableInterrupts(flags);
}
//------------------------------------
void TMSL_TDIH(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSL TDIH TDOsbw
EnableInterrupts(flags);
}
//-------------------------------------
void TMSH_TDIH(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSH TDIH TDOsbw
EnableInterrupts(flags);
}
//------------------------------------
void TMSL_TDIH_TDOrd(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSL TDIH TDO_RD
EnableInterrupts(flags);
}
//------------------------------------
void TMSL_TDIL_TDOrd(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSL TDIL TDO_RD
EnableInterrupts(flags);
}
//------------------------------------
void TMSH_TDIH_TDOrd(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSH TDIH TDO_RD
EnableInterrupts(flags);
}
//------------------------------------
void TMSH_TDIL_TDOrd(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
TMSH TDIL TDO_RD
EnableInterrupts(flags);
}
//----------------------------------------------
// enters with TCLK_saved and exits with TCLK = 0
void ClrTCLK_sbw(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
if (TCLK_saved)
{
TMSLDH
}
else
{
TMSL
}
ClrSBWTDIO();
TDIL TDOsbw //ExitTCLK
TCLK_saved = 0;
EnableInterrupts(flags);
}
//----------------------------------------------
// enters with TCLK_saved and exits with TCLK = 1
void SetTCLK_sbw(void)
{
unsigned long flags = 0;
DisableInterrupts(flags);
if (TCLK_saved)
{
TMSLDH
}
else
{
TMSL
}
SetSBWTDIO();
TDIH TDOsbw //ExitTCLK
TCLK_saved = 1;
EnableInterrupts(flags);
}
//----------------------------------------------------------------------------
/* Shift a value into TDI (MSB first) and simultaneously shift out a value
from TDO (MSB first).
Arguments: word Format (number of bits shifted, 8 (F_BYTE), 16 (F_WORD),
20 (F_ADDR) or 32 (F_LONG))
unsigned long Data (data to be shifted into TDI)
Result: unsigned long (scanned TDO value)
*/
unsigned long AllShifts(word Format, unsigned long Data)
{
unsigned long TDOword = 0x00000000;
unsigned long MSB = 0x00000000;
word i;
//unsigned long flags = 0;
//DisableInterrupts(flags);
switch(Format)
{
case F_BYTE: MSB = 0x00000080;
break;
case F_WORD: MSB = 0x00008000;
break;
case F_ADDR: MSB = 0x00080000;
break;
case F_LONG: MSB = 0x80000000;
break;
default: // this is an unsupported format, function will just return 0
//EnableInterrupts(flags);
return TDOword;
}
// shift in bits
for (i = Format; i > 0; i--)
{
if (i == 1) // last bit requires TMS=1; TDO one bit before TDI
{
((Data & MSB) == 0) ? TMSH_TDIL_TDOrd() : TMSH_TDIH_TDOrd();
}
else
{
((Data & MSB) == 0) ? TMSL_TDIL_TDOrd() : TMSL_TDIH_TDOrd();
}
Data <<= 1;
if (tdo_bit)
TDOword++;
if (i > 1)
TDOword <<= 1; // TDO could be any port pin
}
TMSH_TDIH(); // update IR
if (TCLK_saved)
{
TMSL_TDIH();
}
else
{
TMSL_TDIL();
}
// de-scramble bits on a 20bit shift
if(Format == F_ADDR)
{
TDOword = ((TDOword << 16) + (TDOword >> 4)) & 0x000FFFFF;
}
//EnableInterrupts(flags);
return(TDOword);
}
void DrvSignals(void)
{
SetSBWTDIO();
ClrSBWTCK();
}
void RlsSignals(void)
{
SetSBWTDIO();
ClrSBWTCK();
}
void InitTarget(void)
{
DrvSignals();
}
void ReleaseTarget(void)
{
RlsSignals();
}
/****************************************************************************/
/* END OF SOURCE FILE */
/****************************************************************************/

View File

@@ -0,0 +1,71 @@
#ifndef _low_level_funcs_h_
#define _low_level_funcs_h_
/****************************************************************************/
/* Macros and Pin-to-Signal assignments which have to be programmed */
/* by the user. This implementation assumes use of an MSP430F149 as the host*/
/* controller and the corresponding hardware given in the application */
/* report TBD Appendix A. */
/* */
/* The following MSP430 example acts as a hint of how to generally */
/* implement a micro-controller programmer solution for the MSP430 flash- */
/* based devices. */
/****************************************************************************/
#ifndef __BYTEWORD__
#define __BYTEWORD__
typedef unsigned int word;
typedef unsigned char byte;
#endif
//----------------------------------------------------------------------------
// Pin-to-Signal Assignments
//----------------------------------------------------------------------------
#define TMSH {SetSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTCK();}// TMS = 1
#define TMSL {ClrSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTCK();} // TMS = 0
#define TMSLDH {ClrSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTDIO(); SetSBWTCK();} // TMS = 0, then TCLK(TDI) immediately = 1
#define TDIH {SetSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTCK();} // TDI = 1
#define TDIL {ClrSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTCK();} // TDI = 0
#define TDOsbw {SetSBWTDIO();SetInSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS SetSBWTCK(); SetOutSBWTDIO();} // TDO cycle without reading TDO
#define TDO_RD {SetSBWTDIO();SetInSBWTDIO(); nNOPS ClrSBWTCK(); nNOPS tdo_bit = GetSBWTDIO(); SetSBWTCK(); SetOutSBWTDIO();} // TDO cycle with TDO read
void ClrTCLK_sbw(void);
void SetTCLK_sbw(void);
#define ClrTCLK() ClrTCLK_sbw()
#define SetTCLK() SetTCLK_sbw()
#define SetRST() SetSBWTDIO()
#define ClrRST() ClrSBWTDIO()
#define ReleaseRST() ()
#define SetTST() SetSBWTCK()
#define ClrTST() ClrSBWTCK()
/*----------------------------------------------------------------------------
Definition of global variables
*/
extern byte TCLK_saved; // holds the last value of TCLK before entering a JTAG sequence
/*----------------------------------------------------------------------------
Low Level function prototypes
*/
void TMSL_TDIL(void);
void TMSH_TDIL(void);
void TMSL_TDIH(void);
void TMSH_TDIH(void);
void TMSL_TDIH_TDOrd(void);
void TMSL_TDIL_TDOrd(void);
void TMSH_TDIH_TDOrd(void);
void TMSH_TDIL_TDOrd(void);
unsigned long AllShifts(word Format, unsigned long Data);
void DrvSignals(void);
void RlsSignals(void);
void InitTarget(void);
void ReleaseTarget(void);
#endif

575
drivers/misc/hres_counter.c Normal file
View File

@@ -0,0 +1,575 @@
/*
* linux/drivers/misc/hres_counter.c
*
* Copyright (C) 2008 Palm, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License.
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/clk.h>
#include <linux/hres_counter.h>
#include <linux/sysrq.h>
#include <linux/platform_device.h>
#include <asm/io.h>
#define NUM_CHANNELS 32
#define NUM_EVENTS 512
struct count_ch {
u32 count;
u32 total;
u32 tstamp;
u32 active;
};
struct hres_event {
u32 tstamp;
char* type;
u32 arg1;
u32 arg2;
};
struct dev_ctxt {
void *timer;
int suspended;
struct platform_device *pdev;
struct count_ch ch[NUM_CHANNELS];
int (*init_hres_timer)(void **);
int (*release_hres_timer)(void *);
int (*suspend_hres_timer)(void *);
int (*resume_hres_timer)(void *);
u32 (*read_hres_timer)(void *);
u32 (*convert_hres_timer)(u32);
};
static struct dev_ctxt *gdev = NULL;
static int evlog_on = 1;
static int evlog_cnt = 0;
static int evlog_num = 0;
static struct hres_event evlog[NUM_EVENTS];
/*
*
*/
static inline u32
hres_read_tick ( void ) {
if( unlikely(gdev == NULL))
return 0;
return gdev->read_hres_timer( gdev->timer );
}
/*
* Current value of high res counter
*/
u32
hres_get_counter ( void )
{
return hres_read_tick();
}
EXPORT_SYMBOL(hres_get_counter);
/*
* Return the delta in useconds from start to end
*/
u32
hres_get_delta_usec ( u32 start, u32 end )
{
return gdev->convert_hres_timer(end - start);
}
/*
* Reset channel
*/
void
hres_ch_reset ( uint ch )
{
if( unlikely(gdev == NULL))
return;
if( unlikely(ch >= NUM_CHANNELS))
return;
memset ( &gdev->ch[ch], 0, sizeof(struct count_ch));
}
EXPORT_SYMBOL(hres_ch_reset);
/*
* Increment Event count
*/
void
hres_event_cnt ( uint ch )
{
unsigned long flags;
if( unlikely(gdev == NULL))
return;
if( unlikely(ch >= NUM_CHANNELS))
return;
local_irq_save(flags);
gdev->ch[ch].count++;
local_irq_restore(flags);
}
EXPORT_SYMBOL(hres_event_cnt);
/*
* Mark Event Start
*/
void
hres_event_start ( uint ch )
{
unsigned long flags;
if( unlikely(gdev == NULL))
return;
if( unlikely(ch >= NUM_CHANNELS))
return;
local_irq_save(flags);
gdev->ch[ch].tstamp = hres_read_tick();
gdev->ch[ch].active = 1;
local_irq_restore(flags);
}
EXPORT_SYMBOL(hres_event_start);
/*
* Mark Event End and count
*/
u32
hres_event_end ( uint ch )
{
u32 ts = 0;
unsigned long flags;
if( unlikely(gdev == NULL))
return 0;
if( unlikely(ch >= NUM_CHANNELS))
return 0;
if(!gdev->ch[ch].active)
return 0;
local_irq_save(flags);
ts = gdev->read_hres_timer( gdev->timer ) - gdev->ch[ch].tstamp;
gdev->ch[ch].total += ts;
gdev->ch[ch].count++;
gdev->ch[ch].active = 0;
local_irq_restore(flags);
return ts;
}
EXPORT_SYMBOL(hres_event_end);
/*
* Mark Event End and count
*/
void
hres_event ( char *type, u32 arg1, u32 arg2 )
{
unsigned long flags;
struct hres_event *evt;
if( unlikely(gdev == NULL))
return;
if( !evlog_on )
return;
local_irq_save(flags);
evt = evlog + evlog_cnt;
evlog_cnt++;
if( evlog_cnt > evlog_num )
evlog_num = evlog_cnt;
if( evlog_cnt == NUM_EVENTS )
evlog_cnt = 0;
evt->tstamp = hres_read_tick();
evt->type = type;
evt->arg1 = arg1;
evt->arg2 = arg2;
local_irq_restore(flags);
return;
}
EXPORT_SYMBOL(hres_event);
/*
*
*/
void
hres_evlog_reset(void)
{
unsigned long flags;
local_irq_save(flags);
evlog_cnt = 0;
evlog_num = 0;
local_irq_restore(flags);
}
EXPORT_SYMBOL(hres_evlog_reset);
/*
* Enable logging
*/
int
hres_evlog_enable(void)
{
int rc = evlog_on;
evlog_on = 1;
return rc;
}
EXPORT_SYMBOL(hres_evlog_enable);
/*
* Disable logging
*/
int
hres_evlog_disable(void)
{
int rc = evlog_on;
evlog_on = 0;
return rc;
}
EXPORT_SYMBOL(hres_evlog_disable);
/*
* Print log
*/
void
hres_evlog_print ( void )
{
int i;
u32 last_tstamp = 0;
struct hres_event *evt = evlog;
printk ("evlog: beg\n");
for (i = 0; i < evlog_num; i++, evt++ ) {
printk ( "%010d (d%10d): %12d (0x%08x) %12d (0x%08x) %s\n",
gdev->convert_hres_timer(evt->tstamp),
gdev->convert_hres_timer(evt->tstamp - last_tstamp),
evt->arg1, evt->arg1,
evt->arg2, evt->arg2,
evt->type );
last_tstamp = evt->tstamp;
}
printk ("evlog: end\n");
}
EXPORT_SYMBOL(hres_evlog_print);
/*
* Sysfs
*/
static ssize_t
counter_show ( struct device *dev,
struct device_attribute *attr,
char *buf )
{
return snprintf( buf, PAGE_SIZE, "%d\n", hres_read_tick());
}
static DEVICE_ATTR( counter, S_IRUGO | S_IWUSR, counter_show, NULL );
static ssize_t
evlog_show ( struct device *dev,
struct device_attribute *attr,
char *buf )
{
hres_evlog_print ();
return 0;
}
static ssize_t
evlog_store( struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count )
{
hres_evlog_reset();
return count;
}
static DEVICE_ATTR( evlog, S_IRUGO | S_IWUSR, evlog_show, evlog_store );
static ssize_t
channels_show ( struct device *dev,
struct device_attribute *attr,
char *buf )
{
int ch;
ssize_t len = 0;
for ( ch = 0; ch < NUM_CHANNELS; ch++ ) {
len += snprintf( buf + len, PAGE_SIZE - len,
"%02d: %010u %4d\n", ch,
gdev->convert_hres_timer(gdev->ch[ch].total),
gdev->ch[ch].count
);
}
return len;
}
static ssize_t
channels_store( struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count )
{
int ch;
ch = simple_strtol ( buf, NULL, 10 );
if( ch == -1 ) {
for ( ch = 0; ch < NUM_CHANNELS; ch++ )
hres_ch_reset ( ch );
}
else {
hres_ch_reset ((uint) ch );
}
return count;
}
static DEVICE_ATTR( channels, S_IRUGO | S_IWUSR, channels_show, channels_store);
static void
hres_sysrq_show_evlog(int key, struct tty_struct *tty)
{
hres_evlog_print();
}
/*
*
*/
static int
hres_panic(struct notifier_block *this, unsigned long event, void *ptr)
{
hres_evlog_print();
return NOTIFY_DONE;
}
static struct notifier_block panic_block = {
.notifier_call = hres_panic,
};
/*
* Sys req related
*/
static struct sysrq_key_op sysrq_show_log_op = {
.handler = hres_sysrq_show_evlog,
.help_msg = "show-evLog",
.action_msg = "Show HiRes EvLog",
};
static void
hres_sysrq_reset_evlog(int key, struct tty_struct *tty)
{
hres_evlog_reset();
}
static struct sysrq_key_op sysrq_reset_log_op = {
.handler = hres_sysrq_reset_evlog,
.help_msg = "reset-evlog(c)",
.action_msg = "Reset Hires EvLog",
};
/*
*
*/
static int __devexit
hres_counter_remove ( struct platform_device *pdev )
{
struct dev_ctxt *ctxt = gdev;
gdev = NULL;
device_remove_file ( &pdev->dev, &dev_attr_counter );
device_remove_file ( &pdev->dev, &dev_attr_channels );
device_remove_file ( &pdev->dev, &dev_attr_evlog );
gdev->release_hres_timer ( ctxt->timer );
platform_set_drvdata( pdev, NULL );
kfree ( ctxt );
return 0;
}
/*
*
*/
static int __init
hres_counter_probe ( struct platform_device *pdev )
{
int rc;
struct dev_ctxt *ctxt;
struct hres_counter_platform_data *pdata = pdev->dev.platform_data;
ctxt = kzalloc ( sizeof(struct dev_ctxt), GFP_KERNEL );
if( ctxt == NULL )
goto ret_nodev;
ctxt->pdev = pdev;
ctxt->init_hres_timer = pdata->init_hres_timer;
ctxt->release_hres_timer = pdata->release_hres_timer;
ctxt->read_hres_timer = pdata->read_hres_timer;
ctxt->convert_hres_timer = pdata->convert_hres_timer;
ctxt->suspend_hres_timer = pdata->suspend_hres_timer;
ctxt->resume_hres_timer = pdata->resume_hres_timer;
rc = ctxt->init_hres_timer(&ctxt->timer);
if( rc )
goto free_ctxt;
platform_set_drvdata ( pdev, ctxt );
rc = device_create_file ( &pdev->dev, &dev_attr_counter );
if( rc )
goto free_timer;
rc = device_create_file ( &pdev->dev, &dev_attr_channels );
if( rc )
goto free_sysfs_counter;
rc = device_create_file ( &pdev->dev, &dev_attr_evlog );
if( rc )
goto free_sysfs_channels;
gdev = ctxt;
printk( KERN_INFO "Initialize %s device\n",
pdev->name);
#if 0
#ifndef CONFIG_HRES_COUNTER_TIMER32K
printk( KERN_INFO "Initialize %s device (%dMHz)\n",
pdev->name, clk_rate );
#else
printk( KERN_INFO "Initialize %s device (32KHz)\n", pdev->name);
#endif
#endif
// register sys request key
register_sysrq_key( 'l', &sysrq_show_log_op );
register_sysrq_key( 'c', &sysrq_reset_log_op );
// register panic callback
atomic_notifier_chain_register(&panic_notifier_list, &panic_block);
return 0;
free_sysfs_channels:
device_remove_file ( &pdev->dev, &dev_attr_channels );
free_sysfs_counter:
device_remove_file ( &pdev->dev, &dev_attr_counter );
free_timer:
ctxt->release_hres_timer ( ctxt->timer );
free_ctxt:
kfree ( ctxt );
ret_nodev:
return -ENODEV;
}
#ifdef CONFIG_HRES_COUNTER_TIMER32K
#undef CONFIG_PM
#endif
#ifdef CONFIG_PM
static int
hres_counter_suspend( struct platform_device *dev, pm_message_t state )
{
struct dev_ctxt *ctxt = gdev;
if( ctxt->suspended )
return 0;
ctxt->resume_hres_timer(gdev->timer);
ctxt->suspended = 1;
return 0;
}
static int
hres_counter_resume ( struct platform_device *dev )
{
struct dev_ctxt *ctxt = gdev;
if(!ctxt->suspended )
return 0;
ctxt->suspend_hres_timer(gdev->timer);
ctxt->suspended = 0;
return 0;
}
#else
#define hres_counter_suspend NULL
#define hres_counter_resume NULL
#endif /* CONFIG_PM */
/*
*
*/
static struct platform_driver hres_counter_driver = {
.driver = {
.name = "hres_counter",
},
.probe = hres_counter_probe,
.remove = __devexit_p(hres_counter_remove),
.suspend = hres_counter_suspend,
.resume = hres_counter_resume,
};
static int __init
hres_counter_init(void)
{
platform_driver_register ( &hres_counter_driver );
return 0;
}
static void __exit
hres_counter_exit(void)
{
platform_driver_unregister ( &hres_counter_driver );
return;
}
module_init(hres_counter_init);
module_exit(hres_counter_exit);
MODULE_DESCRIPTION("OMAP High resolution counter driver" );
MODULE_LICENSE("GPL");