|
@@ -1,5 +1,5 @@
|
|
|
/*
|
|
|
- * SPI driver for Micrel/Kendin KS8995M ethernet switch
|
|
|
+ * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
|
|
|
*
|
|
|
* Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
|
|
|
*
|
|
@@ -70,7 +70,10 @@
|
|
|
#define KS8995_REG_IAD1 0x76 /* Indirect Access Data 1 */
|
|
|
#define KS8995_REG_IAD0 0x77 /* Indirect Access Data 0 */
|
|
|
|
|
|
+#define KSZ8864_REG_ID1 0xfe /* Chip ID in bit 7 */
|
|
|
+
|
|
|
#define KS8995_REGS_SIZE 0x80
|
|
|
+#define KSZ8864_REGS_SIZE 0x100
|
|
|
|
|
|
#define ID1_CHIPID_M 0xf
|
|
|
#define ID1_CHIPID_S 4
|
|
@@ -94,6 +97,7 @@ struct ks8995_switch {
|
|
|
struct spi_device *spi;
|
|
|
struct mutex lock;
|
|
|
struct ks8995_pdata *pdata;
|
|
|
+ struct bin_attribute regs_attr;
|
|
|
};
|
|
|
|
|
|
static inline u8 get_chip_id(u8 val)
|
|
@@ -216,11 +220,11 @@ static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj,
|
|
|
dev = container_of(kobj, struct device, kobj);
|
|
|
ks8995 = dev_get_drvdata(dev);
|
|
|
|
|
|
- if (unlikely(off > KS8995_REGS_SIZE))
|
|
|
+ if (unlikely(off > ks8995->regs_attr.size))
|
|
|
return 0;
|
|
|
|
|
|
- if ((off + count) > KS8995_REGS_SIZE)
|
|
|
- count = KS8995_REGS_SIZE - off;
|
|
|
+ if ((off + count) > ks8995->regs_attr.size)
|
|
|
+ count = ks8995->regs_attr.size - off;
|
|
|
|
|
|
if (unlikely(!count))
|
|
|
return count;
|
|
@@ -238,11 +242,11 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
|
|
|
dev = container_of(kobj, struct device, kobj);
|
|
|
ks8995 = dev_get_drvdata(dev);
|
|
|
|
|
|
- if (unlikely(off >= KS8995_REGS_SIZE))
|
|
|
+ if (unlikely(off >= ks8995->regs_attr.size))
|
|
|
return -EFBIG;
|
|
|
|
|
|
- if ((off + count) > KS8995_REGS_SIZE)
|
|
|
- count = KS8995_REGS_SIZE - off;
|
|
|
+ if ((off + count) > ks8995->regs_attr.size)
|
|
|
+ count = ks8995->regs_attr.size - off;
|
|
|
|
|
|
if (unlikely(!count))
|
|
|
return count;
|
|
@@ -251,7 +255,7 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
|
|
|
}
|
|
|
|
|
|
|
|
|
-static struct bin_attribute ks8995_registers_attr = {
|
|
|
+static const struct bin_attribute ks8995_registers_attr = {
|
|
|
.attr = {
|
|
|
.name = "registers",
|
|
|
.mode = S_IRUSR | S_IWUSR,
|
|
@@ -306,20 +310,44 @@ static int ks8995_probe(struct spi_device *spi)
|
|
|
goto err_drvdata;
|
|
|
}
|
|
|
|
|
|
+ memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr));
|
|
|
+ if (get_chip_id(ids[1]) != CHIPID_M) {
|
|
|
+ u8 val;
|
|
|
+
|
|
|
+ /* Check if this is a KSZ8864RMN */
|
|
|
+ err = ks8995_read(ks, &val, KSZ8864_REG_ID1, sizeof(val));
|
|
|
+ if (err < 0) {
|
|
|
+ dev_err(&spi->dev,
|
|
|
+ "unable to read chip id register, err=%d\n",
|
|
|
+ err);
|
|
|
+ goto err_drvdata;
|
|
|
+ }
|
|
|
+ if ((val & 0x80) == 0) {
|
|
|
+ dev_err(&spi->dev, "unknown chip:%02x,0\n", ids[1]);
|
|
|
+ goto err_drvdata;
|
|
|
+ }
|
|
|
+ ks->regs_attr.size = KSZ8864_REGS_SIZE;
|
|
|
+ }
|
|
|
+
|
|
|
err = ks8995_reset(ks);
|
|
|
if (err)
|
|
|
goto err_drvdata;
|
|
|
|
|
|
- err = sysfs_create_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
|
|
|
+ err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr);
|
|
|
if (err) {
|
|
|
dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
|
|
|
err);
|
|
|
goto err_drvdata;
|
|
|
}
|
|
|
|
|
|
- dev_info(&spi->dev, "KS89%02X device found, Chip ID:%01x, "
|
|
|
- "Revision:%01x\n", ids[0],
|
|
|
- get_chip_id(ids[1]), get_chip_rev(ids[1]));
|
|
|
+ if (get_chip_id(ids[1]) == CHIPID_M) {
|
|
|
+ dev_info(&spi->dev,
|
|
|
+ "KS8995 device found, Chip ID:%x, Revision:%x\n",
|
|
|
+ get_chip_id(ids[1]), get_chip_rev(ids[1]));
|
|
|
+ } else {
|
|
|
+ dev_info(&spi->dev, "KSZ8864 device found, Revision:%x\n",
|
|
|
+ get_chip_rev(ids[1]));
|
|
|
+ }
|
|
|
|
|
|
return 0;
|
|
|
|