mirror of https://github.com/Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
141 lines
3.4 KiB
141 lines
3.4 KiB
// SPDX-License-Identifier: GPL-2.0-or-later |
|
/* |
|
* Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com> |
|
* |
|
* Original author: |
|
* Ben Collins <[email protected]> |
|
* |
|
* Additional work by: |
|
* John Brooks <[email protected]> |
|
*/ |
|
|
|
#include <linux/kernel.h> |
|
#include <linux/delay.h> |
|
|
|
#include "solo6x10.h" |
|
|
|
/* Control */ |
|
#define EE_SHIFT_CLK 0x04 |
|
#define EE_CS 0x08 |
|
#define EE_DATA_WRITE 0x02 |
|
#define EE_DATA_READ 0x01 |
|
#define EE_ENB (0x80 | EE_CS) |
|
|
|
#define eeprom_delay() udelay(100) |
|
#if 0 |
|
#define eeprom_delay() solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) |
|
#define eeprom_delay() ({ \ |
|
int i, ret; \ |
|
udelay(100); \ |
|
for (i = ret = 0; i < 1000 && !ret; i++) \ |
|
ret = solo_eeprom_reg_read(solo_dev); \ |
|
}) |
|
#endif |
|
#define ADDR_LEN 6 |
|
|
|
/* Commands */ |
|
#define EE_EWEN_CMD 4 |
|
#define EE_EWDS_CMD 4 |
|
#define EE_WRITE_CMD 5 |
|
#define EE_READ_CMD 6 |
|
#define EE_ERASE_CMD 7 |
|
|
|
static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev) |
|
{ |
|
return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ; |
|
} |
|
|
|
static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data) |
|
{ |
|
solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data); |
|
eeprom_delay(); |
|
} |
|
|
|
static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd) |
|
{ |
|
int i; |
|
|
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN); |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
|
|
|
for (i = 4 + ADDR_LEN; i >= 0; i--) { |
|
int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0; |
|
|
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval); |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
|
EE_SHIFT_CLK | dataval); |
|
} |
|
|
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
|
} |
|
|
|
unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en) |
|
{ |
|
int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN); |
|
unsigned int retval = 0; |
|
int i; |
|
|
|
solo_eeprom_cmd(solo_dev, ewen_cmd); |
|
|
|
for (i = 0; i < 16; i++) { |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
|
EE_SHIFT_CLK); |
|
retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
|
retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
|
} |
|
|
|
solo_eeprom_reg_write(solo_dev, ~EE_CS); |
|
retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
|
|
|
return retval; |
|
} |
|
|
|
__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc) |
|
{ |
|
int read_cmd = loc | (EE_READ_CMD << ADDR_LEN); |
|
u16 retval = 0; |
|
int i; |
|
|
|
solo_eeprom_cmd(solo_dev, read_cmd); |
|
|
|
for (i = 0; i < 16; i++) { |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | |
|
EE_SHIFT_CLK); |
|
retval = (retval << 1) | solo_eeprom_reg_read(solo_dev); |
|
solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE); |
|
} |
|
|
|
solo_eeprom_reg_write(solo_dev, ~EE_CS); |
|
|
|
return (__force __be16)retval; |
|
} |
|
|
|
int solo_eeprom_write(struct solo_dev *solo_dev, int loc, |
|
__be16 data) |
|
{ |
|
int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN); |
|
unsigned int retval; |
|
int i; |
|
|
|
solo_eeprom_cmd(solo_dev, write_cmd); |
|
|
|
for (i = 15; i >= 0; i--) { |
|
unsigned int dataval = ((__force unsigned)data >> i) & 1; |
|
|
|
solo_eeprom_reg_write(solo_dev, EE_ENB); |
|
solo_eeprom_reg_write(solo_dev, |
|
EE_ENB | (dataval << 1) | EE_SHIFT_CLK); |
|
} |
|
|
|
solo_eeprom_reg_write(solo_dev, EE_ENB); |
|
solo_eeprom_reg_write(solo_dev, ~EE_CS); |
|
solo_eeprom_reg_write(solo_dev, EE_ENB); |
|
|
|
for (i = retval = 0; i < 10000 && !retval; i++) |
|
retval = solo_eeprom_reg_read(solo_dev); |
|
|
|
solo_eeprom_reg_write(solo_dev, ~EE_CS); |
|
|
|
return !retval; |
|
}
|
|
|