blob: eae3667d3594625b56541b7d66e899e486ef4d47 [file] [log] [blame]
/*
* Copyright C 2011 by Amlogic, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
*
*
*/
#include <asm/arch/io.h>
#include <asm/cpu_id.h>
#include <common.h>
#include <config.h>
#include <command.h>
#include <amlogic/aml_irblaster.h>
#include <asm/arch/secure_apb.h>
static struct aml_irblaster_drv_s irblaster_drviver;
const char *protocol_name[] = {
"NEC",
};
/*NEC key value*/
#define NEC_HEADER 9000
#define NEC_IDLE 4500
const static int NEC_END[] = {
560,
560
};
const static int NEC_ONE[] = {
560,
1690
};
const static int NEC_ZERO[] = {
560,
560
};
static void get_nec_data(unsigned int value)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
unsigned int num = 0;
int index;
unsigned int *pdata = drv->windows;
pdata[num++] = NEC_HEADER;
pdata[num++] = NEC_IDLE;
/*low bit first*/
for (index = 0; index < 32; index++) {
if (value & (0x01 << index)) {
pdata[num++] = NEC_ONE[0];
pdata[num++] = NEC_ONE[1];
} else {
pdata[num++] = NEC_ZERO[0];
pdata[num++] = NEC_ZERO[1];
}
}
pdata[num++] = NEC_END[0];
pdata[num++] = NEC_END[1];
drv->windows_num = num;
drv->sendvalue = value;
}
static int send_bit(unsigned int hightime, unsigned int lowtime,
unsigned int cycle)
{
unsigned int count_delay;
uint32_t val;
int n = 0;
int tb[3] = {
1, 10, 100
};
/*
AO_IR_BLASTER_ADDR2
bit12: output level(or modulation enable/disable:1=enable)
bit[11:10]: Timebase :
00=1us
01=10us
10=100us
11=Modulator clock
bit[9:0]: Count of timebase units to delay
*/
count_delay = (((hightime + cycle/2) / cycle) - 1) & 0x3ff;
val = (0x10000 | (1 << 12)) | (3 << 10) | (count_delay << 0);
writel(val, AO_IR_BLASTER_ADDR2);
/*
lowtime<1024,n=0,timebase=1us
1024<=lowtime<10240,n=1,timebase=10us
10240<=lowtime,n=2,timebase=100us
*/
n = lowtime >> 10;
if (n > 0 && n < 10)
n = 1;
else if (n >= 10)
n = 2;
lowtime = (lowtime + (tb[n] >> 1))/tb[n];
count_delay = (lowtime-1) & 0x3ff;
val = (0x10000 | (0 << 12)) |
(n << 10) | (count_delay << 0);
writel(val, AO_IR_BLASTER_ADDR2);
return 0;
}
static void send_frame(void)
{
int i;
int exp = 0x00;
unsigned int* pdata;
unsigned int high_ct, low_ct;
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
unsigned int consumerir_cycle = 1000 / (drv->frequency / 1000);
/*reset*/
writel(readl(AO_RTI_GEN_CNTL_REG0) | (1 << 23), AO_IR_BLASTER_ADDR2);
udelay(2);
writel(readl(AO_RTI_GEN_CNTL_REG0) & ~(1 << 23), AO_IR_BLASTER_ADDR2);
/*
1. disable ir blaster
2. set the modulator_tb = 2'10; mpeg_1uS_tick 1us
*/
writel((1 << 2) | (2 << 12) | (1<<2), AO_IR_BLASTER_ADDR0);
/*
1. set mod_high_count = 13
2. set mod_low_count = 13
3. 60khz 8, 38k-13us, 12
*/
high_ct = consumerir_cycle * drv->dutycycle/100;
low_ct = consumerir_cycle - high_ct;
writel(((high_ct - 1) << 16) | ((low_ct - 1) << 0),
AO_IR_BLASTER_ADDR1);
/* Setting this bit to 1 initializes the output to be high.*/
writel(readl(AO_IR_BLASTER_ADDR0) & ~(1 << 2), AO_IR_BLASTER_ADDR0);
/*enable irblaster*/
writel(readl(AO_IR_BLASTER_ADDR0) | (1 << 0), AO_IR_BLASTER_ADDR0);
#define SEND_BIT_NUM 64
exp = drv->windows_num / SEND_BIT_NUM;
pdata = drv->windows;
while (exp) {
for (i = 0; i < SEND_BIT_NUM/2; i++) {
send_bit(*pdata, *(pdata+1), consumerir_cycle);
pdata += 2;
}
while (!(readl(AO_IR_BLASTER_ADDR0) & (1<<24))) ;
while (readl(AO_IR_BLASTER_ADDR0) & (1<<26)) ;
/*reset*/
writel(readl(AO_RTI_GEN_CNTL_REG0) | (1 << 23),
AO_RTI_GEN_CNTL_REG0);
udelay(2);
/*reset*/
writel(readl(AO_RTI_GEN_CNTL_REG0) & ~(1 << 23),
AO_RTI_GEN_CNTL_REG0);
exp--;
}
exp = (drv->windows_num % SEND_BIT_NUM) & (~(1));
for (i = 0; i < exp; ) {
send_bit(*pdata, *(pdata+1), consumerir_cycle);
pdata += 2;
i += 2;
}
}
extern void irblaster_pinmux_config(void);
static int open(void)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
drv->protocol = 0; /*default NEC*/
drv->frequency = 38000; /*freq 38k*/
/*pinmux*/
irblaster_pinmux_config();
drv->openflag = 1;
return 0;
}
static int close(void)
{
return 0;
}
static int send(unsigned int value)
{
get_nec_data(value);
send_frame();
return 0;
}
static void print_windows(void)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
int n;
unsigned int *pdata;
pdata = drv->windows;
n = drv->windows_num;
printf ("sendvalue:%u\n", drv->sendvalue);
printf ("windows_number:%d\n", n);
printf ("windows:\n");
while (n--)
printf ("%d\n", *pdata++);
}
static int setprotocol(char *name)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
int p = 0;
int size = sizeof(protocol_name) / sizeof(protocol_name[0]);
for (p = 0; p < size; p++) {
if (!strcmp(protocol_name[p], name)) {
drv->protocol = p;
return 0;
}
}
return CMD_RET_USAGE;
}
static const char *getprocotol(void)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
int size = sizeof(protocol_name) / sizeof(protocol_name[0]);
if (drv->protocol >= size)
return NULL;
return protocol_name[drv->protocol];
}
static int setfrequency(unsigned int freq)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
if (freq < 20000 || freq > 60000) {
printf("20000<freq<60000\n");
return CMD_RET_USAGE;
}
drv->frequency = freq;
return 0;
}
static unsigned int getfrequency(void)
{
struct aml_irblaster_drv_s *drv = aml_irblaster_get_driver();
return drv->frequency;
}
unsigned char ci_nec_fe01[] = {
0x01,
0x02,
0x03,
0x04,
0x05,
0x06,
0x07,
0x08,
0x09,
0x0a,
0x1F,
0x15,
0x16,
0x0c,
0x0d,
0x0e,
0x0f,
0x11,
0x1c,
0x1b,
0x19,
0x1a,
0x1d,
0x17,
0x49,
0x43,
0x12,
0x14,
0x18,
0x59,
0x5a,
0x42,
0x44,
0x1e,
0x4b,
0x58,
0x46,
0x40,
0x38,
0x57,
0x5b,
0x54,
0x4c,
0x4e,
0x55,
0x53,
0x52,
0x39,
0x41,
0x0b,
0x00,
0x13
};
static int loop_test(unsigned int times)
{
unsigned int framecode;
int n, cnt = 0;
int size = ARRAY_SIZE(ci_nec_fe01);
printf("test loop...\n");
for ( ; times--; ) {
printf("times=%d\n", cnt++);
for (n = 0; n < size; n++) {
framecode = 0xfe01 | ((~ci_nec_fe01[n] & 0xff) << 24) |
(ci_nec_fe01[n] << 16);
printf("0x%x\n", framecode);
get_nec_data(framecode);
send_frame();
mdelay(500);
}
}
return 0;
}
int read_reg(volatile unsigned int *addr, unsigned int length)
{
int n;
int value;
printf("read_reg\n");
for (n = 0; n < length; n++) {
value = readl(addr);
printf("0x%p=0x%x\n", addr, value);
++addr;
}
return 0;
}
int write_reg(volatile unsigned int *addr, unsigned int value)
{
writel(value, addr);
printf("0x%p=0x%x", addr, value);
return 0;
}
static struct aml_irblaster_drv_s irblaster_drviver = {
.frequency = 38000,
.dutycycle = 50,
.protocol = 0,
.windows_num = 0,
.openflag = 0,
.open = open,
.close = close,
.send = send,
.setprotocol = setprotocol,
.getprocotol = getprocotol,
.setfrequency = setfrequency,
.getfrequency = getfrequency,
.test = loop_test,
.print_windows = print_windows,
.read_reg = read_reg,
.write_reg = write_reg,
};
struct aml_irblaster_drv_s *aml_irblaster_get_driver(void)
{
return &irblaster_drviver;
}