363 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3/*4 * EEPROM driver for RAVE SP5 *6 * Copyright (C) 2018 Zodiac Inflight Innovations7 *8 */9#include <linux/kernel.h>10#include <linux/mfd/rave-sp.h>11#include <linux/module.h>12#include <linux/nvmem-provider.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/sizes.h>16 17/**18 * enum rave_sp_eeprom_access_type - Supported types of EEPROM access19 *20 * @RAVE_SP_EEPROM_WRITE: EEPROM write21 * @RAVE_SP_EEPROM_READ: EEPROM read22 */23enum rave_sp_eeprom_access_type {24 RAVE_SP_EEPROM_WRITE = 0,25 RAVE_SP_EEPROM_READ = 1,26};27 28/**29 * enum rave_sp_eeprom_header_size - EEPROM command header sizes30 *31 * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K)32 * @RAVE_SP_EEPROM_HEADER_BIG: EEPROM header size for "big" devices (> 8K)33 */34enum rave_sp_eeprom_header_size {35 RAVE_SP_EEPROM_HEADER_SMALL = 4U,36 RAVE_SP_EEPROM_HEADER_BIG = 5U,37};38#define RAVE_SP_EEPROM_HEADER_MAX RAVE_SP_EEPROM_HEADER_BIG39 40#define RAVE_SP_EEPROM_PAGE_SIZE 32U41 42/**43 * struct rave_sp_eeprom_page - RAVE SP EEPROM page44 *45 * @type: Access type (see enum rave_sp_eeprom_access_type)46 * @success: Success flag (Success = 1, Failure = 0)47 * @data: Read data48 *49 * Note this structure corresponds to RSP_*_EEPROM payload from RAVE50 * SP ICD51 */52struct rave_sp_eeprom_page {53 u8 type;54 u8 success;55 u8 data[RAVE_SP_EEPROM_PAGE_SIZE];56} __packed;57 58/**59 * struct rave_sp_eeprom - RAVE SP EEPROM device60 *61 * @sp: Pointer to parent RAVE SP device62 * @mutex: Lock protecting access to EEPROM63 * @address: EEPROM device address64 * @header_size: Size of EEPROM command header for this device65 * @dev: Pointer to corresponding struct device used for logging66 */67struct rave_sp_eeprom {68 struct rave_sp *sp;69 struct mutex mutex;70 u8 address;71 unsigned int header_size;72 struct device *dev;73};74 75/**76 * rave_sp_eeprom_io - Low-level part of EEPROM page access77 *78 * @eeprom: EEPROM device to write to79 * @type: EEPROM access type (read or write)80 * @idx: number of the EEPROM page81 * @page: Data to write or buffer to store result (via page->data)82 *83 * This function does all of the low-level work required to perform a84 * EEPROM access. This includes formatting correct command payload,85 * sending it and checking received results.86 *87 * Returns zero in case of success or negative error code in88 * case of failure.89 */90static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom,91 enum rave_sp_eeprom_access_type type,92 u16 idx,93 struct rave_sp_eeprom_page *page)94{95 const bool is_write = type == RAVE_SP_EEPROM_WRITE;96 const unsigned int data_size = is_write ? sizeof(page->data) : 0;97 const unsigned int cmd_size = eeprom->header_size + data_size;98 const unsigned int rsp_size =99 is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page);100 unsigned int offset = 0;101 u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)];102 int ret;103 104 if (WARN_ON(cmd_size > sizeof(cmd)))105 return -EINVAL;106 107 cmd[offset++] = eeprom->address;108 cmd[offset++] = 0;109 cmd[offset++] = type;110 cmd[offset++] = idx;111 112 /*113 * If there's still room in this command's header it means we114 * are talkin to EEPROM that uses 16-bit page numbers and we115 * have to specify index's MSB in payload as well.116 */117 if (offset < eeprom->header_size)118 cmd[offset++] = idx >> 8;119 /*120 * Copy our data to write to command buffer first. In case of121 * a read data_size should be zero and memcpy would become a122 * no-op123 */124 memcpy(&cmd[offset], page->data, data_size);125 126 ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size);127 if (ret)128 return ret;129 130 if (page->type != type)131 return -EPROTO;132 133 if (!page->success)134 return -EIO;135 136 return 0;137}138 139/**140 * rave_sp_eeprom_page_access - Access single EEPROM page141 *142 * @eeprom: EEPROM device to access143 * @type: Access type to perform (read or write)144 * @offset: Offset within EEPROM to access145 * @data: Data buffer146 * @data_len: Size of the data buffer147 *148 * This function performs a generic access to a single page or a149 * portion thereof. Requested access MUST NOT cross the EEPROM page150 * boundary.151 *152 * Returns zero in case of success or negative error code in153 * case of failure.154 */155static int156rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom,157 enum rave_sp_eeprom_access_type type,158 unsigned int offset, u8 *data,159 size_t data_len)160{161 const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE;162 const unsigned int page_nr = offset / RAVE_SP_EEPROM_PAGE_SIZE;163 struct rave_sp_eeprom_page page;164 int ret;165 166 /*167 * This function will not work if data access we've been asked168 * to do is crossing EEPROM page boundary. Normally this169 * should never happen and getting here would indicate a bug170 * in the code.171 */172 if (WARN_ON(data_len > sizeof(page.data) - page_offset))173 return -EINVAL;174 175 if (type == RAVE_SP_EEPROM_WRITE) {176 /*177 * If doing a partial write we need to do a read first178 * to fill the rest of the page with correct data.179 */180 if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) {181 ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ,182 page_nr, &page);183 if (ret)184 return ret;185 }186 187 memcpy(&page.data[page_offset], data, data_len);188 }189 190 ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page);191 if (ret)192 return ret;193 194 /*195 * Since we receive the result of the read via 'page.data'196 * buffer we need to copy that to 'data'197 */198 if (type == RAVE_SP_EEPROM_READ)199 memcpy(data, &page.data[page_offset], data_len);200 201 return 0;202}203 204/**205 * rave_sp_eeprom_access - Access EEPROM data206 *207 * @eeprom: EEPROM device to access208 * @type: Access type to perform (read or write)209 * @offset: Offset within EEPROM to access210 * @data: Data buffer211 * @data_len: Size of the data buffer212 *213 * This function performs a generic access (either read or write) at214 * arbitrary offset (not necessary page aligned) of arbitrary length215 * (is not constrained by EEPROM page size).216 *217 * Returns zero in case of success or negative error code in case of218 * failure.219 */220static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom,221 enum rave_sp_eeprom_access_type type,222 unsigned int offset, u8 *data,223 unsigned int data_len)224{225 unsigned int residue;226 unsigned int chunk;227 unsigned int head;228 int ret;229 230 mutex_lock(&eeprom->mutex);231 232 head = offset % RAVE_SP_EEPROM_PAGE_SIZE;233 residue = data_len;234 235 do {236 /*237 * First iteration, if we are doing an access that is238 * not 32-byte aligned, we need to access only data up239 * to a page boundary to avoid corssing it in240 * rave_sp_eeprom_page_access()241 */242 if (unlikely(head)) {243 chunk = RAVE_SP_EEPROM_PAGE_SIZE - head;244 /*245 * This can only happen once per246 * rave_sp_eeprom_access() call, so we set247 * head to zero to process all the other248 * iterations normally.249 */250 head = 0;251 } else {252 chunk = RAVE_SP_EEPROM_PAGE_SIZE;253 }254 255 /*256 * We should never read more that 'residue' bytes257 */258 chunk = min(chunk, residue);259 ret = rave_sp_eeprom_page_access(eeprom, type, offset,260 data, chunk);261 if (ret)262 goto out;263 264 residue -= chunk;265 offset += chunk;266 data += chunk;267 } while (residue);268out:269 mutex_unlock(&eeprom->mutex);270 return ret;271}272 273static int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset,274 void *val, size_t bytes)275{276 return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ,277 offset, val, bytes);278}279 280static int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset,281 void *val, size_t bytes)282{283 return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE,284 offset, val, bytes);285}286 287static int rave_sp_eeprom_probe(struct platform_device *pdev)288{289 struct device *dev = &pdev->dev;290 struct rave_sp *sp = dev_get_drvdata(dev->parent);291 struct device_node *np = dev->of_node;292 struct nvmem_config config = { 0 };293 struct rave_sp_eeprom *eeprom;294 struct nvmem_device *nvmem;295 u32 reg[2], size;296 297 if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) {298 dev_err(dev, "Failed to parse \"reg\" property\n");299 return -EINVAL;300 }301 302 size = reg[1];303 /*304 * Per ICD, we have no more than 2 bytes to specify EEPROM305 * page.306 */307 if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) {308 dev_err(dev, "Specified size is too big\n");309 return -EINVAL;310 }311 312 eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);313 if (!eeprom)314 return -ENOMEM;315 316 eeprom->address = reg[0];317 eeprom->sp = sp;318 eeprom->dev = dev;319 320 if (size > SZ_8K)321 eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG;322 else323 eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL;324 325 mutex_init(&eeprom->mutex);326 327 config.id = -1;328 of_property_read_string(np, "zii,eeprom-name", &config.name);329 config.priv = eeprom;330 config.dev = dev;331 config.add_legacy_fixed_of_cells = true;332 config.size = size;333 config.reg_read = rave_sp_eeprom_reg_read;334 config.reg_write = rave_sp_eeprom_reg_write;335 config.word_size = 1;336 config.stride = 1;337 338 nvmem = devm_nvmem_register(dev, &config);339 340 return PTR_ERR_OR_ZERO(nvmem);341}342 343static const struct of_device_id rave_sp_eeprom_of_match[] = {344 { .compatible = "zii,rave-sp-eeprom" },345 {}346};347MODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match);348 349static struct platform_driver rave_sp_eeprom_driver = {350 .probe = rave_sp_eeprom_probe,351 .driver = {352 .name = KBUILD_MODNAME,353 .of_match_table = rave_sp_eeprom_of_match,354 },355};356module_platform_driver(rave_sp_eeprom_driver);357 358MODULE_LICENSE("GPL");359MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");360MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");361MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");362MODULE_DESCRIPTION("RAVE SP EEPROM driver");363