Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 
0003 /*
0004  * EEPROM driver for RAVE SP
0005  *
0006  * Copyright (C) 2018 Zodiac Inflight Innovations
0007  *
0008  */
0009 #include <linux/kernel.h>
0010 #include <linux/mfd/rave-sp.h>
0011 #include <linux/module.h>
0012 #include <linux/nvmem-provider.h>
0013 #include <linux/of_device.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/sizes.h>
0016 
0017 /**
0018  * enum rave_sp_eeprom_access_type - Supported types of EEPROM access
0019  *
0020  * @RAVE_SP_EEPROM_WRITE:   EEPROM write
0021  * @RAVE_SP_EEPROM_READ:    EEPROM read
0022  */
0023 enum rave_sp_eeprom_access_type {
0024     RAVE_SP_EEPROM_WRITE = 0,
0025     RAVE_SP_EEPROM_READ  = 1,
0026 };
0027 
0028 /**
0029  * enum rave_sp_eeprom_header_size - EEPROM command header sizes
0030  *
0031  * @RAVE_SP_EEPROM_HEADER_SMALL: EEPROM header size for "small" devices (< 8K)
0032  * @RAVE_SP_EEPROM_HEADER_BIG:   EEPROM header size for "big" devices (> 8K)
0033  */
0034 enum rave_sp_eeprom_header_size {
0035     RAVE_SP_EEPROM_HEADER_SMALL = 4U,
0036     RAVE_SP_EEPROM_HEADER_BIG   = 5U,
0037 };
0038 #define RAVE_SP_EEPROM_HEADER_MAX   RAVE_SP_EEPROM_HEADER_BIG
0039 
0040 #define RAVE_SP_EEPROM_PAGE_SIZE    32U
0041 
0042 /**
0043  * struct rave_sp_eeprom_page - RAVE SP EEPROM page
0044  *
0045  * @type:   Access type (see enum rave_sp_eeprom_access_type)
0046  * @success:    Success flag (Success = 1, Failure = 0)
0047  * @data:   Read data
0048 
0049  * Note this structure corresponds to RSP_*_EEPROM payload from RAVE
0050  * SP ICD
0051  */
0052 struct rave_sp_eeprom_page {
0053     u8  type;
0054     u8  success;
0055     u8  data[RAVE_SP_EEPROM_PAGE_SIZE];
0056 } __packed;
0057 
0058 /**
0059  * struct rave_sp_eeprom - RAVE SP EEPROM device
0060  *
0061  * @sp:         Pointer to parent RAVE SP device
0062  * @mutex:      Lock protecting access to EEPROM
0063  * @address:        EEPROM device address
0064  * @header_size:    Size of EEPROM command header for this device
0065  * @dev:        Pointer to corresponding struct device used for logging
0066  */
0067 struct rave_sp_eeprom {
0068     struct rave_sp *sp;
0069     struct mutex mutex;
0070     u8 address;
0071     unsigned int header_size;
0072     struct device *dev;
0073 };
0074 
0075 /**
0076  * rave_sp_eeprom_io - Low-level part of EEPROM page access
0077  *
0078  * @eeprom: EEPROM device to write to
0079  * @type:   EEPROM access type (read or write)
0080  * @idx:    number of the EEPROM page
0081  * @page:   Data to write or buffer to store result (via page->data)
0082  *
0083  * This function does all of the low-level work required to perform a
0084  * EEPROM access. This includes formatting correct command payload,
0085  * sending it and checking received results.
0086  *
0087  * Returns zero in case of success or negative error code in
0088  * case of failure.
0089  */
0090 static int rave_sp_eeprom_io(struct rave_sp_eeprom *eeprom,
0091                  enum rave_sp_eeprom_access_type type,
0092                  u16 idx,
0093                  struct rave_sp_eeprom_page *page)
0094 {
0095     const bool is_write = type == RAVE_SP_EEPROM_WRITE;
0096     const unsigned int data_size = is_write ? sizeof(page->data) : 0;
0097     const unsigned int cmd_size = eeprom->header_size + data_size;
0098     const unsigned int rsp_size =
0099         is_write ? sizeof(*page) - sizeof(page->data) : sizeof(*page);
0100     unsigned int offset = 0;
0101     u8 cmd[RAVE_SP_EEPROM_HEADER_MAX + sizeof(page->data)];
0102     int ret;
0103 
0104     if (WARN_ON(cmd_size > sizeof(cmd)))
0105         return -EINVAL;
0106 
0107     cmd[offset++] = eeprom->address;
0108     cmd[offset++] = 0;
0109     cmd[offset++] = type;
0110     cmd[offset++] = idx;
0111 
0112     /*
0113      * If there's still room in this command's header it means we
0114      * are talkin to EEPROM that uses 16-bit page numbers and we
0115      * have to specify index's MSB in payload as well.
0116      */
0117     if (offset < eeprom->header_size)
0118         cmd[offset++] = idx >> 8;
0119     /*
0120      * Copy our data to write to command buffer first. In case of
0121      * a read data_size should be zero and memcpy would become a
0122      * no-op
0123      */
0124     memcpy(&cmd[offset], page->data, data_size);
0125 
0126     ret = rave_sp_exec(eeprom->sp, cmd, cmd_size, page, rsp_size);
0127     if (ret)
0128         return ret;
0129 
0130     if (page->type != type)
0131         return -EPROTO;
0132 
0133     if (!page->success)
0134         return -EIO;
0135 
0136     return 0;
0137 }
0138 
0139 /**
0140  * rave_sp_eeprom_page_access - Access single EEPROM page
0141  *
0142  * @eeprom: EEPROM device to access
0143  * @type:   Access type to perform (read or write)
0144  * @offset: Offset within EEPROM to access
0145  * @data:   Data buffer
0146  * @data_len:   Size of the data buffer
0147  *
0148  * This function performs a generic access to a single page or a
0149  * portion thereof. Requested access MUST NOT cross the EEPROM page
0150  * boundary.
0151  *
0152  * Returns zero in case of success or negative error code in
0153  * case of failure.
0154  */
0155 static int
0156 rave_sp_eeprom_page_access(struct rave_sp_eeprom *eeprom,
0157                enum rave_sp_eeprom_access_type type,
0158                unsigned int offset, u8 *data,
0159                size_t data_len)
0160 {
0161     const unsigned int page_offset = offset % RAVE_SP_EEPROM_PAGE_SIZE;
0162     const unsigned int page_nr     = offset / RAVE_SP_EEPROM_PAGE_SIZE;
0163     struct rave_sp_eeprom_page page;
0164     int ret;
0165 
0166     /*
0167      * This function will not work if data access we've been asked
0168      * to do is crossing EEPROM page boundary. Normally this
0169      * should never happen and getting here would indicate a bug
0170      * in the code.
0171      */
0172     if (WARN_ON(data_len > sizeof(page.data) - page_offset))
0173         return -EINVAL;
0174 
0175     if (type == RAVE_SP_EEPROM_WRITE) {
0176         /*
0177          * If doing a partial write we need to do a read first
0178          * to fill the rest of the page with correct data.
0179          */
0180         if (data_len < RAVE_SP_EEPROM_PAGE_SIZE) {
0181             ret = rave_sp_eeprom_io(eeprom, RAVE_SP_EEPROM_READ,
0182                         page_nr, &page);
0183             if (ret)
0184                 return ret;
0185         }
0186 
0187         memcpy(&page.data[page_offset], data, data_len);
0188     }
0189 
0190     ret = rave_sp_eeprom_io(eeprom, type, page_nr, &page);
0191     if (ret)
0192         return ret;
0193 
0194     /*
0195      * Since we receive the result of the read via 'page.data'
0196      * buffer we need to copy that to 'data'
0197      */
0198     if (type == RAVE_SP_EEPROM_READ)
0199         memcpy(data, &page.data[page_offset], data_len);
0200 
0201     return 0;
0202 }
0203 
0204 /**
0205  * rave_sp_eeprom_access - Access EEPROM data
0206  *
0207  * @eeprom: EEPROM device to access
0208  * @type:   Access type to perform (read or write)
0209  * @offset: Offset within EEPROM to access
0210  * @data:   Data buffer
0211  * @data_len:   Size of the data buffer
0212  *
0213  * This function performs a generic access (either read or write) at
0214  * arbitrary offset (not necessary page aligned) of arbitrary length
0215  * (is not constrained by EEPROM page size).
0216  *
0217  * Returns zero in case of success or negative error code in case of
0218  * failure.
0219  */
0220 static int rave_sp_eeprom_access(struct rave_sp_eeprom *eeprom,
0221                  enum rave_sp_eeprom_access_type type,
0222                  unsigned int offset, u8 *data,
0223                  unsigned int data_len)
0224 {
0225     unsigned int residue;
0226     unsigned int chunk;
0227     unsigned int head;
0228     int ret;
0229 
0230     mutex_lock(&eeprom->mutex);
0231 
0232     head    = offset % RAVE_SP_EEPROM_PAGE_SIZE;
0233     residue = data_len;
0234 
0235     do {
0236         /*
0237          * First iteration, if we are doing an access that is
0238          * not 32-byte aligned, we need to access only data up
0239          * to a page boundary to avoid corssing it in
0240          * rave_sp_eeprom_page_access()
0241          */
0242         if (unlikely(head)) {
0243             chunk = RAVE_SP_EEPROM_PAGE_SIZE - head;
0244             /*
0245              * This can only happen once per
0246              * rave_sp_eeprom_access() call, so we set
0247              * head to zero to process all the other
0248              * iterations normally.
0249              */
0250             head  = 0;
0251         } else {
0252             chunk = RAVE_SP_EEPROM_PAGE_SIZE;
0253         }
0254 
0255         /*
0256          * We should never read more that 'residue' bytes
0257          */
0258         chunk = min(chunk, residue);
0259         ret = rave_sp_eeprom_page_access(eeprom, type, offset,
0260                          data, chunk);
0261         if (ret)
0262             goto out;
0263 
0264         residue -= chunk;
0265         offset  += chunk;
0266         data    += chunk;
0267     } while (residue);
0268 out:
0269     mutex_unlock(&eeprom->mutex);
0270     return ret;
0271 }
0272 
0273 static int rave_sp_eeprom_reg_read(void *eeprom, unsigned int offset,
0274                    void *val, size_t bytes)
0275 {
0276     return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_READ,
0277                      offset, val, bytes);
0278 }
0279 
0280 static int rave_sp_eeprom_reg_write(void *eeprom, unsigned int offset,
0281                     void *val, size_t bytes)
0282 {
0283     return rave_sp_eeprom_access(eeprom, RAVE_SP_EEPROM_WRITE,
0284                      offset, val, bytes);
0285 }
0286 
0287 static int rave_sp_eeprom_probe(struct platform_device *pdev)
0288 {
0289     struct device *dev = &pdev->dev;
0290     struct rave_sp *sp = dev_get_drvdata(dev->parent);
0291     struct device_node *np = dev->of_node;
0292     struct nvmem_config config = { 0 };
0293     struct rave_sp_eeprom *eeprom;
0294     struct nvmem_device *nvmem;
0295     u32 reg[2], size;
0296 
0297     if (of_property_read_u32_array(np, "reg", reg, ARRAY_SIZE(reg))) {
0298         dev_err(dev, "Failed to parse \"reg\" property\n");
0299         return -EINVAL;
0300     }
0301 
0302     size = reg[1];
0303     /*
0304      * Per ICD, we have no more than 2 bytes to specify EEPROM
0305      * page.
0306      */
0307     if (size > U16_MAX * RAVE_SP_EEPROM_PAGE_SIZE) {
0308         dev_err(dev, "Specified size is too big\n");
0309         return -EINVAL;
0310     }
0311 
0312     eeprom = devm_kzalloc(dev, sizeof(*eeprom), GFP_KERNEL);
0313     if (!eeprom)
0314         return -ENOMEM;
0315 
0316     eeprom->address = reg[0];
0317     eeprom->sp      = sp;
0318     eeprom->dev     = dev;
0319 
0320     if (size > SZ_8K)
0321         eeprom->header_size = RAVE_SP_EEPROM_HEADER_BIG;
0322     else
0323         eeprom->header_size = RAVE_SP_EEPROM_HEADER_SMALL;
0324 
0325     mutex_init(&eeprom->mutex);
0326 
0327     config.id       = -1;
0328     of_property_read_string(np, "zii,eeprom-name", &config.name);
0329     config.priv     = eeprom;
0330     config.dev      = dev;
0331     config.size     = size;
0332     config.reg_read     = rave_sp_eeprom_reg_read;
0333     config.reg_write    = rave_sp_eeprom_reg_write;
0334     config.word_size    = 1;
0335     config.stride       = 1;
0336 
0337     nvmem = devm_nvmem_register(dev, &config);
0338 
0339     return PTR_ERR_OR_ZERO(nvmem);
0340 }
0341 
0342 static const struct of_device_id rave_sp_eeprom_of_match[] = {
0343     { .compatible = "zii,rave-sp-eeprom" },
0344     {}
0345 };
0346 MODULE_DEVICE_TABLE(of, rave_sp_eeprom_of_match);
0347 
0348 static struct platform_driver rave_sp_eeprom_driver = {
0349     .probe = rave_sp_eeprom_probe,
0350     .driver = {
0351         .name = KBUILD_MODNAME,
0352         .of_match_table = rave_sp_eeprom_of_match,
0353     },
0354 };
0355 module_platform_driver(rave_sp_eeprom_driver);
0356 
0357 MODULE_LICENSE("GPL");
0358 MODULE_AUTHOR("Andrey Vostrikov <andrey.vostrikov@cogentembedded.com>");
0359 MODULE_AUTHOR("Nikita Yushchenko <nikita.yoush@cogentembedded.com>");
0360 MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
0361 MODULE_DESCRIPTION("RAVE SP EEPROM driver");