162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Driver for 93xx46 EEPROMs
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * (C) 2011 DENX Software Engineering, Anatolij Gustschin <agust@denx.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <linux/device.h>
1062306a36Sopenharmony_ci#include <linux/gpio/consumer.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/log2.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/mutex.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/of_device.h>
1762306a36Sopenharmony_ci#include <linux/of_gpio.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/spi/spi.h>
2062306a36Sopenharmony_ci#include <linux/nvmem-provider.h>
2162306a36Sopenharmony_ci#include <linux/eeprom_93xx46.h>
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define OP_START	0x4
2462306a36Sopenharmony_ci#define OP_WRITE	(OP_START | 0x1)
2562306a36Sopenharmony_ci#define OP_READ		(OP_START | 0x2)
2662306a36Sopenharmony_ci#define ADDR_EWDS	0x00
2762306a36Sopenharmony_ci#define ADDR_ERAL	0x20
2862306a36Sopenharmony_ci#define ADDR_EWEN	0x30
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct eeprom_93xx46_devtype_data {
3162306a36Sopenharmony_ci	unsigned int quirks;
3262306a36Sopenharmony_ci	unsigned char flags;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const struct eeprom_93xx46_devtype_data at93c46_data = {
3662306a36Sopenharmony_ci	.flags = EE_SIZE1K,
3762306a36Sopenharmony_ci};
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic const struct eeprom_93xx46_devtype_data at93c56_data = {
4062306a36Sopenharmony_ci	.flags = EE_SIZE2K,
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cistatic const struct eeprom_93xx46_devtype_data at93c66_data = {
4462306a36Sopenharmony_ci	.flags = EE_SIZE4K,
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const struct eeprom_93xx46_devtype_data atmel_at93c46d_data = {
4862306a36Sopenharmony_ci	.flags = EE_SIZE1K,
4962306a36Sopenharmony_ci	.quirks = EEPROM_93XX46_QUIRK_SINGLE_WORD_READ |
5062306a36Sopenharmony_ci		  EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic const struct eeprom_93xx46_devtype_data microchip_93lc46b_data = {
5462306a36Sopenharmony_ci	.flags = EE_SIZE1K,
5562306a36Sopenharmony_ci	.quirks = EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE,
5662306a36Sopenharmony_ci};
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_cistruct eeprom_93xx46_dev {
5962306a36Sopenharmony_ci	struct spi_device *spi;
6062306a36Sopenharmony_ci	struct eeprom_93xx46_platform_data *pdata;
6162306a36Sopenharmony_ci	struct mutex lock;
6262306a36Sopenharmony_ci	struct nvmem_config nvmem_config;
6362306a36Sopenharmony_ci	struct nvmem_device *nvmem;
6462306a36Sopenharmony_ci	int addrlen;
6562306a36Sopenharmony_ci	int size;
6662306a36Sopenharmony_ci};
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic inline bool has_quirk_single_word_read(struct eeprom_93xx46_dev *edev)
6962306a36Sopenharmony_ci{
7062306a36Sopenharmony_ci	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_SINGLE_WORD_READ;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic inline bool has_quirk_instruction_length(struct eeprom_93xx46_dev *edev)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_INSTRUCTION_LENGTH;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic inline bool has_quirk_extra_read_cycle(struct eeprom_93xx46_dev *edev)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	return edev->pdata->quirks & EEPROM_93XX46_QUIRK_EXTRA_READ_CYCLE;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic int eeprom_93xx46_read(void *priv, unsigned int off,
8462306a36Sopenharmony_ci			      void *val, size_t count)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = priv;
8762306a36Sopenharmony_ci	char *buf = val;
8862306a36Sopenharmony_ci	int err = 0;
8962306a36Sopenharmony_ci	int bits;
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	if (unlikely(off >= edev->size))
9262306a36Sopenharmony_ci		return 0;
9362306a36Sopenharmony_ci	if ((off + count) > edev->size)
9462306a36Sopenharmony_ci		count = edev->size - off;
9562306a36Sopenharmony_ci	if (unlikely(!count))
9662306a36Sopenharmony_ci		return count;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	mutex_lock(&edev->lock);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (edev->pdata->prepare)
10162306a36Sopenharmony_ci		edev->pdata->prepare(edev);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	/* The opcode in front of the address is three bits. */
10462306a36Sopenharmony_ci	bits = edev->addrlen + 3;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	while (count) {
10762306a36Sopenharmony_ci		struct spi_message m;
10862306a36Sopenharmony_ci		struct spi_transfer t[2] = { { 0 } };
10962306a36Sopenharmony_ci		u16 cmd_addr = OP_READ << edev->addrlen;
11062306a36Sopenharmony_ci		size_t nbytes = count;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci		if (edev->pdata->flags & EE_ADDR8) {
11362306a36Sopenharmony_ci			cmd_addr |= off;
11462306a36Sopenharmony_ci			if (has_quirk_single_word_read(edev))
11562306a36Sopenharmony_ci				nbytes = 1;
11662306a36Sopenharmony_ci		} else {
11762306a36Sopenharmony_ci			cmd_addr |= (off >> 1);
11862306a36Sopenharmony_ci			if (has_quirk_single_word_read(edev))
11962306a36Sopenharmony_ci				nbytes = 2;
12062306a36Sopenharmony_ci		}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci		dev_dbg(&edev->spi->dev, "read cmd 0x%x, %d Hz\n",
12362306a36Sopenharmony_ci			cmd_addr, edev->spi->max_speed_hz);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		if (has_quirk_extra_read_cycle(edev)) {
12662306a36Sopenharmony_ci			cmd_addr <<= 1;
12762306a36Sopenharmony_ci			bits += 1;
12862306a36Sopenharmony_ci		}
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		spi_message_init(&m);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci		t[0].tx_buf = (char *)&cmd_addr;
13362306a36Sopenharmony_ci		t[0].len = 2;
13462306a36Sopenharmony_ci		t[0].bits_per_word = bits;
13562306a36Sopenharmony_ci		spi_message_add_tail(&t[0], &m);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		t[1].rx_buf = buf;
13862306a36Sopenharmony_ci		t[1].len = count;
13962306a36Sopenharmony_ci		t[1].bits_per_word = 8;
14062306a36Sopenharmony_ci		spi_message_add_tail(&t[1], &m);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci		err = spi_sync(edev->spi, &m);
14362306a36Sopenharmony_ci		/* have to wait at least Tcsl ns */
14462306a36Sopenharmony_ci		ndelay(250);
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci		if (err) {
14762306a36Sopenharmony_ci			dev_err(&edev->spi->dev, "read %zu bytes at %d: err. %d\n",
14862306a36Sopenharmony_ci				nbytes, (int)off, err);
14962306a36Sopenharmony_ci			break;
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci		buf += nbytes;
15362306a36Sopenharmony_ci		off += nbytes;
15462306a36Sopenharmony_ci		count -= nbytes;
15562306a36Sopenharmony_ci	}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (edev->pdata->finish)
15862306a36Sopenharmony_ci		edev->pdata->finish(edev);
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	mutex_unlock(&edev->lock);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return err;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_cistatic int eeprom_93xx46_ew(struct eeprom_93xx46_dev *edev, int is_on)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	struct spi_message m;
16862306a36Sopenharmony_ci	struct spi_transfer t;
16962306a36Sopenharmony_ci	int bits, ret;
17062306a36Sopenharmony_ci	u16 cmd_addr;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	/* The opcode in front of the address is three bits. */
17362306a36Sopenharmony_ci	bits = edev->addrlen + 3;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	cmd_addr = OP_START << edev->addrlen;
17662306a36Sopenharmony_ci	if (edev->pdata->flags & EE_ADDR8)
17762306a36Sopenharmony_ci		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS) << 1;
17862306a36Sopenharmony_ci	else
17962306a36Sopenharmony_ci		cmd_addr |= (is_on ? ADDR_EWEN : ADDR_EWDS);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	if (has_quirk_instruction_length(edev)) {
18262306a36Sopenharmony_ci		cmd_addr <<= 2;
18362306a36Sopenharmony_ci		bits += 2;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	dev_dbg(&edev->spi->dev, "ew%s cmd 0x%04x, %d bits\n",
18762306a36Sopenharmony_ci			is_on ? "en" : "ds", cmd_addr, bits);
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	spi_message_init(&m);
19062306a36Sopenharmony_ci	memset(&t, 0, sizeof(t));
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	t.tx_buf = &cmd_addr;
19362306a36Sopenharmony_ci	t.len = 2;
19462306a36Sopenharmony_ci	t.bits_per_word = bits;
19562306a36Sopenharmony_ci	spi_message_add_tail(&t, &m);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	mutex_lock(&edev->lock);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	if (edev->pdata->prepare)
20062306a36Sopenharmony_ci		edev->pdata->prepare(edev);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	ret = spi_sync(edev->spi, &m);
20362306a36Sopenharmony_ci	/* have to wait at least Tcsl ns */
20462306a36Sopenharmony_ci	ndelay(250);
20562306a36Sopenharmony_ci	if (ret)
20662306a36Sopenharmony_ci		dev_err(&edev->spi->dev, "erase/write %sable error %d\n",
20762306a36Sopenharmony_ci			is_on ? "en" : "dis", ret);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	if (edev->pdata->finish)
21062306a36Sopenharmony_ci		edev->pdata->finish(edev);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	mutex_unlock(&edev->lock);
21362306a36Sopenharmony_ci	return ret;
21462306a36Sopenharmony_ci}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_cistatic ssize_t
21762306a36Sopenharmony_cieeprom_93xx46_write_word(struct eeprom_93xx46_dev *edev,
21862306a36Sopenharmony_ci			 const char *buf, unsigned off)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct spi_message m;
22162306a36Sopenharmony_ci	struct spi_transfer t[2];
22262306a36Sopenharmony_ci	int bits, data_len, ret;
22362306a36Sopenharmony_ci	u16 cmd_addr;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	if (unlikely(off >= edev->size))
22662306a36Sopenharmony_ci		return -EINVAL;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	/* The opcode in front of the address is three bits. */
22962306a36Sopenharmony_ci	bits = edev->addrlen + 3;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	cmd_addr = OP_WRITE << edev->addrlen;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	if (edev->pdata->flags & EE_ADDR8) {
23462306a36Sopenharmony_ci		cmd_addr |= off;
23562306a36Sopenharmony_ci		data_len = 1;
23662306a36Sopenharmony_ci	} else {
23762306a36Sopenharmony_ci		cmd_addr |= (off >> 1);
23862306a36Sopenharmony_ci		data_len = 2;
23962306a36Sopenharmony_ci	}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	dev_dbg(&edev->spi->dev, "write cmd 0x%x\n", cmd_addr);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	spi_message_init(&m);
24462306a36Sopenharmony_ci	memset(t, 0, sizeof(t));
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	t[0].tx_buf = (char *)&cmd_addr;
24762306a36Sopenharmony_ci	t[0].len = 2;
24862306a36Sopenharmony_ci	t[0].bits_per_word = bits;
24962306a36Sopenharmony_ci	spi_message_add_tail(&t[0], &m);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	t[1].tx_buf = buf;
25262306a36Sopenharmony_ci	t[1].len = data_len;
25362306a36Sopenharmony_ci	t[1].bits_per_word = 8;
25462306a36Sopenharmony_ci	spi_message_add_tail(&t[1], &m);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	ret = spi_sync(edev->spi, &m);
25762306a36Sopenharmony_ci	/* have to wait program cycle time Twc ms */
25862306a36Sopenharmony_ci	mdelay(6);
25962306a36Sopenharmony_ci	return ret;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int eeprom_93xx46_write(void *priv, unsigned int off,
26362306a36Sopenharmony_ci				   void *val, size_t count)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = priv;
26662306a36Sopenharmony_ci	char *buf = val;
26762306a36Sopenharmony_ci	int i, ret, step = 1;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (unlikely(off >= edev->size))
27062306a36Sopenharmony_ci		return -EFBIG;
27162306a36Sopenharmony_ci	if ((off + count) > edev->size)
27262306a36Sopenharmony_ci		count = edev->size - off;
27362306a36Sopenharmony_ci	if (unlikely(!count))
27462306a36Sopenharmony_ci		return count;
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	/* only write even number of bytes on 16-bit devices */
27762306a36Sopenharmony_ci	if (edev->pdata->flags & EE_ADDR16) {
27862306a36Sopenharmony_ci		step = 2;
27962306a36Sopenharmony_ci		count &= ~1;
28062306a36Sopenharmony_ci	}
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* erase/write enable */
28362306a36Sopenharmony_ci	ret = eeprom_93xx46_ew(edev, 1);
28462306a36Sopenharmony_ci	if (ret)
28562306a36Sopenharmony_ci		return ret;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci	mutex_lock(&edev->lock);
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci	if (edev->pdata->prepare)
29062306a36Sopenharmony_ci		edev->pdata->prepare(edev);
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	for (i = 0; i < count; i += step) {
29362306a36Sopenharmony_ci		ret = eeprom_93xx46_write_word(edev, &buf[i], off + i);
29462306a36Sopenharmony_ci		if (ret) {
29562306a36Sopenharmony_ci			dev_err(&edev->spi->dev, "write failed at %d: %d\n",
29662306a36Sopenharmony_ci				(int)off + i, ret);
29762306a36Sopenharmony_ci			break;
29862306a36Sopenharmony_ci		}
29962306a36Sopenharmony_ci	}
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	if (edev->pdata->finish)
30262306a36Sopenharmony_ci		edev->pdata->finish(edev);
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	mutex_unlock(&edev->lock);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	/* erase/write disable */
30762306a36Sopenharmony_ci	eeprom_93xx46_ew(edev, 0);
30862306a36Sopenharmony_ci	return ret;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int eeprom_93xx46_eral(struct eeprom_93xx46_dev *edev)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	struct eeprom_93xx46_platform_data *pd = edev->pdata;
31462306a36Sopenharmony_ci	struct spi_message m;
31562306a36Sopenharmony_ci	struct spi_transfer t;
31662306a36Sopenharmony_ci	int bits, ret;
31762306a36Sopenharmony_ci	u16 cmd_addr;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* The opcode in front of the address is three bits. */
32062306a36Sopenharmony_ci	bits = edev->addrlen + 3;
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	cmd_addr = OP_START << edev->addrlen;
32362306a36Sopenharmony_ci	if (edev->pdata->flags & EE_ADDR8)
32462306a36Sopenharmony_ci		cmd_addr |= ADDR_ERAL << 1;
32562306a36Sopenharmony_ci	else
32662306a36Sopenharmony_ci		cmd_addr |= ADDR_ERAL;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	if (has_quirk_instruction_length(edev)) {
32962306a36Sopenharmony_ci		cmd_addr <<= 2;
33062306a36Sopenharmony_ci		bits += 2;
33162306a36Sopenharmony_ci	}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	dev_dbg(&edev->spi->dev, "eral cmd 0x%04x, %d bits\n", cmd_addr, bits);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	spi_message_init(&m);
33662306a36Sopenharmony_ci	memset(&t, 0, sizeof(t));
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	t.tx_buf = &cmd_addr;
33962306a36Sopenharmony_ci	t.len = 2;
34062306a36Sopenharmony_ci	t.bits_per_word = bits;
34162306a36Sopenharmony_ci	spi_message_add_tail(&t, &m);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	mutex_lock(&edev->lock);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (edev->pdata->prepare)
34662306a36Sopenharmony_ci		edev->pdata->prepare(edev);
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	ret = spi_sync(edev->spi, &m);
34962306a36Sopenharmony_ci	if (ret)
35062306a36Sopenharmony_ci		dev_err(&edev->spi->dev, "erase error %d\n", ret);
35162306a36Sopenharmony_ci	/* have to wait erase cycle time Tec ms */
35262306a36Sopenharmony_ci	mdelay(6);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	if (pd->finish)
35562306a36Sopenharmony_ci		pd->finish(edev);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	mutex_unlock(&edev->lock);
35862306a36Sopenharmony_ci	return ret;
35962306a36Sopenharmony_ci}
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_cistatic ssize_t eeprom_93xx46_store_erase(struct device *dev,
36262306a36Sopenharmony_ci					 struct device_attribute *attr,
36362306a36Sopenharmony_ci					 const char *buf, size_t count)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = dev_get_drvdata(dev);
36662306a36Sopenharmony_ci	int erase = 0, ret;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	sscanf(buf, "%d", &erase);
36962306a36Sopenharmony_ci	if (erase) {
37062306a36Sopenharmony_ci		ret = eeprom_93xx46_ew(edev, 1);
37162306a36Sopenharmony_ci		if (ret)
37262306a36Sopenharmony_ci			return ret;
37362306a36Sopenharmony_ci		ret = eeprom_93xx46_eral(edev);
37462306a36Sopenharmony_ci		if (ret)
37562306a36Sopenharmony_ci			return ret;
37662306a36Sopenharmony_ci		ret = eeprom_93xx46_ew(edev, 0);
37762306a36Sopenharmony_ci		if (ret)
37862306a36Sopenharmony_ci			return ret;
37962306a36Sopenharmony_ci	}
38062306a36Sopenharmony_ci	return count;
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_cistatic DEVICE_ATTR(erase, S_IWUSR, NULL, eeprom_93xx46_store_erase);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void select_assert(void *context)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = context;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	gpiod_set_value_cansleep(edev->pdata->select, 1);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic void select_deassert(void *context)
39262306a36Sopenharmony_ci{
39362306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = context;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	gpiod_set_value_cansleep(edev->pdata->select, 0);
39662306a36Sopenharmony_ci}
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cistatic const struct of_device_id eeprom_93xx46_of_table[] = {
39962306a36Sopenharmony_ci	{ .compatible = "eeprom-93xx46", .data = &at93c46_data, },
40062306a36Sopenharmony_ci	{ .compatible = "atmel,at93c46", .data = &at93c46_data, },
40162306a36Sopenharmony_ci	{ .compatible = "atmel,at93c46d", .data = &atmel_at93c46d_data, },
40262306a36Sopenharmony_ci	{ .compatible = "atmel,at93c56", .data = &at93c56_data, },
40362306a36Sopenharmony_ci	{ .compatible = "atmel,at93c66", .data = &at93c66_data, },
40462306a36Sopenharmony_ci	{ .compatible = "microchip,93lc46b", .data = &microchip_93lc46b_data, },
40562306a36Sopenharmony_ci	{}
40662306a36Sopenharmony_ci};
40762306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, eeprom_93xx46_of_table);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic const struct spi_device_id eeprom_93xx46_spi_ids[] = {
41062306a36Sopenharmony_ci	{ .name = "eeprom-93xx46",
41162306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&at93c46_data, },
41262306a36Sopenharmony_ci	{ .name = "at93c46",
41362306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&at93c46_data, },
41462306a36Sopenharmony_ci	{ .name = "at93c46d",
41562306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&atmel_at93c46d_data, },
41662306a36Sopenharmony_ci	{ .name = "at93c56",
41762306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&at93c56_data, },
41862306a36Sopenharmony_ci	{ .name = "at93c66",
41962306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&at93c66_data, },
42062306a36Sopenharmony_ci	{ .name = "93lc46b",
42162306a36Sopenharmony_ci	  .driver_data = (kernel_ulong_t)&microchip_93lc46b_data, },
42262306a36Sopenharmony_ci	{}
42362306a36Sopenharmony_ci};
42462306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, eeprom_93xx46_spi_ids);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_cistatic int eeprom_93xx46_probe_dt(struct spi_device *spi)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	const struct of_device_id *of_id =
42962306a36Sopenharmony_ci		of_match_device(eeprom_93xx46_of_table, &spi->dev);
43062306a36Sopenharmony_ci	struct device_node *np = spi->dev.of_node;
43162306a36Sopenharmony_ci	struct eeprom_93xx46_platform_data *pd;
43262306a36Sopenharmony_ci	u32 tmp;
43362306a36Sopenharmony_ci	int ret;
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	pd = devm_kzalloc(&spi->dev, sizeof(*pd), GFP_KERNEL);
43662306a36Sopenharmony_ci	if (!pd)
43762306a36Sopenharmony_ci		return -ENOMEM;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	ret = of_property_read_u32(np, "data-size", &tmp);
44062306a36Sopenharmony_ci	if (ret < 0) {
44162306a36Sopenharmony_ci		dev_err(&spi->dev, "data-size property not found\n");
44262306a36Sopenharmony_ci		return ret;
44362306a36Sopenharmony_ci	}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	if (tmp == 8) {
44662306a36Sopenharmony_ci		pd->flags |= EE_ADDR8;
44762306a36Sopenharmony_ci	} else if (tmp == 16) {
44862306a36Sopenharmony_ci		pd->flags |= EE_ADDR16;
44962306a36Sopenharmony_ci	} else {
45062306a36Sopenharmony_ci		dev_err(&spi->dev, "invalid data-size (%d)\n", tmp);
45162306a36Sopenharmony_ci		return -EINVAL;
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if (of_property_read_bool(np, "read-only"))
45562306a36Sopenharmony_ci		pd->flags |= EE_READONLY;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	pd->select = devm_gpiod_get_optional(&spi->dev, "select",
45862306a36Sopenharmony_ci					     GPIOD_OUT_LOW);
45962306a36Sopenharmony_ci	if (IS_ERR(pd->select))
46062306a36Sopenharmony_ci		return PTR_ERR(pd->select);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	pd->prepare = select_assert;
46362306a36Sopenharmony_ci	pd->finish = select_deassert;
46462306a36Sopenharmony_ci	gpiod_direction_output(pd->select, 0);
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ci	if (of_id->data) {
46762306a36Sopenharmony_ci		const struct eeprom_93xx46_devtype_data *data = of_id->data;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci		pd->quirks = data->quirks;
47062306a36Sopenharmony_ci		pd->flags |= data->flags;
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	spi->dev.platform_data = pd;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	return 0;
47662306a36Sopenharmony_ci}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int eeprom_93xx46_probe(struct spi_device *spi)
47962306a36Sopenharmony_ci{
48062306a36Sopenharmony_ci	struct eeprom_93xx46_platform_data *pd;
48162306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev;
48262306a36Sopenharmony_ci	int err;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci	if (spi->dev.of_node) {
48562306a36Sopenharmony_ci		err = eeprom_93xx46_probe_dt(spi);
48662306a36Sopenharmony_ci		if (err < 0)
48762306a36Sopenharmony_ci			return err;
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	pd = spi->dev.platform_data;
49162306a36Sopenharmony_ci	if (!pd) {
49262306a36Sopenharmony_ci		dev_err(&spi->dev, "missing platform data\n");
49362306a36Sopenharmony_ci		return -ENODEV;
49462306a36Sopenharmony_ci	}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci	edev = devm_kzalloc(&spi->dev, sizeof(*edev), GFP_KERNEL);
49762306a36Sopenharmony_ci	if (!edev)
49862306a36Sopenharmony_ci		return -ENOMEM;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	if (pd->flags & EE_SIZE1K)
50162306a36Sopenharmony_ci		edev->size = 128;
50262306a36Sopenharmony_ci	else if (pd->flags & EE_SIZE2K)
50362306a36Sopenharmony_ci		edev->size = 256;
50462306a36Sopenharmony_ci	else if (pd->flags & EE_SIZE4K)
50562306a36Sopenharmony_ci		edev->size = 512;
50662306a36Sopenharmony_ci	else {
50762306a36Sopenharmony_ci		dev_err(&spi->dev, "unspecified size\n");
50862306a36Sopenharmony_ci		return -EINVAL;
50962306a36Sopenharmony_ci	}
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	if (pd->flags & EE_ADDR8)
51262306a36Sopenharmony_ci		edev->addrlen = ilog2(edev->size);
51362306a36Sopenharmony_ci	else if (pd->flags & EE_ADDR16)
51462306a36Sopenharmony_ci		edev->addrlen = ilog2(edev->size) - 1;
51562306a36Sopenharmony_ci	else {
51662306a36Sopenharmony_ci		dev_err(&spi->dev, "unspecified address type\n");
51762306a36Sopenharmony_ci		return -EINVAL;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	mutex_init(&edev->lock);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	edev->spi = spi;
52362306a36Sopenharmony_ci	edev->pdata = pd;
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	edev->nvmem_config.type = NVMEM_TYPE_EEPROM;
52662306a36Sopenharmony_ci	edev->nvmem_config.name = dev_name(&spi->dev);
52762306a36Sopenharmony_ci	edev->nvmem_config.dev = &spi->dev;
52862306a36Sopenharmony_ci	edev->nvmem_config.read_only = pd->flags & EE_READONLY;
52962306a36Sopenharmony_ci	edev->nvmem_config.root_only = true;
53062306a36Sopenharmony_ci	edev->nvmem_config.owner = THIS_MODULE;
53162306a36Sopenharmony_ci	edev->nvmem_config.compat = true;
53262306a36Sopenharmony_ci	edev->nvmem_config.base_dev = &spi->dev;
53362306a36Sopenharmony_ci	edev->nvmem_config.reg_read = eeprom_93xx46_read;
53462306a36Sopenharmony_ci	edev->nvmem_config.reg_write = eeprom_93xx46_write;
53562306a36Sopenharmony_ci	edev->nvmem_config.priv = edev;
53662306a36Sopenharmony_ci	edev->nvmem_config.stride = 4;
53762306a36Sopenharmony_ci	edev->nvmem_config.word_size = 1;
53862306a36Sopenharmony_ci	edev->nvmem_config.size = edev->size;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	edev->nvmem = devm_nvmem_register(&spi->dev, &edev->nvmem_config);
54162306a36Sopenharmony_ci	if (IS_ERR(edev->nvmem))
54262306a36Sopenharmony_ci		return PTR_ERR(edev->nvmem);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	dev_info(&spi->dev, "%d-bit eeprom containing %d bytes %s\n",
54562306a36Sopenharmony_ci		(pd->flags & EE_ADDR8) ? 8 : 16,
54662306a36Sopenharmony_ci		edev->size,
54762306a36Sopenharmony_ci		(pd->flags & EE_READONLY) ? "(readonly)" : "");
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (!(pd->flags & EE_READONLY)) {
55062306a36Sopenharmony_ci		if (device_create_file(&spi->dev, &dev_attr_erase))
55162306a36Sopenharmony_ci			dev_err(&spi->dev, "can't create erase interface\n");
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ci	spi_set_drvdata(spi, edev);
55562306a36Sopenharmony_ci	return 0;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_cistatic void eeprom_93xx46_remove(struct spi_device *spi)
55962306a36Sopenharmony_ci{
56062306a36Sopenharmony_ci	struct eeprom_93xx46_dev *edev = spi_get_drvdata(spi);
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (!(edev->pdata->flags & EE_READONLY))
56362306a36Sopenharmony_ci		device_remove_file(&spi->dev, &dev_attr_erase);
56462306a36Sopenharmony_ci}
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_cistatic struct spi_driver eeprom_93xx46_driver = {
56762306a36Sopenharmony_ci	.driver = {
56862306a36Sopenharmony_ci		.name	= "93xx46",
56962306a36Sopenharmony_ci		.of_match_table = of_match_ptr(eeprom_93xx46_of_table),
57062306a36Sopenharmony_ci	},
57162306a36Sopenharmony_ci	.probe		= eeprom_93xx46_probe,
57262306a36Sopenharmony_ci	.remove		= eeprom_93xx46_remove,
57362306a36Sopenharmony_ci	.id_table	= eeprom_93xx46_spi_ids,
57462306a36Sopenharmony_ci};
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cimodule_spi_driver(eeprom_93xx46_driver);
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ciMODULE_LICENSE("GPL");
57962306a36Sopenharmony_ciMODULE_DESCRIPTION("Driver for 93xx46 EEPROMs");
58062306a36Sopenharmony_ciMODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
58162306a36Sopenharmony_ciMODULE_ALIAS("spi:93xx46");
58262306a36Sopenharmony_ciMODULE_ALIAS("spi:eeprom-93xx46");
58362306a36Sopenharmony_ciMODULE_ALIAS("spi:93lc46b");
584