18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci/*
48c2ecf20Sopenharmony_ci * EEPROM driver for RAVE SP
58c2ecf20Sopenharmony_ci *
68c2ecf20Sopenharmony_ci * Copyright (C) 2018 Zodiac Inflight Innovations
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/rave-sp.h>
118c2ecf20Sopenharmony_ci#include <linux/module.h>
128c2ecf20Sopenharmony_ci#include <linux/nvmem-provider.h>
138c2ecf20Sopenharmony_ci#include <linux/of_device.h>
148c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
158c2ecf20Sopenharmony_ci#include <linux/sizes.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci/**
188c2ecf20Sopenharmony_ci * enum rave_sp_eeprom_access_type - Supported types of EEPROM access
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * @RAVE_SP_EEPROM_WRITE:	EEPROM write
218c2ecf20Sopenharmony_ci * @RAVE_SP_EEPROM_READ:	EEPROM read
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_cienum rave_sp_eeprom_access_type {
248c2ecf20Sopenharmony_ci	RAVE_SP_EEPROM_WRITE = 0,
258c2ecf20Sopenharmony_ci	RAVE_SP_EEPROM_READ  = 1,
268c2ecf20Sopenharmony_ci};
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/**
298c2ecf20Sopenharmony_ci * enum rave_sp_eeprom_header_size - EEPROM command header sizes
308c2ecf20Sopenharmony_ci *
318c2ecf20Sopenharmony_ci * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K)
328c2ecf20Sopenharmony_ci * @RAVE_SP_EEPROM_HEADER_BIG:	 EEPROM header size for "big" devices (> 8K)
338c2ecf20Sopenharmony_ci */
348c2ecf20Sopenharmony_cienum rave_sp_eeprom_header_size {
358c2ecf20Sopenharmony_ci	RAVE_SP_EEPROM_HEADER_SMALL = 4U,
368c2ecf20Sopenharmony_ci	RAVE_SP_EEPROM_HEADER_BIG   = 5U,
378c2ecf20Sopenharmony_ci};
388c2ecf20Sopenharmony_ci#define RAVE_SP_EEPROM_HEADER_MAX	RAVE_SP_EEPROM_HEADER_BIG
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ci#define	RAVE_SP_EEPROM_PAGE_SIZE	32U
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci/**
438c2ecf20Sopenharmony_ci * struct rave_sp_eeprom_page - RAVE SP EEPROM page
448c2ecf20Sopenharmony_ci *
458c2ecf20Sopenharmony_ci * @type:	Access type (see enum rave_sp_eeprom_access_type)
468c2ecf20Sopenharmony_ci * @success:	Success flag (Success = 1, Failure = 0)
478c2ecf20Sopenharmony_ci * @data:	Read data
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci * Note this structure corresponds to RSP_*_EEPROM payload from RAVE
508c2ecf20Sopenharmony_ci * SP ICD
518c2ecf20Sopenharmony_ci */
528c2ecf20Sopenharmony_cistruct rave_sp_eeprom_page {
538c2ecf20Sopenharmony_ci	u8  type;
548c2ecf20Sopenharmony_ci	u8  success;
558c2ecf20Sopenharmony_ci	u8  data[RAVE_SP_EEPROM_PAGE_SIZE];
568c2ecf20Sopenharmony_ci} __packed;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci/**
598c2ecf20Sopenharmony_ci * struct rave_sp_eeprom - RAVE SP EEPROM device
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * @sp:			Pointer to parent RAVE SP device
628c2ecf20Sopenharmony_ci * @mutex:		Lock protecting access to EEPROM
638c2ecf20Sopenharmony_ci * @address:		EEPROM device address
648c2ecf20Sopenharmony_ci * @header_size:	Size of EEPROM command header for this device
658c2ecf20Sopenharmony_ci * @dev:		Pointer to corresponding struct device used for logging
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistruct rave_sp_eeprom {
688c2ecf20Sopenharmony_ci	struct rave_sp *sp;
698c2ecf20Sopenharmony_ci	struct mutex mutex;
708c2ecf20Sopenharmony_ci	u8 address;
718c2ecf20Sopenharmony_ci	unsigned int header_size;
728c2ecf20Sopenharmony_ci	struct device *dev;
738c2ecf20Sopenharmony_ci};
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci/**
768c2ecf20Sopenharmony_ci * rave_sp_eeprom_io - Low-level part of EEPROM page access
778c2ecf20Sopenharmony_ci *
788c2ecf20Sopenharmony_ci * @eeprom:	EEPROM device to write to
798c2ecf20Sopenharmony_ci * @type:	EEPROM access type (read or write)
808c2ecf20Sopenharmony_ci * @idx:	number of the EEPROM page
818c2ecf20Sopenharmony_ci * @page:	Data to write or buffer to store result (via page->data)
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * This function does all of the low-level work required to perform a
848c2ecf20Sopenharmony_ci * EEPROM access. This includes formatting correct command payload,
858c2ecf20Sopenharmony_ci * sending it and checking received results.
868c2ecf20Sopenharmony_ci *
878c2ecf20Sopenharmony_ci * Returns zero in case of success or negative error code in
888c2ecf20Sopenharmony_ci * case of failure.
898c2ecf20Sopenharmony_ci */
908c2ecf20Sopenharmony_cistatic int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom,
918c2ecf20Sopenharmony_ci			     enum rave_sp_eeprom_access_type type,
928c2ecf20Sopenharmony_ci			     u16 idx,
938c2ecf20Sopenharmony_ci			     struct rave_sp_eeprom_page *page)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	const bool is_write = type == RAVE_SP_EEPROM_WRITE;
968c2ecf20Sopenharmony_ci	const unsigned int data_size = is_write ? sizeof(page->data) : 0;
978c2ecf20Sopenharmony_ci	const unsigned int cmd_size = eeprom->header_size + data_size;
988c2ecf20Sopenharmony_ci	const unsigned int rsp_size =
998c2ecf20Sopenharmony_ci		is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page);
1008c2ecf20Sopenharmony_ci	unsigned int offset = 0;
1018c2ecf20Sopenharmony_ci	u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)];
1028c2ecf20Sopenharmony_ci	int ret;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (WARN_ON(cmd_size > sizeof(cmd)))
1058c2ecf20Sopenharmony_ci		return -EINVAL;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	cmd[offset++] = eeprom->address;
1088c2ecf20Sopenharmony_ci	cmd[offset++] = 0;
1098c2ecf20Sopenharmony_ci	cmd[offset++] = type;
1108c2ecf20Sopenharmony_ci	cmd[offset++] = idx;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/*
1138c2ecf20Sopenharmony_ci	 * If there's still room in this command's header it means we
1148c2ecf20Sopenharmony_ci	 * are talkin to EEPROM that uses 16-bit page numbers and we
1158c2ecf20Sopenharmony_ci	 * have to specify index's MSB in payload as well.
1168c2ecf20Sopenharmony_ci	 */
1178c2ecf20Sopenharmony_ci	if (offset < eeprom->header_size)
1188c2ecf20Sopenharmony_ci		cmd[offset++] = idx >> 8;
1198c2ecf20Sopenharmony_ci	/*
1208c2ecf20Sopenharmony_ci	 * Copy our data to write to command buffer first. In case of
1218c2ecf20Sopenharmony_ci	 * a read data_size should be zero and memcpy would become a
1228c2ecf20Sopenharmony_ci	 * no-op
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	memcpy(&cmd[offset], page->data, data_size);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size);
1278c2ecf20Sopenharmony_ci	if (ret)
1288c2ecf20Sopenharmony_ci		return ret;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (page->type != type)
1318c2ecf20Sopenharmony_ci		return -EPROTO;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	if (!page->success)
1348c2ecf20Sopenharmony_ci		return -EIO;
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci/**
1408c2ecf20Sopenharmony_ci * rave_sp_eeprom_page_access - Access single EEPROM page
1418c2ecf20Sopenharmony_ci *
1428c2ecf20Sopenharmony_ci * @eeprom:	EEPROM device to access
1438c2ecf20Sopenharmony_ci * @type:	Access type to perform (read or write)
1448c2ecf20Sopenharmony_ci * @offset:	Offset within EEPROM to access
1458c2ecf20Sopenharmony_ci * @data:	Data buffer
1468c2ecf20Sopenharmony_ci * @data_len:	Size of the data buffer
1478c2ecf20Sopenharmony_ci *
1488c2ecf20Sopenharmony_ci * This function performs a generic access to a single page or a
1498c2ecf20Sopenharmony_ci * portion thereof. Requested access MUST NOT cross the EEPROM page
1508c2ecf20Sopenharmony_ci * boundary.
1518c2ecf20Sopenharmony_ci *
1528c2ecf20Sopenharmony_ci * Returns zero in case of success or negative error code in
1538c2ecf20Sopenharmony_ci * case of failure.
1548c2ecf20Sopenharmony_ci */
1558c2ecf20Sopenharmony_cistatic int
1568c2ecf20Sopenharmony_cirave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom,
1578c2ecf20Sopenharmony_ci			   enum rave_sp_eeprom_access_type type,
1588c2ecf20Sopenharmony_ci			   unsigned int offset, u8 *data,
1598c2ecf20Sopenharmony_ci			   size_t data_len)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE;
1628c2ecf20Sopenharmony_ci	const unsigned int page_nr     = offset / RAVE_SP_EEPROM_PAGE_SIZE;
1638c2ecf20Sopenharmony_ci	struct rave_sp_eeprom_page page;
1648c2ecf20Sopenharmony_ci	int ret;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/*
1678c2ecf20Sopenharmony_ci	 * This function will not work if data access we've been asked
1688c2ecf20Sopenharmony_ci	 * to do is crossing EEPROM page boundary. Normally this
1698c2ecf20Sopenharmony_ci	 * should never happen and getting here would indicate a bug
1708c2ecf20Sopenharmony_ci	 * in the code.
1718c2ecf20Sopenharmony_ci	 */
1728c2ecf20Sopenharmony_ci	if (WARN_ON(data_len > sizeof(page.data) - page_offset))
1738c2ecf20Sopenharmony_ci		return -EINVAL;
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	if (type == RAVE_SP_EEPROM_WRITE) {
1768c2ecf20Sopenharmony_ci		/*
1778c2ecf20Sopenharmony_ci		 * If doing a partial write we need to do a read first
1788c2ecf20Sopenharmony_ci		 * to fill the rest of the page with correct data.
1798c2ecf20Sopenharmony_ci		 */
1808c2ecf20Sopenharmony_ci		if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) {
1818c2ecf20Sopenharmony_ci			ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ,
1828c2ecf20Sopenharmony_ci						page_nr, &page);
1838c2ecf20Sopenharmony_ci			if (ret)
1848c2ecf20Sopenharmony_ci				return ret;
1858c2ecf20Sopenharmony_ci		}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci		memcpy(&page.data[page_offset], data, data_len);
1888c2ecf20Sopenharmony_ci	}
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page);
1918c2ecf20Sopenharmony_ci	if (ret)
1928c2ecf20Sopenharmony_ci		return ret;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	/*
1958c2ecf20Sopenharmony_ci	 * Since we receive the result of the read via 'page.data'
1968c2ecf20Sopenharmony_ci	 * buffer we need to copy that to 'data'
1978c2ecf20Sopenharmony_ci	 */
1988c2ecf20Sopenharmony_ci	if (type == RAVE_SP_EEPROM_READ)
1998c2ecf20Sopenharmony_ci		memcpy(data, &page.data[page_offset], data_len);
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	return 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/**
2058c2ecf20Sopenharmony_ci * rave_sp_eeprom_access - Access EEPROM data
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci * @eeprom:	EEPROM device to access
2088c2ecf20Sopenharmony_ci * @type:	Access type to perform (read or write)
2098c2ecf20Sopenharmony_ci * @offset:	Offset within EEPROM to access
2108c2ecf20Sopenharmony_ci * @data:	Data buffer
2118c2ecf20Sopenharmony_ci * @data_len:	Size of the data buffer
2128c2ecf20Sopenharmony_ci *
2138c2ecf20Sopenharmony_ci * This function performs a generic access (either read or write) at
2148c2ecf20Sopenharmony_ci * arbitrary offset (not necessary page aligned) of arbitrary length
2158c2ecf20Sopenharmony_ci * (is not constrained by EEPROM page size).
2168c2ecf20Sopenharmony_ci *
2178c2ecf20Sopenharmony_ci * Returns zero in case of success or negative error code in case of
2188c2ecf20Sopenharmony_ci * failure.
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_cistatic int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom,
2218c2ecf20Sopenharmony_ci				 enum rave_sp_eeprom_access_type type,
2228c2ecf20Sopenharmony_ci				 unsigned int offset, u8 *data,
2238c2ecf20Sopenharmony_ci				 unsigned int data_len)
2248c2ecf20Sopenharmony_ci{
2258c2ecf20Sopenharmony_ci	unsigned int residue;
2268c2ecf20Sopenharmony_ci	unsigned int chunk;
2278c2ecf20Sopenharmony_ci	unsigned int head;
2288c2ecf20Sopenharmony_ci	int ret;
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	mutex_lock(&eeprom->mutex);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	head    = offset % RAVE_SP_EEPROM_PAGE_SIZE;
2338c2ecf20Sopenharmony_ci	residue = data_len;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	do {
2368c2ecf20Sopenharmony_ci		/*
2378c2ecf20Sopenharmony_ci		 * First iteration, if we are doing an access that is
2388c2ecf20Sopenharmony_ci		 * not 32-byte aligned, we need to access only data up
2398c2ecf20Sopenharmony_ci		 * to a page boundary to avoid corssing it in
2408c2ecf20Sopenharmony_ci		 * rave_sp_eeprom_page_access()
2418c2ecf20Sopenharmony_ci		 */
2428c2ecf20Sopenharmony_ci		if (unlikely(head)) {
2438c2ecf20Sopenharmony_ci			chunk = RAVE_SP_EEPROM_PAGE_SIZE - head;
2448c2ecf20Sopenharmony_ci			/*
2458c2ecf20Sopenharmony_ci			 * This can only happen once per
2468c2ecf20Sopenharmony_ci			 * rave_sp_eeprom_access() call, so we set
2478c2ecf20Sopenharmony_ci			 * head to zero to process all the other
2488c2ecf20Sopenharmony_ci			 * iterations normally.
2498c2ecf20Sopenharmony_ci			 */
2508c2ecf20Sopenharmony_ci			head  = 0;
2518c2ecf20Sopenharmony_ci		} else {
2528c2ecf20Sopenharmony_ci			chunk = RAVE_SP_EEPROM_PAGE_SIZE;
2538c2ecf20Sopenharmony_ci		}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci		/*
2568c2ecf20Sopenharmony_ci		 * We should never read more that 'residue' bytes
2578c2ecf20Sopenharmony_ci		 */
2588c2ecf20Sopenharmony_ci		chunk = min(chunk, residue);
2598c2ecf20Sopenharmony_ci		ret = rave_sp_eeprom_page_access(eeprom, type, offset,
2608c2ecf20Sopenharmony_ci						 data, chunk);
2618c2ecf20Sopenharmony_ci		if (ret)
2628c2ecf20Sopenharmony_ci			goto out;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci		residue -= chunk;
2658c2ecf20Sopenharmony_ci		offset  += chunk;
2668c2ecf20Sopenharmony_ci		data    += chunk;
2678c2ecf20Sopenharmony_ci	} while (residue);
2688c2ecf20Sopenharmony_ciout:
2698c2ecf20Sopenharmony_ci	mutex_unlock(&eeprom->mutex);
2708c2ecf20Sopenharmony_ci	return ret;
2718c2ecf20Sopenharmony_ci}
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset,
2748c2ecf20Sopenharmony_ci				   void *val, size_t bytes)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ,
2778c2ecf20Sopenharmony_ci				     offset, val, bytes);
2788c2ecf20Sopenharmony_ci}
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_cistatic int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset,
2818c2ecf20Sopenharmony_ci				    void *val, size_t bytes)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE,
2848c2ecf20Sopenharmony_ci				     offset, val, bytes);
2858c2ecf20Sopenharmony_ci}
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_cistatic int rave_sp_eeprom_probe(struct platform_device *pdev)
2888c2ecf20Sopenharmony_ci{
2898c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
2908c2ecf20Sopenharmony_ci	struct rave_sp *sp = dev_get_drvdata(dev->parent);
2918c2ecf20Sopenharmony_ci	struct device_node *np = dev->of_node;
2928c2ecf20Sopenharmony_ci	struct nvmem_config config = { 0 };
2938c2ecf20Sopenharmony_ci	struct rave_sp_eeprom *eeprom;
2948c2ecf20Sopenharmony_ci	struct nvmem_device *nvmem;
2958c2ecf20Sopenharmony_ci	u32 reg[2], size;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) {
2988c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to parse \"reg\" property\n");
2998c2ecf20Sopenharmony_ci		return -EINVAL;
3008c2ecf20Sopenharmony_ci	}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_ci	size = reg[1];
3038c2ecf20Sopenharmony_ci	/*
3048c2ecf20Sopenharmony_ci	 * Per ICD, we have no more than 2 bytes to specify EEPROM
3058c2ecf20Sopenharmony_ci	 * page.
3068c2ecf20Sopenharmony_ci	 */
3078c2ecf20Sopenharmony_ci	if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) {
3088c2ecf20Sopenharmony_ci		dev_err(dev, "Specified size is too big\n");
3098c2ecf20Sopenharmony_ci		return -EINVAL;
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
3138c2ecf20Sopenharmony_ci	if (!eeprom)
3148c2ecf20Sopenharmony_ci		return -ENOMEM;
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	eeprom->address = reg[0];
3178c2ecf20Sopenharmony_ci	eeprom->sp      = sp;
3188c2ecf20Sopenharmony_ci	eeprom->dev     = dev;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	if (size > SZ_8K)
3218c2ecf20Sopenharmony_ci		eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG;
3228c2ecf20Sopenharmony_ci	else
3238c2ecf20Sopenharmony_ci		eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci	mutex_init(&eeprom->mutex);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	config.id		= -1;
3288c2ecf20Sopenharmony_ci	of_property_read_string(np, "zii,eeprom-name", &config.name);
3298c2ecf20Sopenharmony_ci	config.priv		= eeprom;
3308c2ecf20Sopenharmony_ci	config.dev		= dev;
3318c2ecf20Sopenharmony_ci	config.size		= size;
3328c2ecf20Sopenharmony_ci	config.reg_read		= rave_sp_eeprom_reg_read;
3338c2ecf20Sopenharmony_ci	config.reg_write	= rave_sp_eeprom_reg_write;
3348c2ecf20Sopenharmony_ci	config.word_size	= 1;
3358c2ecf20Sopenharmony_ci	config.stride		= 1;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	nvmem = devm_nvmem_register(dev, &config);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(nvmem);
3408c2ecf20Sopenharmony_ci}
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic const struct of_device_id rave_sp_eeprom_of_match[] = {
3438c2ecf20Sopenharmony_ci	{ .compatible = "zii,rave-sp-eeprom" },
3448c2ecf20Sopenharmony_ci	{}
3458c2ecf20Sopenharmony_ci};
3468c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic struct platform_driver rave_sp_eeprom_driver = {
3498c2ecf20Sopenharmony_ci	.probe = rave_sp_eeprom_probe,
3508c2ecf20Sopenharmony_ci	.driver	= {
3518c2ecf20Sopenharmony_ci		.name = KBUILD_MODNAME,
3528c2ecf20Sopenharmony_ci		.of_match_table = rave_sp_eeprom_of_match,
3538c2ecf20Sopenharmony_ci	},
3548c2ecf20Sopenharmony_ci};
3558c2ecf20Sopenharmony_cimodule_platform_driver(rave_sp_eeprom_driver);
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
3588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
3598c2ecf20Sopenharmony_ciMODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
3608c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
3618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RAVE SP EEPROM driver");
362