13b51f47bSAndrey Smirnov // SPDX-License-Identifier: GPL-2.0+ 23b51f47bSAndrey Smirnov 33b51f47bSAndrey Smirnov /* 43b51f47bSAndrey Smirnov * EEPROM driver for RAVE SP 53b51f47bSAndrey Smirnov * 63b51f47bSAndrey Smirnov * Copyright (C) 2018 Zodiac Inflight Innovations 73b51f47bSAndrey Smirnov * 83b51f47bSAndrey Smirnov */ 93b51f47bSAndrey Smirnov #include <linux/kernel.h> 103b51f47bSAndrey Smirnov #include <linux/mfd/rave-sp.h> 113b51f47bSAndrey Smirnov #include <linux/module.h> 123b51f47bSAndrey Smirnov #include <linux/nvmem-provider.h> 133b51f47bSAndrey Smirnov #include <linux/of_device.h> 143b51f47bSAndrey Smirnov #include <linux/platform_device.h> 153b51f47bSAndrey Smirnov #include <linux/sizes.h> 163b51f47bSAndrey Smirnov 173b51f47bSAndrey Smirnov /** 183b51f47bSAndrey Smirnov * enum rave_sp_eeprom_access_type - Supported types of EEPROM access 193b51f47bSAndrey Smirnov * 203b51f47bSAndrey Smirnov * @RAVE_SP_EEPROM_WRITE: EEPROM write 213b51f47bSAndrey Smirnov * @RAVE_SP_EEPROM_READ: EEPROM read 223b51f47bSAndrey Smirnov */ 233b51f47bSAndrey Smirnov enum rave_sp_eeprom_access_type { 243b51f47bSAndrey Smirnov RAVE_SP_EEPROM_WRITE = 0, 253b51f47bSAndrey Smirnov RAVE_SP_EEPROM_READ = 1, 263b51f47bSAndrey Smirnov }; 273b51f47bSAndrey Smirnov 283b51f47bSAndrey Smirnov /** 293b51f47bSAndrey Smirnov * enum rave_sp_eeprom_header_size - EEPROM command header sizes 303b51f47bSAndrey Smirnov * 313b51f47bSAndrey Smirnov * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K) 323b51f47bSAndrey Smirnov * @RAVE_SP_EEPROM_HEADER_BIG: EEPROM header size for "big" devices (> 8K) 333b51f47bSAndrey Smirnov */ 343b51f47bSAndrey Smirnov enum rave_sp_eeprom_header_size { 353b51f47bSAndrey Smirnov RAVE_SP_EEPROM_HEADER_SMALL = 4U, 363b51f47bSAndrey Smirnov RAVE_SP_EEPROM_HEADER_BIG = 5U, 373b51f47bSAndrey Smirnov }; 38*26d79b82SKees Cook #define RAVE_SP_EEPROM_HEADER_MAX RAVE_SP_EEPROM_HEADER_BIG 393b51f47bSAndrey Smirnov 403b51f47bSAndrey Smirnov #define RAVE_SP_EEPROM_PAGE_SIZE 32U 413b51f47bSAndrey Smirnov 423b51f47bSAndrey Smirnov /** 433b51f47bSAndrey Smirnov * struct rave_sp_eeprom_page - RAVE SP EEPROM page 443b51f47bSAndrey Smirnov * 453b51f47bSAndrey Smirnov * @type: Access type (see enum rave_sp_eeprom_access_type) 463b51f47bSAndrey Smirnov * @success: Success flag (Success = 1, Failure = 0) 473b51f47bSAndrey Smirnov * @data: Read data 483b51f47bSAndrey Smirnov 493b51f47bSAndrey Smirnov * Note this structure corresponds to RSP_*_EEPROM payload from RAVE 503b51f47bSAndrey Smirnov * SP ICD 513b51f47bSAndrey Smirnov */ 523b51f47bSAndrey Smirnov struct rave_sp_eeprom_page { 533b51f47bSAndrey Smirnov u8 type; 543b51f47bSAndrey Smirnov u8 success; 553b51f47bSAndrey Smirnov u8 data[RAVE_SP_EEPROM_PAGE_SIZE]; 563b51f47bSAndrey Smirnov } __packed; 573b51f47bSAndrey Smirnov 583b51f47bSAndrey Smirnov /** 593b51f47bSAndrey Smirnov * struct rave_sp_eeprom - RAVE SP EEPROM device 603b51f47bSAndrey Smirnov * 613b51f47bSAndrey Smirnov * @sp: Pointer to parent RAVE SP device 623b51f47bSAndrey Smirnov * @mutex: Lock protecting access to EEPROM 633b51f47bSAndrey Smirnov * @address: EEPROM device address 643b51f47bSAndrey Smirnov * @header_size: Size of EEPROM command header for this device 653b51f47bSAndrey Smirnov * @dev: Pointer to corresponding struct device used for logging 663b51f47bSAndrey Smirnov */ 673b51f47bSAndrey Smirnov struct rave_sp_eeprom { 683b51f47bSAndrey Smirnov struct rave_sp *sp; 693b51f47bSAndrey Smirnov struct mutex mutex; 703b51f47bSAndrey Smirnov u8 address; 713b51f47bSAndrey Smirnov unsigned int header_size; 723b51f47bSAndrey Smirnov struct device *dev; 733b51f47bSAndrey Smirnov }; 743b51f47bSAndrey Smirnov 753b51f47bSAndrey Smirnov /** 763b51f47bSAndrey Smirnov * rave_sp_eeprom_io - Low-level part of EEPROM page access 773b51f47bSAndrey Smirnov * 783b51f47bSAndrey Smirnov * @eeprom: EEPROM device to write to 793b51f47bSAndrey Smirnov * @type: EEPROM access type (read or write) 803b51f47bSAndrey Smirnov * @idx: number of the EEPROM page 813b51f47bSAndrey Smirnov * @page: Data to write or buffer to store result (via page->data) 823b51f47bSAndrey Smirnov * 833b51f47bSAndrey Smirnov * This function does all of the low-level work required to perform a 843b51f47bSAndrey Smirnov * EEPROM access. This includes formatting correct command payload, 853b51f47bSAndrey Smirnov * sending it and checking received results. 863b51f47bSAndrey Smirnov * 873b51f47bSAndrey Smirnov * Returns zero in case of success or negative error code in 883b51f47bSAndrey Smirnov * case of failure. 893b51f47bSAndrey Smirnov */ 903b51f47bSAndrey Smirnov static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom, 913b51f47bSAndrey Smirnov enum rave_sp_eeprom_access_type type, 923b51f47bSAndrey Smirnov u16 idx, 933b51f47bSAndrey Smirnov struct rave_sp_eeprom_page *page) 943b51f47bSAndrey Smirnov { 953b51f47bSAndrey Smirnov const bool is_write = type == RAVE_SP_EEPROM_WRITE; 963b51f47bSAndrey Smirnov const unsigned int data_size = is_write ? sizeof(page->data) : 0; 973b51f47bSAndrey Smirnov const unsigned int cmd_size = eeprom->header_size + data_size; 983b51f47bSAndrey Smirnov const unsigned int rsp_size = 993b51f47bSAndrey Smirnov is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page); 1003b51f47bSAndrey Smirnov unsigned int offset = 0; 101*26d79b82SKees Cook u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)]; 1023b51f47bSAndrey Smirnov int ret; 1033b51f47bSAndrey Smirnov 104*26d79b82SKees Cook if (WARN_ON(cmd_size > sizeof(cmd))) 105*26d79b82SKees Cook return -EINVAL; 106*26d79b82SKees Cook 1073b51f47bSAndrey Smirnov cmd[offset++] = eeprom->address; 1083b51f47bSAndrey Smirnov cmd[offset++] = 0; 1093b51f47bSAndrey Smirnov cmd[offset++] = type; 1103b51f47bSAndrey Smirnov cmd[offset++] = idx; 1113b51f47bSAndrey Smirnov 1123b51f47bSAndrey Smirnov /* 1133b51f47bSAndrey Smirnov * If there's still room in this command's header it means we 1143b51f47bSAndrey Smirnov * are talkin to EEPROM that uses 16-bit page numbers and we 1153b51f47bSAndrey Smirnov * have to specify index's MSB in payload as well. 1163b51f47bSAndrey Smirnov */ 1173b51f47bSAndrey Smirnov if (offset < eeprom->header_size) 1183b51f47bSAndrey Smirnov cmd[offset++] = idx >> 8; 1193b51f47bSAndrey Smirnov /* 1203b51f47bSAndrey Smirnov * Copy our data to write to command buffer first. In case of 1213b51f47bSAndrey Smirnov * a read data_size should be zero and memcpy would become a 1223b51f47bSAndrey Smirnov * no-op 1233b51f47bSAndrey Smirnov */ 1243b51f47bSAndrey Smirnov memcpy(&cmd[offset], page->data, data_size); 1253b51f47bSAndrey Smirnov 1263b51f47bSAndrey Smirnov ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size); 1273b51f47bSAndrey Smirnov if (ret) 1283b51f47bSAndrey Smirnov return ret; 1293b51f47bSAndrey Smirnov 1303b51f47bSAndrey Smirnov if (page->type != type) 1313b51f47bSAndrey Smirnov return -EPROTO; 1323b51f47bSAndrey Smirnov 1333b51f47bSAndrey Smirnov if (!page->success) 1343b51f47bSAndrey Smirnov return -EIO; 1353b51f47bSAndrey Smirnov 1363b51f47bSAndrey Smirnov return 0; 1373b51f47bSAndrey Smirnov } 1383b51f47bSAndrey Smirnov 1393b51f47bSAndrey Smirnov /** 1403b51f47bSAndrey Smirnov * rave_sp_eeprom_page_access - Access single EEPROM page 1413b51f47bSAndrey Smirnov * 1423b51f47bSAndrey Smirnov * @eeprom: EEPROM device to access 1433b51f47bSAndrey Smirnov * @type: Access type to perform (read or write) 1443b51f47bSAndrey Smirnov * @offset: Offset within EEPROM to access 1453b51f47bSAndrey Smirnov * @data: Data buffer 1463b51f47bSAndrey Smirnov * @data_len: Size of the data buffer 1473b51f47bSAndrey Smirnov * 1483b51f47bSAndrey Smirnov * This function performs a generic access to a single page or a 1493b51f47bSAndrey Smirnov * portion thereof. Requested access MUST NOT cross the EEPROM page 1503b51f47bSAndrey Smirnov * boundary. 1513b51f47bSAndrey Smirnov * 1523b51f47bSAndrey Smirnov * Returns zero in case of success or negative error code in 1533b51f47bSAndrey Smirnov * case of failure. 1543b51f47bSAndrey Smirnov */ 1553b51f47bSAndrey Smirnov static int 1563b51f47bSAndrey Smirnov rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom, 1573b51f47bSAndrey Smirnov enum rave_sp_eeprom_access_type type, 1583b51f47bSAndrey Smirnov unsigned int offset, u8 *data, 1593b51f47bSAndrey Smirnov size_t data_len) 1603b51f47bSAndrey Smirnov { 1613b51f47bSAndrey Smirnov const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE; 1623b51f47bSAndrey Smirnov const unsigned int page_nr = offset / RAVE_SP_EEPROM_PAGE_SIZE; 1633b51f47bSAndrey Smirnov struct rave_sp_eeprom_page page; 1643b51f47bSAndrey Smirnov int ret; 1653b51f47bSAndrey Smirnov 1663b51f47bSAndrey Smirnov /* 1673b51f47bSAndrey Smirnov * This function will not work if data access we've been asked 1683b51f47bSAndrey Smirnov * to do is crossing EEPROM page boundary. Normally this 1693b51f47bSAndrey Smirnov * should never happen and getting here would indicate a bug 1703b51f47bSAndrey Smirnov * in the code. 1713b51f47bSAndrey Smirnov */ 1723b51f47bSAndrey Smirnov if (WARN_ON(data_len > sizeof(page.data) - page_offset)) 1733b51f47bSAndrey Smirnov return -EINVAL; 1743b51f47bSAndrey Smirnov 1753b51f47bSAndrey Smirnov if (type == RAVE_SP_EEPROM_WRITE) { 1763b51f47bSAndrey Smirnov /* 1773b51f47bSAndrey Smirnov * If doing a partial write we need to do a read first 1783b51f47bSAndrey Smirnov * to fill the rest of the page with correct data. 1793b51f47bSAndrey Smirnov */ 1803b51f47bSAndrey Smirnov if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) { 1813b51f47bSAndrey Smirnov ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ, 1823b51f47bSAndrey Smirnov page_nr, &page); 1833b51f47bSAndrey Smirnov if (ret) 1843b51f47bSAndrey Smirnov return ret; 1853b51f47bSAndrey Smirnov } 1863b51f47bSAndrey Smirnov 1873b51f47bSAndrey Smirnov memcpy(&page.data[page_offset], data, data_len); 1883b51f47bSAndrey Smirnov } 1893b51f47bSAndrey Smirnov 1903b51f47bSAndrey Smirnov ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page); 1913b51f47bSAndrey Smirnov if (ret) 1923b51f47bSAndrey Smirnov return ret; 1933b51f47bSAndrey Smirnov 1943b51f47bSAndrey Smirnov /* 1953b51f47bSAndrey Smirnov * Since we receive the result of the read via 'page.data' 1963b51f47bSAndrey Smirnov * buffer we need to copy that to 'data' 1973b51f47bSAndrey Smirnov */ 1983b51f47bSAndrey Smirnov if (type == RAVE_SP_EEPROM_READ) 1993b51f47bSAndrey Smirnov memcpy(data, &page.data[page_offset], data_len); 2003b51f47bSAndrey Smirnov 2013b51f47bSAndrey Smirnov return 0; 2023b51f47bSAndrey Smirnov } 2033b51f47bSAndrey Smirnov 2043b51f47bSAndrey Smirnov /** 2053b51f47bSAndrey Smirnov * rave_sp_eeprom_access - Access EEPROM data 2063b51f47bSAndrey Smirnov * 2073b51f47bSAndrey Smirnov * @eeprom: EEPROM device to access 2083b51f47bSAndrey Smirnov * @type: Access type to perform (read or write) 2093b51f47bSAndrey Smirnov * @offset: Offset within EEPROM to access 2103b51f47bSAndrey Smirnov * @data: Data buffer 2113b51f47bSAndrey Smirnov * @data_len: Size of the data buffer 2123b51f47bSAndrey Smirnov * 2133b51f47bSAndrey Smirnov * This function performs a generic access (either read or write) at 2143b51f47bSAndrey Smirnov * arbitrary offset (not necessary page aligned) of arbitrary length 2153b51f47bSAndrey Smirnov * (is not constrained by EEPROM page size). 2163b51f47bSAndrey Smirnov * 2173b51f47bSAndrey Smirnov * Returns zero in case of success or negative error code in case of 2183b51f47bSAndrey Smirnov * failure. 2193b51f47bSAndrey Smirnov */ 2203b51f47bSAndrey Smirnov static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom, 2213b51f47bSAndrey Smirnov enum rave_sp_eeprom_access_type type, 2223b51f47bSAndrey Smirnov unsigned int offset, u8 *data, 2233b51f47bSAndrey Smirnov unsigned int data_len) 2243b51f47bSAndrey Smirnov { 2253b51f47bSAndrey Smirnov unsigned int residue; 2263b51f47bSAndrey Smirnov unsigned int chunk; 2273b51f47bSAndrey Smirnov unsigned int head; 2283b51f47bSAndrey Smirnov int ret; 2293b51f47bSAndrey Smirnov 2303b51f47bSAndrey Smirnov mutex_lock(&eeprom->mutex); 2313b51f47bSAndrey Smirnov 2323b51f47bSAndrey Smirnov head = offset % RAVE_SP_EEPROM_PAGE_SIZE; 2333b51f47bSAndrey Smirnov residue = data_len; 2343b51f47bSAndrey Smirnov 2353b51f47bSAndrey Smirnov do { 2363b51f47bSAndrey Smirnov /* 2373b51f47bSAndrey Smirnov * First iteration, if we are doing an access that is 2383b51f47bSAndrey Smirnov * not 32-byte aligned, we need to access only data up 2393b51f47bSAndrey Smirnov * to a page boundary to avoid corssing it in 2403b51f47bSAndrey Smirnov * rave_sp_eeprom_page_access() 2413b51f47bSAndrey Smirnov */ 2423b51f47bSAndrey Smirnov if (unlikely(head)) { 2433b51f47bSAndrey Smirnov chunk = RAVE_SP_EEPROM_PAGE_SIZE - head; 2443b51f47bSAndrey Smirnov /* 2453b51f47bSAndrey Smirnov * This can only happen once per 2463b51f47bSAndrey Smirnov * rave_sp_eeprom_access() call, so we set 2473b51f47bSAndrey Smirnov * head to zero to process all the other 2483b51f47bSAndrey Smirnov * iterations normally. 2493b51f47bSAndrey Smirnov */ 2503b51f47bSAndrey Smirnov head = 0; 2513b51f47bSAndrey Smirnov } else { 2523b51f47bSAndrey Smirnov chunk = RAVE_SP_EEPROM_PAGE_SIZE; 2533b51f47bSAndrey Smirnov } 2543b51f47bSAndrey Smirnov 2553b51f47bSAndrey Smirnov /* 2563b51f47bSAndrey Smirnov * We should never read more that 'residue' bytes 2573b51f47bSAndrey Smirnov */ 2583b51f47bSAndrey Smirnov chunk = min(chunk, residue); 2593b51f47bSAndrey Smirnov ret = rave_sp_eeprom_page_access(eeprom, type, offset, 2603b51f47bSAndrey Smirnov data, chunk); 2613b51f47bSAndrey Smirnov if (ret) 2623b51f47bSAndrey Smirnov goto out; 2633b51f47bSAndrey Smirnov 2643b51f47bSAndrey Smirnov residue -= chunk; 2653b51f47bSAndrey Smirnov offset += chunk; 2663b51f47bSAndrey Smirnov data += chunk; 2673b51f47bSAndrey Smirnov } while (residue); 2683b51f47bSAndrey Smirnov out: 2693b51f47bSAndrey Smirnov mutex_unlock(&eeprom->mutex); 2703b51f47bSAndrey Smirnov return ret; 2713b51f47bSAndrey Smirnov } 2723b51f47bSAndrey Smirnov 2733b51f47bSAndrey Smirnov static int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset, 2743b51f47bSAndrey Smirnov void *val, size_t bytes) 2753b51f47bSAndrey Smirnov { 2763b51f47bSAndrey Smirnov return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ, 2773b51f47bSAndrey Smirnov offset, val, bytes); 2783b51f47bSAndrey Smirnov } 2793b51f47bSAndrey Smirnov 2803b51f47bSAndrey Smirnov static int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset, 2813b51f47bSAndrey Smirnov void *val, size_t bytes) 2823b51f47bSAndrey Smirnov { 2833b51f47bSAndrey Smirnov return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE, 2843b51f47bSAndrey Smirnov offset, val, bytes); 2853b51f47bSAndrey Smirnov } 2863b51f47bSAndrey Smirnov 2873b51f47bSAndrey Smirnov static int rave_sp_eeprom_probe(struct platform_device *pdev) 2883b51f47bSAndrey Smirnov { 2893b51f47bSAndrey Smirnov struct device *dev = &pdev->dev; 2903b51f47bSAndrey Smirnov struct rave_sp *sp = dev_get_drvdata(dev->parent); 2913b51f47bSAndrey Smirnov struct device_node *np = dev->of_node; 2923b51f47bSAndrey Smirnov struct nvmem_config config = { 0 }; 2933b51f47bSAndrey Smirnov struct rave_sp_eeprom *eeprom; 2943b51f47bSAndrey Smirnov struct nvmem_device *nvmem; 2953b51f47bSAndrey Smirnov u32 reg[2], size; 2963b51f47bSAndrey Smirnov 2973b51f47bSAndrey Smirnov if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) { 2983b51f47bSAndrey Smirnov dev_err(dev, "Failed to parse \"reg\" property\n"); 2993b51f47bSAndrey Smirnov return -EINVAL; 3003b51f47bSAndrey Smirnov } 3013b51f47bSAndrey Smirnov 3023b51f47bSAndrey Smirnov size = reg[1]; 3033b51f47bSAndrey Smirnov /* 3043b51f47bSAndrey Smirnov * Per ICD, we have no more than 2 bytes to specify EEPROM 3053b51f47bSAndrey Smirnov * page. 3063b51f47bSAndrey Smirnov */ 3073b51f47bSAndrey Smirnov if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) { 3083b51f47bSAndrey Smirnov dev_err(dev, "Specified size is too big\n"); 3093b51f47bSAndrey Smirnov return -EINVAL; 3103b51f47bSAndrey Smirnov } 3113b51f47bSAndrey Smirnov 3123b51f47bSAndrey Smirnov eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL); 3133b51f47bSAndrey Smirnov if (!eeprom) 3143b51f47bSAndrey Smirnov return -ENOMEM; 3153b51f47bSAndrey Smirnov 3163b51f47bSAndrey Smirnov eeprom->address = reg[0]; 3173b51f47bSAndrey Smirnov eeprom->sp = sp; 3183b51f47bSAndrey Smirnov eeprom->dev = dev; 3193b51f47bSAndrey Smirnov 3203b51f47bSAndrey Smirnov if (size > SZ_8K) 3213b51f47bSAndrey Smirnov eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG; 3223b51f47bSAndrey Smirnov else 3233b51f47bSAndrey Smirnov eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL; 3243b51f47bSAndrey Smirnov 3253b51f47bSAndrey Smirnov mutex_init(&eeprom->mutex); 3263b51f47bSAndrey Smirnov 3273b51f47bSAndrey Smirnov config.id = -1; 3283b51f47bSAndrey Smirnov of_property_read_string(np, "zii,eeprom-name", &config.name); 3293b51f47bSAndrey Smirnov config.priv = eeprom; 3303b51f47bSAndrey Smirnov config.dev = dev; 3313b51f47bSAndrey Smirnov config.size = size; 3323b51f47bSAndrey Smirnov config.reg_read = rave_sp_eeprom_reg_read; 3333b51f47bSAndrey Smirnov config.reg_write = rave_sp_eeprom_reg_write; 3343b51f47bSAndrey Smirnov config.word_size = 1; 3353b51f47bSAndrey Smirnov config.stride = 1; 3363b51f47bSAndrey Smirnov 3373b51f47bSAndrey Smirnov nvmem = devm_nvmem_register(dev, &config); 3383b51f47bSAndrey Smirnov 3393b51f47bSAndrey Smirnov return PTR_ERR_OR_ZERO(nvmem); 3403b51f47bSAndrey Smirnov } 3413b51f47bSAndrey Smirnov 3423b51f47bSAndrey Smirnov static const struct of_device_id rave_sp_eeprom_of_match[] = { 3433b51f47bSAndrey Smirnov { .compatible = "zii,rave-sp-eeprom" }, 3443b51f47bSAndrey Smirnov {} 3453b51f47bSAndrey Smirnov }; 3463b51f47bSAndrey Smirnov MODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match); 3473b51f47bSAndrey Smirnov 3483b51f47bSAndrey Smirnov static struct platform_driver rave_sp_eeprom_driver = { 3493b51f47bSAndrey Smirnov .probe = rave_sp_eeprom_probe, 3503b51f47bSAndrey Smirnov .driver = { 3513b51f47bSAndrey Smirnov .name = KBUILD_MODNAME, 3523b51f47bSAndrey Smirnov .of_match_table = rave_sp_eeprom_of_match, 3533b51f47bSAndrey Smirnov }, 3543b51f47bSAndrey Smirnov }; 3553b51f47bSAndrey Smirnov module_platform_driver(rave_sp_eeprom_driver); 3563b51f47bSAndrey Smirnov 3573b51f47bSAndrey Smirnov MODULE_LICENSE("GPL"); 3583b51f47bSAndrey Smirnov MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>"); 3593b51f47bSAndrey Smirnov MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>"); 3603b51f47bSAndrey Smirnov MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>"); 3613b51f47bSAndrey Smirnov MODULE_DESCRIPTION("RAVE SP EEPROM driver"); 362