Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 165471
b: refs/heads/master
c: 49aac4a
h: refs/heads/master
i:
  165469: e821599
  165467: 8619a95
  165463: 0ecce88
  165455: a3b6d1b
  165439: 1adebca
v: v3
  • Loading branch information
Graf Yang authored and David Woodhouse committed Sep 19, 2009
1 parent 0048c7a commit aac050a
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 2 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 80f53da0ac752fe16a01ffeddaea658670974a05
refs/heads/master: 49aac4aec53c523f16343b4668a5a239b69659f1
126 changes: 125 additions & 1 deletion trunk/drivers/mtd/devices/m25p80.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
#define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */
#define OPCODE_RDID 0x9f /* Read JEDEC ID */

/* Used for SST flashes only. */
#define OPCODE_BP 0x02 /* Byte program */
#define OPCODE_WRDI 0x04 /* Write disable */
#define OPCODE_AAI_WP 0xad /* Auto address increment word program */

/* Status Register bits. */
#define SR_WIP 1 /* Write in progress */
#define SR_WEL 2 /* Write enable latch */
Expand Down Expand Up @@ -132,6 +137,15 @@ static inline int write_enable(struct m25p *flash)
return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}

/*
* Send write disble instruction to the chip.
*/
static inline int write_disable(struct m25p *flash)
{
u8 code = OPCODE_WRDI;

return spi_write_then_read(flash->spi, &code, 1, NULL, 0);
}

/*
* Service routine to read status register until ready, or timeout occurs.
Expand Down Expand Up @@ -454,6 +468,111 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
return 0;
}

static int sst_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct m25p *flash = mtd_to_m25p(mtd);
struct spi_transfer t[2];
struct spi_message m;
size_t actual;
int cmd_sz, ret;

if (retlen)
*retlen = 0;

/* sanity checks */
if (!len)
return 0;

if (to + len > flash->mtd.size)
return -EINVAL;

spi_message_init(&m);
memset(t, 0, (sizeof t));

t[0].tx_buf = flash->command;
t[0].len = CMD_SIZE;
spi_message_add_tail(&t[0], &m);

t[1].tx_buf = buf;
spi_message_add_tail(&t[1], &m);

mutex_lock(&flash->lock);

/* Wait until finished previous write command. */
ret = wait_till_ready(flash);
if (ret)
goto time_out;

write_enable(flash);

actual = to % 2;
/* Start write from odd address. */
if (actual) {
flash->command[0] = OPCODE_BP;
flash->command[1] = to >> 16;
flash->command[2] = to >> 8;
flash->command[3] = to;

/* write one byte. */
t[1].len = 1;
spi_sync(flash->spi, &m);
ret = wait_till_ready(flash);
if (ret)
goto time_out;
*retlen += m.actual_length - CMD_SIZE;
}
to += actual;

flash->command[0] = OPCODE_AAI_WP;
flash->command[1] = to >> 16;
flash->command[2] = to >> 8;
flash->command[3] = to;

/* Write out most of the data here. */
cmd_sz = CMD_SIZE;
for (; actual < len - 1; actual += 2) {
t[0].len = cmd_sz;
/* write two bytes. */
t[1].len = 2;
t[1].tx_buf = buf + actual;

spi_sync(flash->spi, &m);
ret = wait_till_ready(flash);
if (ret)
goto time_out;
*retlen += m.actual_length - cmd_sz;
cmd_sz = 1;
to += 2;
}
write_disable(flash);
ret = wait_till_ready(flash);
if (ret)
goto time_out;

/* Write out trailing byte if it exists. */
if (actual != len) {
write_enable(flash);
flash->command[0] = OPCODE_BP;
flash->command[1] = to >> 16;
flash->command[2] = to >> 8;
flash->command[3] = to;
t[0].len = CMD_SIZE;
t[1].len = 1;
t[1].tx_buf = buf + actual;

spi_sync(flash->spi, &m);
ret = wait_till_ready(flash);
if (ret)
goto time_out;
*retlen += m.actual_length - CMD_SIZE;
write_disable(flash);
}

time_out:
mutex_unlock(&flash->lock);
return ret;
}

/****************************************************************************/

Expand Down Expand Up @@ -670,7 +789,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
flash->mtd.size = info->sector_size * info->n_sectors;
flash->mtd.erase = m25p80_erase;
flash->mtd.read = m25p80_read;
flash->mtd.write = m25p80_write;

/* sst flash chips use AAI word program */
if (info->jedec_id >> 16 == 0xbf)
flash->mtd.write = sst_write;
else
flash->mtd.write = m25p80_write;

/* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) {
Expand Down

0 comments on commit aac050a

Please sign in to comment.