1/* 2 * Atmel AT93C46 serial eeprom driver 3 * 4 * Brian Murphy <brian.murphy@eicon.com> 5 * 6 */ 7#include <linux/kernel.h> 8#include <linux/delay.h> 9#include <asm/lasat/lasat.h> 10 11#include "at93c.h" 12 13#define AT93C_ADDR_SHIFT 7 14#define AT93C_ADDR_MAX ((1 << AT93C_ADDR_SHIFT) - 1) 15#define AT93C_RCMD (0x6 << AT93C_ADDR_SHIFT) 16#define AT93C_WCMD (0x5 << AT93C_ADDR_SHIFT) 17#define AT93C_WENCMD 0x260 18#define AT93C_WDSCMD 0x200 19 20struct at93c_defs *at93c; 21 22static void at93c_reg_write(u32 val) 23{ 24 *at93c->reg = val; 25} 26 27static u32 at93c_reg_read(void) 28{ 29 u32 tmp = *at93c->reg; 30 return tmp; 31} 32 33static u32 at93c_datareg_read(void) 34{ 35 u32 tmp = *at93c->rdata_reg; 36 return tmp; 37} 38 39static void at93c_cycle_clk(u32 data) 40{ 41 at93c_reg_write(data | at93c->clk); 42 lasat_ndelay(250); 43 at93c_reg_write(data & ~at93c->clk); 44 lasat_ndelay(250); 45} 46 47static void at93c_write_databit(u8 bit) 48{ 49 u32 data = at93c_reg_read(); 50 if (bit) 51 data |= 1 << at93c->wdata_shift; 52 else 53 data &= ~(1 << at93c->wdata_shift); 54 55 at93c_reg_write(data); 56 lasat_ndelay(100); 57 at93c_cycle_clk(data); 58} 59 60static unsigned int at93c_read_databit(void) 61{ 62 u32 data; 63 64 at93c_cycle_clk(at93c_reg_read()); 65 data = (at93c_datareg_read() >> at93c->rdata_shift) & 1; 66 return data; 67} 68 69static u8 at93c_read_byte(void) 70{ 71 int i; 72 u8 data = 0; 73 74 for (i = 0; i <= 7; i++) { 75 data <<= 1; 76 data |= at93c_read_databit(); 77 } 78 return data; 79} 80 81static void at93c_write_bits(u32 data, int size) 82{ 83 int i; 84 int shift = size - 1; 85 u32 mask = (1 << shift); 86 87 for (i = 0; i < size; i++) { 88 at93c_write_databit((data & mask) >> shift); 89 data <<= 1; 90 } 91} 92 93static void at93c_init_op(void) 94{ 95 at93c_reg_write((at93c_reg_read() | at93c->cs) & 96 ~at93c->clk & ~(1 << at93c->rdata_shift)); 97 lasat_ndelay(50); 98} 99 100static void at93c_end_op(void) 101{ 102 at93c_reg_write(at93c_reg_read() & ~at93c->cs); 103 lasat_ndelay(250); 104} 105 106static void at93c_wait(void) 107{ 108 at93c_init_op(); 109 while (!at93c_read_databit()) 110 ; 111 at93c_end_op(); 112}; 113 114static void at93c_disable_wp(void) 115{ 116 at93c_init_op(); 117 at93c_write_bits(AT93C_WENCMD, 10); 118 at93c_end_op(); 119} 120 121static void at93c_enable_wp(void) 122{ 123 at93c_init_op(); 124 at93c_write_bits(AT93C_WDSCMD, 10); 125 at93c_end_op(); 126} 127 128u8 at93c_read(u8 addr) 129{ 130 u8 byte; 131 at93c_init_op(); 132 at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_RCMD, 10); 133 byte = at93c_read_byte(); 134 at93c_end_op(); 135 return byte; 136} 137 138void at93c_write(u8 addr, u8 data) 139{ 140 at93c_disable_wp(); 141 at93c_init_op(); 142 at93c_write_bits((addr & AT93C_ADDR_MAX)|AT93C_WCMD, 10); 143 at93c_write_bits(data, 8); 144 at93c_end_op(); 145 at93c_wait(); 146 at93c_enable_wp(); 147} 148