841 lines
16 KiB
C
Executable File
841 lines
16 KiB
C
Executable File
/*
|
||
*
|
||
* Based on arch/arm/mach-pxa/htcblueangel/blueangel_dpram.c
|
||
* Autor: Angell Fear <angell@angellfear.ru>
|
||
* MSM6280 to PXA270 communication on Dual Port RAM for Toshiba G900
|
||
*
|
||
*/
|
||
|
||
#include <linux/module.h>
|
||
#include <linux/ioport.h>
|
||
#include <linux/init.h>
|
||
#include <linux/serial_reg.h>
|
||
#include <linux/circ_buf.h>
|
||
#include <linux/delay.h>
|
||
#include <linux/interrupt.h>
|
||
#include <linux/platform_device.h>
|
||
#include <linux/tty.h>
|
||
#include <linux/tty_flip.h>
|
||
#include <linux/serial_core.h>
|
||
#include <linux/irq.h>
|
||
|
||
#include <asm/io.h>
|
||
#include <asm/mach-types.h>
|
||
#include <mach/hardware.h>
|
||
#include <asm/irq.h>
|
||
#include <mach/pxa2xx-regs.h>
|
||
#include <asm/gpio.h>
|
||
#include <linux/types.h>
|
||
#include <linux/ctype.h>
|
||
|
||
|
||
#include <mach/g900-gpio.h>
|
||
|
||
|
||
#include <linux/pda_power.h>
|
||
|
||
|
||
|
||
#define RX_AT_BUF (0x400-4)
|
||
#define TX_AT_BUF (0x400-4)
|
||
|
||
#define IRQ_RX gpio_to_irq(0)
|
||
|
||
|
||
|
||
#define MBOX1 *((u8*)dpram_data.data_virt + 0x7FFC)
|
||
#define MBOX2 *((u8*)dpram_data.data_virt + 0x7FFD)
|
||
#define MBOX3 *((u8*)dpram_data.data_virt + 0x7FFE)
|
||
#define MBOX4 *((u8*)dpram_data.data_virt + 0x7FFF)
|
||
|
||
|
||
/* DPRAM */
|
||
#define PORT_DPRAM 69
|
||
|
||
struct dpram_data {
|
||
unsigned long data_phys;
|
||
void *data_virt;
|
||
} dpram_data;
|
||
|
||
int p_BATT_CAPACITY=50;
|
||
int p_AC_POWER=0;
|
||
|
||
#if 0
|
||
#define dbprintk(x...) printk(x)
|
||
#define dprintk(x...) printk(x)
|
||
#define dvprintk(x...) printk(x)
|
||
#define dmprintk(x...) printk(x)
|
||
|
||
#define dcharprint(s) \
|
||
if( isascii(s) && isprint(s) ){ \
|
||
dprintk("%c",s); \
|
||
}else{ \
|
||
dprintk("<0x%02x>",s); \
|
||
}
|
||
#else
|
||
|
||
#define dbprintk(x...)
|
||
#define dprintk(x...)
|
||
#define dvprintk(x...)
|
||
|
||
#define dmprintk(s,b1,b2,b3,b4) \
|
||
mbtmp = b1; mbtmp = b2; mbtmp = b3; mbtmp = b4;
|
||
|
||
#define dcharprint(s)
|
||
|
||
#endif
|
||
|
||
|
||
|
||
u8 mbtmp;
|
||
|
||
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
#ifdef CONFIG_POWER_SUPPLY
|
||
|
||
#include <linux/power_supply.h>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
static int g900_power_get_property(struct power_supply *psy,
|
||
enum power_supply_property prop,
|
||
union power_supply_propval *val)
|
||
{
|
||
|
||
int ret = 0;
|
||
switch (prop) {
|
||
|
||
case POWER_SUPPLY_PROP_CAPACITY:
|
||
val->intval = p_BATT_CAPACITY;
|
||
break;
|
||
|
||
case POWER_SUPPLY_PROP_TECHNOLOGY: /* All our batteries are Li-ions (right?)*/
|
||
val->intval = POWER_SUPPLY_TECHNOLOGY_LION;
|
||
break;
|
||
|
||
case POWER_SUPPLY_PROP_STATUS:
|
||
if (p_AC_POWER > 0 && p_BATT_CAPACITY <= 99)
|
||
val->intval = POWER_SUPPLY_STATUS_CHARGING;
|
||
else if (p_AC_POWER == 1 && p_BATT_CAPACITY > 99)
|
||
val->intval = POWER_SUPPLY_STATUS_FULL;
|
||
else
|
||
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
|
||
break;
|
||
|
||
case POWER_SUPPLY_PROP_ONLINE: /* either USB or AC */
|
||
if (psy->type == POWER_SUPPLY_TYPE_MAINS){ /* AC on/offline*/
|
||
if(p_AC_POWER==1){
|
||
val->intval = 1;
|
||
}else{
|
||
val->intval = 0;
|
||
}
|
||
}else if(psy->type == POWER_SUPPLY_TYPE_USB) { /* USB on/offline */
|
||
|
||
/*
|
||
40 USB detect IRQ
|
||
41 USB_P2_7(Client = 1, host =0(up 75,93) )
|
||
*/
|
||
|
||
|
||
val->intval =0 ;// (GPIO41_USB_MODE ? 1 : 0); /* TODO!!! */
|
||
}else
|
||
dbprintk("MSM6280:POWER_SUPPLY_PROP_ONLINE type = %d = %d \n",psy->type,val->intval);
|
||
|
||
|
||
|
||
break;
|
||
|
||
|
||
#define VOLTAGE_MIN 3635000 /* todo */
|
||
#define VOLTAGE_MAX 4158000 /* todo */
|
||
#define VOLTAGE_STEP ((VOLTAGE_MAX - VOLTAGE_MIN)/100)
|
||
|
||
case POWER_SUPPLY_PROP_BATT_VOL:
|
||
val->intval = (p_BATT_CAPACITY * VOLTAGE_STEP ) + VOLTAGE_MIN; //fake !!! percent math
|
||
break;
|
||
case POWER_SUPPLY_PROP_BATT_TEMP:
|
||
val->intval = 27; /// fake !!!
|
||
break;
|
||
case POWER_SUPPLY_PROP_PRESENT:
|
||
val->intval = 0;
|
||
break;
|
||
case POWER_SUPPLY_PROP_HEALTH:
|
||
val->intval = 1;
|
||
break;
|
||
|
||
#if 0
|
||
case POWER_SUPPLY_PROP_VOLTAGE_MIN: /* lowest measured value in uV */
|
||
val->intval = VOLTAGE_MIN;
|
||
break;
|
||
case POWER_SUPPLY_PROP_VOLTAGE_MAX: /* highest measured value in uV */
|
||
val->intval = VOLTAGE_MAX;
|
||
break;
|
||
|
||
case POWER_SUPPLY_PROP_VOLTAGE_NOW:
|
||
val->intval = (p_BATT_CAPACITY * VOLTAGE_STEP ) + VOLTAGE_MIN; /*mV*/ //fake !!! percent math
|
||
break;
|
||
#endif
|
||
|
||
default:
|
||
ret = -EINVAL;
|
||
}
|
||
|
||
return ret;
|
||
}
|
||
|
||
/* property for AC and USB */
|
||
static enum power_supply_property g900_power_line_props[] = {
|
||
POWER_SUPPLY_PROP_ONLINE,
|
||
};
|
||
|
||
/* main battery properties */
|
||
static enum power_supply_property g900_power_battery_props[] = {
|
||
POWER_SUPPLY_PROP_CAPACITY,
|
||
POWER_SUPPLY_PROP_TECHNOLOGY,
|
||
POWER_SUPPLY_PROP_STATUS,
|
||
POWER_SUPPLY_PROP_PRESENT,
|
||
POWER_SUPPLY_PROP_HEALTH,
|
||
POWER_SUPPLY_PROP_BATT_VOL,
|
||
POWER_SUPPLY_PROP_BATT_TEMP,
|
||
|
||
#if 0
|
||
POWER_SUPPLY_PROP_VOLTAGE_MIN,
|
||
POWER_SUPPLY_PROP_VOLTAGE_MAX,
|
||
POWER_SUPPLY_PROP_VOLTAGE_NOW,
|
||
#endif
|
||
|
||
};
|
||
|
||
|
||
static char *g900_power_supplied_to[] = {
|
||
"main-battery",
|
||
/* backup-battery could be added if we knew how to access info about it */
|
||
};
|
||
|
||
static struct power_supply g900_psy_ac = {
|
||
.name = "ac",
|
||
.type = POWER_SUPPLY_TYPE_MAINS,
|
||
.supplied_to = g900_power_supplied_to,
|
||
.num_supplicants = ARRAY_SIZE(g900_power_supplied_to),
|
||
.properties = g900_power_line_props,
|
||
.num_properties = ARRAY_SIZE(g900_power_line_props),
|
||
.get_property = g900_power_get_property,
|
||
};
|
||
|
||
static struct power_supply g900_psy_usb = {
|
||
.name = "usb",
|
||
.type = POWER_SUPPLY_TYPE_USB,
|
||
.supplied_to = g900_power_supplied_to,
|
||
.num_supplicants = ARRAY_SIZE(g900_power_supplied_to),
|
||
.properties = g900_power_line_props,
|
||
.num_properties = ARRAY_SIZE(g900_power_line_props),
|
||
.get_property = g900_power_get_property,
|
||
};
|
||
|
||
static struct power_supply g900_psy_battery = {
|
||
.name = "battery",
|
||
.type = POWER_SUPPLY_TYPE_BATTERY,
|
||
.properties = g900_power_battery_props,
|
||
.num_properties = ARRAY_SIZE(g900_power_battery_props),
|
||
.get_property = g900_power_get_property,
|
||
.use_for_apm = 1,
|
||
};
|
||
#endif
|
||
|
||
static struct platform_device *pdev;
|
||
|
||
void batt_probe(void){
|
||
#ifdef CONFIG_POWER_SUPPLY
|
||
int ret;
|
||
|
||
dbprintk("MSM6280:batt_probe \n");
|
||
pdev = platform_device_register_simple("MSM6280_batt",
|
||
0, NULL, 0);
|
||
if (IS_ERR(pdev)) {
|
||
ret = PTR_ERR(pdev);
|
||
dbprintk("MSM6280: failed to register pdev ret=%d\n",ret);
|
||
return;
|
||
}
|
||
|
||
if (power_supply_register(&pdev->dev, &g900_psy_ac) != 0)
|
||
dev_err(&pdev->dev, "failed to register %s power supply\n",g900_psy_ac.name);
|
||
if (power_supply_register(&pdev->dev, &g900_psy_usb) != 0)
|
||
dev_err(&pdev->dev, "failed to register %s power supply\n",g900_psy_usb.name);
|
||
if (power_supply_register(&pdev->dev, &g900_psy_battery) != 0)
|
||
dev_err(&pdev->dev, "failed to register %s power supply\n",g900_psy_battery.name);
|
||
|
||
|
||
#endif
|
||
}
|
||
|
||
|
||
void batt_remove(void){
|
||
#ifdef CONFIG_POWER_SUPPLY
|
||
power_supply_unregister(&g900_psy_ac);
|
||
power_supply_unregister(&g900_psy_usb);
|
||
power_supply_unregister(&g900_psy_battery);
|
||
#endif
|
||
}
|
||
|
||
#ifdef CONFIG_POWER_SUPPLY
|
||
|
||
void battery(char *percent,int acpower)
|
||
{
|
||
int capacity = 0;
|
||
dbprintk("MSM6280:BATERY %s%% - POWER %d\n",percent,acpower);
|
||
capacity = percent[0]-'0';
|
||
if((percent[1]-'0') >=0 && (percent[1]-'0') <=9)
|
||
{
|
||
capacity=(capacity*10)+(percent[1]-'0');
|
||
if((percent[2]-'0') >=0 && (percent[2]-'0') <=9)
|
||
{
|
||
capacity=(capacity*10)+(percent[2]-'0');
|
||
}
|
||
}
|
||
|
||
if(p_BATT_CAPACITY != capacity)
|
||
{
|
||
p_BATT_CAPACITY = capacity;
|
||
}
|
||
|
||
|
||
if((acpower >= 0) && (p_AC_POWER != acpower))
|
||
{
|
||
p_AC_POWER = acpower;
|
||
power_supply_changed(&g900_psy_ac);
|
||
}
|
||
|
||
power_supply_changed(&g900_psy_battery);
|
||
dbprintk("MSM6280:BATERY %d%% - POWER %d\n",p_BATT_CAPACITY,p_AC_POWER);
|
||
|
||
}
|
||
#endif
|
||
|
||
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
/** BATTERY **/
|
||
|
||
|
||
|
||
/** SPLITER **/
|
||
int atresp(char *atbuf)
|
||
{
|
||
char *p;
|
||
int end=0,j=0,i=0,len,x,y,z;
|
||
char buf[256],values[256];
|
||
|
||
char tmp[5][16];
|
||
|
||
//printk("MSM6280: atresp = %s\n",atbuf);
|
||
|
||
for (p = atbuf,j=0; *p != '\0' ;p++,j++) {
|
||
|
||
if (*p == ':'){
|
||
|
||
while(*(atbuf + end) == 0x0d || *(atbuf + end) == 0x0a) end++;
|
||
|
||
len=j-end;
|
||
strncpy(buf, atbuf+end, len);
|
||
buf[len] = 0;
|
||
p++;
|
||
for(i=0;((*p != 0) && (*p != 0x0d)) ;p++,i++)
|
||
{
|
||
values[i]=*p;
|
||
}
|
||
end = j;
|
||
values[i]=0;
|
||
|
||
//printk("MSM6280: AT ANSWER end=%d,len=%d, %s - %s\n",end,len,buf,values);
|
||
#ifdef CONFIG_POWER_SUPPLY
|
||
/**
|
||
BATTERY
|
||
|
||
plug charger
|
||
$CBN: 1,49,1
|
||
unplug charger
|
||
$CBN: 1,49,4
|
||
|
||
$CBN - 1,61,14 ??
|
||
|
||
$CBN: 1,49,8
|
||
$CBN: 1,77,0
|
||
|
||
call AT+CBN
|
||
+CBN: 1,49
|
||
|
||
call AT+CBC
|
||
+CBC: 0,49 ?? power capacity??
|
||
*/
|
||
if(
|
||
(buf[0] == '$' || buf[0] == '+')&&
|
||
buf[1] == 'C' &&
|
||
buf[2] == 'B' &&
|
||
(buf[3] == 'N' /*|| buf[3] == 'C'*/)
|
||
)
|
||
{
|
||
dbprintk("MSM6280: AT BATERY ANSWER %s - %s\n",buf,values);
|
||
for (x=0,y=0,z=0; values[z] != '\0' ;z++,y++) {
|
||
if(values[z] == ','){
|
||
tmp[x][y] = 0;
|
||
x++;
|
||
z++;
|
||
y=0;
|
||
}
|
||
tmp[x][y] = values[z];
|
||
}
|
||
tmp[x][y] = 0;
|
||
|
||
for (x=0; x<4 ;x++) {
|
||
dbprintk("tmp[%i] = \"%s\"\n",x,tmp[x]);
|
||
}
|
||
z = -1;
|
||
if(tmp[2][0] == '1' && (tmp[2][1] == 0 || (tmp[2][1] == '4' && tmp[2][2] == 0) )){
|
||
z = 1;
|
||
}
|
||
if(tmp[2][0] == '4' && tmp[2][1] == 0){
|
||
z = 0;
|
||
}
|
||
|
||
dbprintk("MSM6280: AT !! call battery( %s , %d)\n",tmp[1],z);
|
||
battery(tmp[1],z);
|
||
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/**
|
||
|
||
======================
|
||
|
||
LED
|
||
|
||
AT+LED=3,10,0
|
||
======================
|
||
*/
|
||
|
||
return 0;
|
||
}
|
||
|
||
|
||
/**/
|
||
|
||
|
||
static void dpram_enable_ms(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_enable_ms\n");
|
||
}
|
||
|
||
static void dpram_stop_tx(struct uart_port *port)
|
||
{
|
||
//dprintk("dpram_stop_tx\n");
|
||
}
|
||
|
||
static void dpram_stop_rx(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_stop_rx\n");
|
||
}
|
||
|
||
|
||
static void
|
||
receive_chars(struct uart_port *up)
|
||
{
|
||
struct tty_struct *tty = up->state->port.tty;
|
||
unsigned int ch,atcnt,i=0;
|
||
u16 head,tail;
|
||
char atbuf[256];
|
||
// unsigned long flags;
|
||
//spin_lock_irqsave(&up->port.lock, flags);
|
||
|
||
dmprintk("receive_chars MBOX=%02x,%02x,%02x,%02x\n",MBOX1,MBOX2,MBOX3,MBOX4);
|
||
|
||
|
||
//MBOX2 = 0x1;
|
||
//MBOX3 = 0x1;
|
||
//MBOX4 = 0x1;
|
||
|
||
head = *((u16*)dpram_data.data_virt + 0x00);
|
||
tail = *((u16*)dpram_data.data_virt + 0x01);
|
||
|
||
if(tail == head ) return ; // mb fast IRQ
|
||
|
||
//dvprintk("receive_chars head = 0x%04x, tail = 0x%04x: \n",head,tail);
|
||
dprintk("R<-: ");
|
||
|
||
atcnt=0;
|
||
atbuf[0] = 0;
|
||
|
||
while((head != tail))
|
||
{
|
||
if(tail >= RX_AT_BUF){
|
||
tail = 0x00;
|
||
}
|
||
if(i >= RX_AT_BUF) break;
|
||
|
||
ch =*((u8*)dpram_data.data_virt+tail+0x04);
|
||
tail++;
|
||
i++;
|
||
up->icount.rx++;
|
||
|
||
if (!uart_handle_sysrq_char(up, c))
|
||
{
|
||
tty_insert_flip_char(tty, ch, TTY_NORMAL);
|
||
/*
|
||
at resporens other devices
|
||
*/
|
||
atbuf[atcnt] = ch;
|
||
atcnt++;
|
||
|
||
dcharprint(ch);
|
||
}
|
||
|
||
}
|
||
|
||
atbuf[atcnt] = 0;
|
||
atresp(atbuf);
|
||
|
||
|
||
tty_flip_buffer_push(tty);
|
||
|
||
*((u16*)dpram_data.data_virt+0x01)=tail;
|
||
|
||
MBOX1 = 0x0;
|
||
MBOX2 = 0x0;
|
||
MBOX3 = 0x0; /*MAILBOX clean ch1 INTERPUT*/
|
||
MBOX4 = 0x0;
|
||
|
||
dprintk("\n");
|
||
|
||
return;
|
||
}
|
||
|
||
static unsigned char
|
||
transmit_char(struct uart_port *up, struct circ_buf *xmit)
|
||
{
|
||
unsigned char ret;
|
||
|
||
ret=xmit->buf[xmit->tail];
|
||
xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
|
||
up->icount.tx++;
|
||
|
||
return ret;
|
||
}
|
||
static void transmit_chars(struct uart_port *up)
|
||
{
|
||
struct circ_buf *xmit = &up->state->xmit;
|
||
u16 count;
|
||
unsigned short *txptr;
|
||
u16 head,tail;
|
||
char s;
|
||
|
||
|
||
txptr=dpram_data.data_virt;
|
||
|
||
if (up->x_char) {
|
||
|
||
dprintk("send x_char 0x%02x(%c)\n",up->x_char,up->x_char);
|
||
up->icount.tx++;
|
||
up->x_char = 0;
|
||
return;
|
||
}
|
||
|
||
if (uart_circ_empty(xmit) || uart_tx_stopped(up)) {
|
||
dpram_stop_tx(up);
|
||
return;
|
||
}
|
||
|
||
/*************************/
|
||
/*
|
||
<EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD>
|
||
{
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>. <20> <20><><EFBFBD><EFBFBD> <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD>
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD> msm <20><><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||
}
|
||
|
||
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD> len+tail
|
||
*/
|
||
|
||
head = *((u16*)dpram_data.data_virt + 0x200);
|
||
tail = *((u16*)dpram_data.data_virt + 0x201);
|
||
|
||
count=TX_AT_BUF-1;
|
||
//dvprintk("transmit_chars head = 0x%04x, tail = 0x%04x: \n",head,tail);
|
||
dmprintk("transmit_chars MBOX=%02x,%02x,%02x,%02x\n",MBOX1,MBOX2,MBOX3,MBOX4);
|
||
dprintk("\nS-> :");
|
||
while(count--)
|
||
{
|
||
//if(tail==(head+1)) {
|
||
// printk("FULL BUF0x%04x, tail = 0x%04x: \n",head,tail);
|
||
// break; // <20><><EFBFBD><EFBFBD><EFBFBD>, DPram <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>
|
||
//}
|
||
if(head >= TX_AT_BUF){
|
||
head = 0x00;
|
||
}
|
||
s=transmit_char(up, xmit);
|
||
|
||
*((u8*)dpram_data.data_virt+head+0x404)=s;
|
||
|
||
dcharprint(s);
|
||
head++;
|
||
|
||
if (uart_circ_empty(xmit)) // <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20> uarte <20><><EFBFBD><EFBFBD><EFBFBD>
|
||
break;
|
||
|
||
}
|
||
*((u16*)dpram_data.data_virt + 0x200) = head;
|
||
//dprintk("dpram_end_Tx head = 0x%04x, tail = 0x%04x: \n",head,tail);
|
||
|
||
MBOX1 = 0x1; /*MAILBOX set ch1 INTERPUT*/
|
||
MBOX2 = 0x0;
|
||
MBOX3 = 0x0;
|
||
MBOX4 = 0x0;
|
||
|
||
dprintk("\n");
|
||
|
||
|
||
|
||
/*************************/
|
||
|
||
|
||
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
|
||
uart_write_wakeup(up);
|
||
|
||
if (uart_circ_empty(xmit))
|
||
dpram_stop_tx(up);
|
||
}
|
||
|
||
static void dpram_start_tx(struct uart_port *port)
|
||
{
|
||
//dprintk("dpram_start_tx\n");
|
||
transmit_chars(port);
|
||
}
|
||
|
||
|
||
static unsigned int dpram_tx_empty(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_tx_empty\n");
|
||
return TIOCSER_TEMT;
|
||
}
|
||
|
||
static unsigned int dpram_get_mctrl(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_get_mctrl\n");
|
||
return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
|
||
}
|
||
|
||
static void dpram_set_mctrl(struct uart_port *port, unsigned int mctrl)
|
||
{
|
||
dprintk("dpram_set_mctrl\n");
|
||
}
|
||
|
||
static void dpram_break_ctl(struct uart_port *port, int break_state)
|
||
{
|
||
dprintk("dpram_break_ctl\n");
|
||
}
|
||
|
||
|
||
/*
|
||
* This handles the interrupt from one port.
|
||
*/
|
||
static irqreturn_t
|
||
dpram_irq_rx(int irq, void *dev_id)
|
||
{
|
||
//dprintk("\ndpram_irq_rx!!!!!!!!!!!\n");
|
||
receive_chars(dev_id);
|
||
|
||
return IRQ_HANDLED;
|
||
}
|
||
|
||
|
||
static int dpram_startup(struct uart_port *port)
|
||
{
|
||
int retval;
|
||
dprintk("\n!!!dpram_startup!!!!\n");
|
||
|
||
retval = request_irq(IRQ_RX, dpram_irq_rx, 0, "DPRAM_RX", port);
|
||
if (retval)
|
||
{
|
||
printk(KERN_ERR "%s: Cannot assign GPIO_0 IRQ\n", __FUNCTION__);
|
||
return retval;
|
||
}
|
||
set_irq_type(IRQ_RX, IRQ_TYPE_EDGE_FALLING);
|
||
|
||
receive_chars(port);
|
||
return retval;
|
||
}
|
||
|
||
static void dpram_shutdown(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_shutdown\n");
|
||
free_irq(IRQ_RX, port);
|
||
}
|
||
|
||
static void
|
||
dpram_set_termios(struct uart_port *port, struct ktermios *termios,
|
||
struct ktermios *old)
|
||
{
|
||
dprintk("dpram_set_termios\n");
|
||
}
|
||
|
||
static void
|
||
dpram_pm(struct uart_port *port, unsigned int state,
|
||
unsigned int oldstate)
|
||
{
|
||
dprintk("dpram_pm %d %d\n", state, oldstate);
|
||
}
|
||
|
||
static void dpram_release_port(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_release_port\n");
|
||
}
|
||
|
||
static int dpram_request_port(struct uart_port *port)
|
||
{
|
||
dprintk("dpram_request_port\n");
|
||
return 0;
|
||
}
|
||
|
||
static void dpram_config_port(struct uart_port *port, int flags)
|
||
{
|
||
dprintk("dpram_config_port\n");
|
||
port->type = PORT_DPRAM;
|
||
}
|
||
|
||
static int
|
||
dpram_verify_port(struct uart_port *port, struct serial_struct *ser)
|
||
{
|
||
/* we don't want the core code to modify any port params */
|
||
return -EINVAL;
|
||
}
|
||
|
||
static const char *
|
||
dpram_type(struct uart_port *port)
|
||
{
|
||
return "DPRAM";
|
||
}
|
||
|
||
struct uart_ops dpram_pops = {
|
||
.tx_empty = dpram_tx_empty,
|
||
.set_mctrl = dpram_set_mctrl,
|
||
.get_mctrl = dpram_get_mctrl,
|
||
.stop_tx = dpram_stop_tx,
|
||
.start_tx = dpram_start_tx,
|
||
.stop_rx = dpram_stop_rx,
|
||
.enable_ms = dpram_enable_ms,
|
||
.break_ctl = dpram_break_ctl,
|
||
.startup = dpram_startup,
|
||
.shutdown = dpram_shutdown,
|
||
.set_termios = dpram_set_termios,
|
||
.pm = dpram_pm,
|
||
.type = dpram_type,
|
||
.release_port = dpram_release_port,
|
||
.request_port = dpram_request_port,
|
||
.config_port = dpram_config_port,
|
||
.verify_port = dpram_verify_port,
|
||
};
|
||
|
||
static struct uart_port dpram_port = {
|
||
.type = PORT_DPRAM,
|
||
.iotype = UPIO_MEM,
|
||
.irq = IRQ_RX,
|
||
.uartclk = 115000 * 16,
|
||
.fifosize = 64,
|
||
.ops = &dpram_pops,
|
||
.line = 0,
|
||
};
|
||
|
||
static struct uart_driver dpram_reg = {
|
||
.owner = THIS_MODULE,
|
||
.driver_name = "DPRAM serial",
|
||
.dev_name = "ttyS",
|
||
.major = TTY_MAJOR,
|
||
.minor = 72,
|
||
.nr = 1,
|
||
};
|
||
|
||
/*END AT UART*/
|
||
|
||
|
||
int __init dpram_init(void)
|
||
{
|
||
int ret;
|
||
|
||
if (!machine_is_g900())
|
||
return -ENODEV;
|
||
|
||
/** maping **/
|
||
dpram_data.data_phys=PXA_CS5_PHYS;
|
||
dpram_data.data_virt=ioremap(dpram_data.data_phys, 0x8000);
|
||
if (! dpram_data.data_virt) {
|
||
ret=-ENOMEM;
|
||
goto err1;
|
||
}
|
||
dpram_port.mapbase=dpram_data.data_phys;
|
||
|
||
/** at uart **/
|
||
ret = uart_register_driver(&dpram_reg);
|
||
if (ret != 0)
|
||
goto err2;
|
||
ret = uart_add_one_port(&dpram_reg, &dpram_port);
|
||
if (ret != 0)
|
||
goto err3;
|
||
|
||
batt_probe();
|
||
|
||
return 0;
|
||
|
||
err3:
|
||
uart_unregister_driver(&dpram_reg);
|
||
err2:
|
||
iounmap(dpram_data.data_virt);
|
||
err1:
|
||
return ret;
|
||
}
|
||
|
||
void __exit dpram_exit(void)
|
||
{
|
||
batt_remove();
|
||
uart_remove_one_port(&dpram_reg, &dpram_port);
|
||
uart_unregister_driver(&dpram_reg);
|
||
iounmap(dpram_data.data_virt);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
module_init(dpram_init);
|
||
module_exit(dpram_exit);
|
||
|
||
MODULE_AUTHOR("Angell Fear <angell@angellfear.ru>");
|
||
MODULE_DESCRIPTION("Dual Port RAM communication for Toshiba G900, PXA270<->MSM6280");
|
||
MODULE_LICENSE("GPL");
|