* [PATCH] misc: eeprom: add driver for Cypress FRAM
@ 2014-10-14 9:23 Jiri Prchal
[not found] ` <8bfffe403f558ff93b50ae4088848c1c489c485b.1413278480.git.jiri.prchal-cKCO0sOKHLPtwjQa/ONI9g@public.gmane.org>
0 siblings, 1 reply; 2+ messages in thread
From: Jiri Prchal @ 2014-10-14 9:23 UTC (permalink / raw)
To: linux-i2c-u79uwXL29TY76Z2rM5mHXA; +Cc: wsa-z923LK4zBo2bacvFa/9K2g, Jiri Prchal
This patch adds driver for Cypress FRAMs on SPI bus, such as FM25V05, FM25V10
etc.
Reworked from at25 driver:
- simplified writing since data are written without erasing and waiting to
finish write cycle
- add reading device ID and choose size and addr len from it
- add serial number reading and exporting it to sysfs
Signed-off-by: Jiri Prchal <jiri.prchal-cKCO0sOKHLPtwjQa/ONI9g@public.gmane.org>
---
drivers/misc/eeprom/Kconfig | 11 +
drivers/misc/eeprom/Makefile | 1 +
drivers/misc/eeprom/fm25.c | 500 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 512 insertions(+)
diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
index 9536852f..aee6a73 100644
--- a/drivers/misc/eeprom/Kconfig
+++ b/drivers/misc/eeprom/Kconfig
@@ -38,6 +38,17 @@ config EEPROM_AT25
This driver can also be built as a module. If so, the module
will be called at25.
+config FRAM_FM25
+ tristate "SPI Cypress FRAM"
+ depends on SPI && SYSFS
+ help
+ Enable this driver to get read/write support to SPI FRAMs,
+ after you configure the board init code to know about each fram
+ on your target board.
+
+ This driver can also be built as a module. If so, the module
+ will be called fm25.
+
config EEPROM_LEGACY
tristate "Old I2C EEPROM reader"
depends on I2C && SYSFS
diff --git a/drivers/misc/eeprom/Makefile b/drivers/misc/eeprom/Makefile
index 9507aec..6738752 100644
--- a/drivers/misc/eeprom/Makefile
+++ b/drivers/misc/eeprom/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_EEPROM_AT24) += at24.o
obj-$(CONFIG_EEPROM_AT25) += at25.o
+obj-$(CONFIG_FRAM_FM25) += fm25.o
obj-$(CONFIG_EEPROM_LEGACY) += eeprom.o
obj-$(CONFIG_EEPROM_MAX6875) += max6875.o
obj-$(CONFIG_EEPROM_93CX6) += eeprom_93cx6.o
diff --git a/drivers/misc/eeprom/fm25.c b/drivers/misc/eeprom/fm25.c
new file mode 100644
index 0000000..6a33b4d
--- /dev/null
+++ b/drivers/misc/eeprom/fm25.c
@@ -0,0 +1,500 @@
+/*
+ * fm25.c -- support SPI FRAMs, such as Cypress FM25 models
+ *
+ * Copyright (C) 2014 Jiri Prchal
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/sched.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+#include <linux/of.h>
+
+struct fm25_data {
+ struct spi_device *spi;
+ struct memory_accessor mem;
+ struct mutex lock;
+ struct spi_eeprom chip;
+ struct bin_attribute bin;
+ unsigned addrlen;
+ int has_sernum;
+};
+
+#define FM25_WREN 0x06 /* latch the write enable */
+#define FM25_WRDI 0x04 /* reset the write enable */
+#define FM25_RDSR 0x05 /* read status register */
+#define FM25_WRSR 0x01 /* write status register */
+#define FM25_READ 0x03 /* read byte(s) */
+#define FM25_WRITE 0x02 /* write byte(s)/sector */
+#define FM25_SLEEP 0xb9 /* enter sleep mode */
+#define FM25_RDID 0x9f /* read device ID */
+#define FM25_RDSN 0xc3 /* read S/N */
+
+#define FM25_SR_WEN 0x02 /* write enable (latched) */
+#define FM25_SR_BP0 0x04 /* BP for software writeprotect */
+#define FM25_SR_BP1 0x08
+#define FM25_SR_WPEN 0x80 /* writeprotect enable */
+
+#define FM25_ID_LEN 9 /* ID lenght */
+#define FM25_SN_LEN 8 /* serial number lenght */
+
+#define FM25_MAXADDRLEN 3 /* 24 bit addresses */
+
+#define io_limit PAGE_SIZE /* bytes */
+
+static ssize_t
+fm25_data_read(
+ struct fm25_data *fm25,
+ char *buf,
+ unsigned offset,
+ size_t count
+)
+{
+ u8 command[FM25_MAXADDRLEN + 1];
+ u8 *cp;
+ ssize_t status;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u8 instr;
+
+ if (unlikely(offset >= fm25->bin.size))
+ return 0;
+ if ((offset + count) > fm25->bin.size)
+ count = fm25->bin.size - offset;
+ if (unlikely(!count))
+ return count;
+
+ cp = command;
+
+ instr = FM25_READ;
+ *cp++ = instr;
+
+ /* 8/16/24-bit address is written MSB first */
+ switch (fm25->addrlen) {
+ default: /* case 3 */
+ *cp++ = offset >> 16;
+ case 2:
+ *cp++ = offset >> 8;
+ case 1:
+ case 0: /* can't happen: for better codegen */
+ *cp++ = offset >> 0;
+ }
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof t);
+
+ t[0].tx_buf = command;
+ t[0].len = fm25->addrlen + 1;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = count;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&fm25->lock);
+
+ /* Read it all at once.
+ *
+ * REVISIT that's potentially a problem with large chips, if
+ * other devices on the bus need to be accessed regularly or
+ * this chip is clocked very slowly
+ */
+ status = spi_sync(fm25->spi, &m);
+ dev_dbg(&fm25->spi->dev,
+ "read %Zd bytes at %d --> %d\n",
+ count, offset, (int) status);
+
+ mutex_unlock(&fm25->lock);
+ return status ? status : count;
+}
+
+static ssize_t
+fm25_id_read(struct fm25_data *fm25, char *buf)
+{
+ u8 command = FM25_RDID;
+ ssize_t status;
+ struct spi_transfer t[2];
+ struct spi_message m;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof t);
+
+ t[0].tx_buf = &command;
+ t[0].len = 1;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = FM25_ID_LEN;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&fm25->lock);
+
+ status = spi_sync(fm25->spi, &m);
+ dev_dbg(&fm25->spi->dev,
+ "read %Zd bytes of ID --> %d\n",
+ FM25_ID_LEN, (int) status);
+
+ mutex_unlock(&fm25->lock);
+ return status ? status : FM25_ID_LEN;
+}
+
+static ssize_t
+fm25_sernum_read(struct fm25_data *fm25, char *buf)
+{
+ u8 command = FM25_RDSN;
+ ssize_t status;
+ struct spi_transfer t[2];
+ struct spi_message m;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof t);
+
+ t[0].tx_buf = &command;
+ t[0].len = 1;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = FM25_SN_LEN;
+ spi_message_add_tail(&t[1], &m);
+
+ mutex_lock(&fm25->lock);
+
+ status = spi_sync(fm25->spi, &m);
+ dev_dbg(&fm25->spi->dev,
+ "read %Zd bytes of serial number --> %d\n",
+ FM25_SN_LEN, (int) status);
+
+ mutex_unlock(&fm25->lock);
+ return status ? status : FM25_SN_LEN;
+}
+
+static ssize_t
+sernum_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ char binbuf[FM25_SN_LEN];
+ struct fm25_data *fm25;
+ int i;
+ char *pbuf = buf;
+
+ fm25 = dev_get_drvdata(dev);
+ fm25_sernum_read(fm25, binbuf);
+ for (i = 0; i < FM25_SN_LEN; i++)
+ pbuf += sprintf(pbuf, "%02x ", binbuf[i]);
+ sprintf(--pbuf, "\n");
+ return (3 * i);
+}
+static const DEVICE_ATTR_RO(sernum);
+
+static ssize_t
+fm25_bin_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct fm25_data *fm25;
+
+ dev = container_of(kobj, struct device, kobj);
+ fm25 = dev_get_drvdata(dev);
+
+ return fm25_data_read(fm25, buf, off, count);
+}
+
+
+static ssize_t
+fm25_data_write(struct fm25_data *fm25, const char *buf, loff_t off,
+ size_t count)
+{
+ ssize_t status = 0;
+ unsigned written = 0;
+ unsigned buf_size;
+ u8 *bounce;
+
+ if (unlikely(off >= fm25->bin.size))
+ return -EFBIG;
+ if ((off + count) > fm25->bin.size)
+ count = fm25->bin.size - off;
+ if (unlikely(!count))
+ return count;
+
+ /* Temp buffer starts with command and address */
+ buf_size = io_limit;
+ bounce = kmalloc(buf_size + fm25->addrlen + 1, GFP_KERNEL);
+ if (!bounce)
+ return -ENOMEM;
+
+ /* For write, rollover is within the page ... so we write at
+ * most one page, then manually roll over to the next page.
+ */
+ mutex_lock(&fm25->lock);
+ do {
+ unsigned segment;
+ unsigned offset = (unsigned) off;
+ u8 *cp = bounce;
+ u8 instr;
+
+ *cp = FM25_WREN;
+ status = spi_write(fm25->spi, cp, 1);
+ if (status < 0) {
+ dev_dbg(&fm25->spi->dev, "WREN --> %d\n",
+ (int) status);
+ break;
+ }
+
+ instr = FM25_WRITE;
+ *cp++ = instr;
+
+ /* 8/16/24-bit address is written MSB first */
+ switch (fm25->addrlen) {
+ default: /* case 3 */
+ *cp++ = offset >> 16;
+ case 2:
+ *cp++ = offset >> 8;
+ case 1:
+ case 0: /* can't happen: for better codegen */
+ *cp++ = offset >> 0;
+ }
+
+ /* Write as much of a page as we can */
+ segment = buf_size - (offset % buf_size);
+ if (segment > count)
+ segment = count;
+ memcpy(cp, buf, segment);
+ status = spi_write(fm25->spi, bounce,
+ segment + fm25->addrlen + 1);
+ dev_dbg(&fm25->spi->dev,
+ "write %u bytes at %u --> %d\n",
+ segment, offset, (int) status);
+ if (status < 0)
+ break;
+
+ /* REVISIT this should detect (or prevent) failed writes
+ * to readonly sections of the EEPROM...
+ */
+
+ off += segment;
+ buf += segment;
+ count -= segment;
+ written += segment;
+
+ } while (count > 0);
+
+ mutex_unlock(&fm25->lock);
+
+ kfree(bounce);
+ return written ? written : status;
+}
+
+static ssize_t
+fm25_bin_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev;
+ struct fm25_data *fm25;
+
+ dev = container_of(kobj, struct device, kobj);
+ fm25 = dev_get_drvdata(dev);
+
+ return fm25_data_write(fm25, buf, off, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* Let in-kernel code access the eeprom data. */
+
+static ssize_t fm25_mem_read(struct memory_accessor *mem, char *buf,
+ off_t offset, size_t count)
+{
+ struct fm25_data *fm25 = container_of(mem, struct fm25_data, mem);
+
+ return fm25_data_read(fm25, buf, offset, count);
+}
+
+static ssize_t fm25_mem_write(struct memory_accessor *mem, const char *buf,
+ off_t offset, size_t count)
+{
+ struct fm25_data *fm25 = container_of(mem, struct fm25_data, mem);
+
+ return fm25_data_write(fm25, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int fm25_np_to_chip(struct device *dev,
+ struct device_node *np,
+ struct spi_eeprom *chip)
+{
+ memset(chip, 0, sizeof(*chip));
+ strncpy(chip->name, np->name, sizeof(chip->name));
+
+ if (of_find_property(np, "read-only", NULL))
+ chip->flags |= EE_READONLY;
+ return 0;
+}
+
+static int fm25_probe(struct spi_device *spi)
+{
+ struct fm25_data *fm25 = NULL;
+ struct spi_eeprom chip;
+ struct device_node *np = spi->dev.of_node;
+ int err;
+ char id[FM25_ID_LEN];
+
+ /* Chip description */
+ if (!spi->dev.platform_data) {
+ if (np) {
+ err = fm25_np_to_chip(&spi->dev, np, &chip);
+ if (err)
+ return err;
+ } else {
+ dev_err(&spi->dev, "Error: no chip description\n");
+ return -ENODEV;
+ }
+ } else
+ chip = *(struct spi_eeprom *)spi->dev.platform_data;
+
+ fm25 = devm_kzalloc(&spi->dev, sizeof(struct fm25_data), GFP_KERNEL);
+ if (!fm25)
+ return -ENOMEM;
+
+ mutex_init(&fm25->lock);
+ fm25->chip = chip;
+ fm25->spi = spi_dev_get(spi);
+ spi_set_drvdata(spi, fm25);
+
+ /* Get ID of chip */
+ fm25_id_read(fm25, id);
+ if (id[6] != 0xc2) {
+ dev_err(&spi->dev, "Error: no Cypress FRAM (id %02x)\n", id[6]);
+ return -ENODEV;
+ }
+ /* set size found in ID */
+ switch (id[7]) {
+ case 0x21:
+ fm25->chip.byte_len = 16 * 1024;
+ break;
+ case 0x22:
+ fm25->chip.byte_len = 32 * 1024;
+ break;
+ case 0x23:
+ fm25->chip.byte_len = 64 * 1024;
+ break;
+ case 0x24:
+ fm25->chip.byte_len = 128 * 1024;
+ break;
+ case 0x25:
+ fm25->chip.byte_len = 256 * 1024;
+ break;
+ default:
+ dev_err(&spi->dev,
+ "Error: unsupported size (id %02x)\n", id[7]);
+ return -ENODEV;
+ break;
+ }
+
+ if (fm25->chip.byte_len > 64 * 1024) {
+ fm25->addrlen = 3;
+ fm25->chip.flags |= EE_ADDR3;
+ }
+ else {
+ fm25->addrlen = 2;
+ fm25->chip.flags |= EE_ADDR2;
+ }
+
+ if (id[8])
+ fm25->has_sernum = 1;
+ else
+ fm25->has_sernum = 0;
+
+ /* Export the EEPROM bytes through sysfs, since that's convenient.
+ * And maybe to other kernel code; it might hold a board's Ethernet
+ * address, or board-specific calibration data generated on the
+ * manufacturing floor.
+ *
+ * Default to root-only access to the data; EEPROMs often hold data
+ * that's sensitive for read and/or write, like ethernet addresses,
+ * security codes, board-specific manufacturing calibrations, etc.
+ */
+ sysfs_bin_attr_init(&fm25->bin);
+ fm25->bin.attr.name = "fram";
+ fm25->bin.attr.mode = S_IRUGO;
+ fm25->bin.read = fm25_bin_read;
+ fm25->mem.read = fm25_mem_read;
+
+ fm25->bin.size = fm25->chip.byte_len;
+ if (!(chip.flags & EE_READONLY)) {
+ fm25->bin.write = fm25_bin_write;
+ fm25->bin.attr.mode |= S_IWUSR | S_IWGRP;
+ fm25->mem.write = fm25_mem_write;
+ }
+
+ err = sysfs_create_bin_file(&spi->dev.kobj, &fm25->bin);
+ if (err)
+ return err;
+
+ /* Export the FM25 serial number */
+ if (fm25->has_sernum) {
+ err = device_create_file(&spi->dev, &dev_attr_sernum);
+ if (err)
+ return err;
+ }
+
+ if (chip.setup)
+ chip.setup(&fm25->mem, chip.context);
+
+ dev_info(&spi->dev, "%Zd %s %s fram%s\n",
+ (fm25->bin.size < 1024)
+ ? fm25->bin.size
+ : (fm25->bin.size / 1024),
+ (fm25->bin.size < 1024) ? "Byte" : "KByte",
+ fm25->chip.name,
+ (chip.flags & EE_READONLY) ? " (readonly)" : "");
+ return 0;
+}
+
+static int fm25_remove(struct spi_device *spi)
+{
+ struct fm25_data *fm25;
+
+ fm25 = spi_get_drvdata(spi);
+ sysfs_remove_bin_file(&spi->dev.kobj, &fm25->bin);
+ if (fm25->has_sernum)
+ device_remove_file(&spi->dev, &dev_attr_sernum);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static const struct of_device_id fm25_of_match[] = {
+ { .compatible = "cypress,fm25", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, fm25_of_match);
+
+static struct spi_driver fm25_driver = {
+ .driver = {
+ .name = "fm25",
+ .owner = THIS_MODULE,
+ .of_match_table = fm25_of_match,
+ },
+ .probe = fm25_probe,
+ .remove = fm25_remove,
+};
+
+module_spi_driver(fm25_driver);
+
+MODULE_DESCRIPTION("Driver for Cypress SPI FRAMs");
+MODULE_AUTHOR("Jiri Prchal");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("spi:fram");
--
1.9.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] misc: eeprom: add driver for Cypress FRAM
[not found] ` <8bfffe403f558ff93b50ae4088848c1c489c485b.1413278480.git.jiri.prchal-cKCO0sOKHLPtwjQa/ONI9g@public.gmane.org>
@ 2014-10-14 9:42 ` Varka Bhadram
0 siblings, 0 replies; 2+ messages in thread
From: Varka Bhadram @ 2014-10-14 9:42 UTC (permalink / raw)
To: Jiri Prchal, linux-i2c-u79uwXL29TY76Z2rM5mHXA; +Cc: wsa-z923LK4zBo2bacvFa/9K2g
On 10/14/2014 02:53 PM, Jiri Prchal wrote:
> This patch adds driver for Cypress FRAMs on SPI bus, such as FM25V05, FM25V10
> etc.
> Reworked from at25 driver:
> - simplified writing since data are written without erasing and waiting to
> finish write cycle
> - add reading device ID and choose size and addr len from it
> - add serial number reading and exporting it to sysfs
>
(...)
> +static int fm25_probe(struct spi_device *spi)
> +{
> + struct fm25_data *fm25 = NULL;
> + struct spi_eeprom chip;
> + struct device_node *np = spi->dev.of_node;
> + int err;
> + char id[FM25_ID_LEN];
> +
> + /* Chip description */
> + if (!spi->dev.platform_data) {
> + if (np) {
> + err = fm25_np_to_chip(&spi->dev, np, &chip);
> + if (err)
> + return err;
> + } else {
> + dev_err(&spi->dev, "Error: no chip description\n");
> + return -ENODEV;
> + }
> + } else
> + chip = *(struct spi_eeprom *)spi->dev.platform_data;
> +
> + fm25 = devm_kzalloc(&spi->dev, sizeof(struct fm25_data), GFP_KERNEL);
> + if (!fm25)
> + return -ENOMEM;
sizeof(*fm25)..?
> +
> + mutex_init(&fm25->lock);
> + fm25->chip = chip;
> + fm25->spi = spi_dev_get(spi);
> + spi_set_drvdata(spi, fm25);
> +
> + /* Get ID of chip */
> + fm25_id_read(fm25, id);
> + if (id[6] != 0xc2) {
> + dev_err(&spi->dev, "Error: no Cypress FRAM (id %02x)\n", id[6]);
> + return -ENODEV;
> + }
> + /* set size found in ID */
> + switch (id[7]) {
> + case 0x21:
> + fm25->chip.byte_len = 16 * 1024;
> + break;
> + case 0x22:
> + fm25->chip.byte_len = 32 * 1024;
> + break;
> + case 0x23:
> + fm25->chip.byte_len = 64 * 1024;
> + break;
> + case 0x24:
> + fm25->chip.byte_len = 128 * 1024;
> + break;
> + case 0x25:
> + fm25->chip.byte_len = 256 * 1024;
> + break;
> + default:
> + dev_err(&spi->dev,
> + "Error: unsupported size (id %02x)\n", id[7]);
> + return -ENODEV;
> + break;
> + }
The preferred way of using switchhttp://lxr.free-electrons.com/source/Documentation/CodingStyle#L38
> +
> + if (fm25->chip.byte_len > 64 * 1024) {
> + fm25->addrlen = 3;
> + fm25->chip.flags |= EE_ADDR3;
> + }
> + else {
> + fm25->addrlen = 2;
> + fm25->chip.flags |= EE_ADDR2;
> + }
> +
> + if (id[8])
> + fm25->has_sernum = 1;
> + else
> + fm25->has_sernum = 0;
> +
> + /* Export the EEPROM bytes through sysfs, since that's convenient.
> + * And maybe to other kernel code; it might hold a board's Ethernet
> + * address, or board-specific calibration data generated on the
> + * manufacturing floor.
> + *
> + * Default to root-only access to the data; EEPROMs often hold data
> + * that's sensitive for read and/or write, like ethernet addresses,
> + * security codes, board-specific manufacturing calibrations, etc.
> + */
> + sysfs_bin_attr_init(&fm25->bin);
> + fm25->bin.attr.name = "fram";
> + fm25->bin.attr.mode = S_IRUGO;
> + fm25->bin.read = fm25_bin_read;
> + fm25->mem.read = fm25_mem_read;
> +
> + fm25->bin.size = fm25->chip.byte_len;
> + if (!(chip.flags & EE_READONLY)) {
> + fm25->bin.write = fm25_bin_write;
> + fm25->bin.attr.mode |= S_IWUSR | S_IWGRP;
> + fm25->mem.write = fm25_mem_write;
> + }
> +
> + err = sysfs_create_bin_file(&spi->dev.kobj, &fm25->bin);
> + if (err)
> + return err;
> +
> + /* Export the FM25 serial number */
> + if (fm25->has_sernum) {
> + err = device_create_file(&spi->dev, &dev_attr_sernum);
> + if (err)
> + return err;
> + }
> +
> + if (chip.setup)
> + chip.setup(&fm25->mem, chip.context);
> +
> + dev_info(&spi->dev, "%Zd %s %s fram%s\n",
> + (fm25->bin.size < 1024)
> + ? fm25->bin.size
> + : (fm25->bin.size / 1024),
> + (fm25->bin.size < 1024) ? "Byte" : "KByte",
> + fm25->chip.name,
> + (chip.flags & EE_READONLY) ? " (readonly)" : "");
> + return 0;
> +}
> +
> +static int fm25_remove(struct spi_device *spi)
> +{
> + struct fm25_data *fm25;
> +
> + fm25 = spi_get_drvdata(spi);
Both statements can be combine.
struct fm25_datd *fm25 = spi_get_drvdata(spi);
> + sysfs_remove_bin_file(&spi->dev.kobj, &fm25->bin);
> + if (fm25->has_sernum)
> + device_remove_file(&spi->dev, &dev_attr_sernum);
> + return 0;
> +}
> +
> +/*-------------------------------------------------------------------------*/
> +
> +static const struct of_device_id fm25_of_match[] = {
> + { .compatible = "cypress,fm25", },
> + { }
> +};
> +MODULE_DEVICE_TABLE(of, fm25_of_match);
> +
> +static struct spi_driver fm25_driver = {
> + .driver = {
> + .name = "fm25",
> + .owner = THIS_MODULE,
Can remove this filed. It will populate by module_spi_driver().
> + .of_match_table = fm25_of_match,
> + },
> + .probe = fm25_probe,
> + .remove = fm25_remove,
> +};
> +
> +module_spi_driver(fm25_driver);
> +
> +MODULE_DESCRIPTION("Driver for Cypress SPI FRAMs");
> +MODULE_AUTHOR("Jiri Prchal");
> +MODULE_LICENSE("GPL");
> +MODULE_ALIAS("spi:fram");
--
Regards,
Varka Bhadram.
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2014-10-14 9:42 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-10-14 9:23 [PATCH] misc: eeprom: add driver for Cypress FRAM Jiri Prchal
[not found] ` <8bfffe403f558ff93b50ae4088848c1c489c485b.1413278480.git.jiri.prchal-cKCO0sOKHLPtwjQa/ONI9g@public.gmane.org>
2014-10-14 9:42 ` Varka Bhadram
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).