linux/drivers/media/pci/solo6x10/solo6x10-eeprom.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Copyright (C) 2010-2013 Bluecherry, LLC <https://www.bluecherrydvr.com>
   4 *
   5 * Original author:
   6 * Ben Collins <bcollins@ubuntu.com>
   7 *
   8 * Additional work by:
   9 * John Brooks <john.brooks@bluecherry.net>
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/delay.h>
  14
  15#include "solo6x10.h"
  16
  17/* Control */
  18#define EE_SHIFT_CLK    0x04
  19#define EE_CS           0x08
  20#define EE_DATA_WRITE   0x02
  21#define EE_DATA_READ    0x01
  22#define EE_ENB          (0x80 | EE_CS)
  23
  24#define eeprom_delay()  udelay(100)
  25#if 0
  26#define eeprom_delay()  solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
  27#define eeprom_delay()  ({                              \
  28        int i, ret;                                     \
  29        udelay(100);                                    \
  30        for (i = ret = 0; i < 1000 && !ret; i++)        \
  31                ret = solo_eeprom_reg_read(solo_dev);   \
  32})
  33#endif
  34#define ADDR_LEN        6
  35
  36/* Commands */
  37#define EE_EWEN_CMD     4
  38#define EE_EWDS_CMD     4
  39#define EE_WRITE_CMD    5
  40#define EE_READ_CMD     6
  41#define EE_ERASE_CMD    7
  42
  43static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
  44{
  45        return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
  46}
  47
  48static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
  49{
  50        solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
  51        eeprom_delay();
  52}
  53
  54static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
  55{
  56        int i;
  57
  58        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
  59        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  60
  61        for (i = 4 + ADDR_LEN; i >= 0; i--) {
  62                int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
  63
  64                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
  65                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  66                                      EE_SHIFT_CLK | dataval);
  67        }
  68
  69        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  70}
  71
  72unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
  73{
  74        int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
  75        unsigned int retval = 0;
  76        int i;
  77
  78        solo_eeprom_cmd(solo_dev, ewen_cmd);
  79
  80        for (i = 0; i < 16; i++) {
  81                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  82                                      EE_SHIFT_CLK);
  83                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  84                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  85                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  86        }
  87
  88        solo_eeprom_reg_write(solo_dev, ~EE_CS);
  89        retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  90
  91        return retval;
  92}
  93
  94__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
  95{
  96        int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
  97        u16 retval = 0;
  98        int i;
  99
 100        solo_eeprom_cmd(solo_dev, read_cmd);
 101
 102        for (i = 0; i < 16; i++) {
 103                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
 104                                      EE_SHIFT_CLK);
 105                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
 106                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
 107        }
 108
 109        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 110
 111        return (__force __be16)retval;
 112}
 113
 114int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
 115                      __be16 data)
 116{
 117        int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
 118        unsigned int retval;
 119        int i;
 120
 121        solo_eeprom_cmd(solo_dev, write_cmd);
 122
 123        for (i = 15; i >= 0; i--) {
 124                unsigned int dataval = ((__force unsigned)data >> i) & 1;
 125
 126                solo_eeprom_reg_write(solo_dev, EE_ENB);
 127                solo_eeprom_reg_write(solo_dev,
 128                                      EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
 129        }
 130
 131        solo_eeprom_reg_write(solo_dev, EE_ENB);
 132        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 133        solo_eeprom_reg_write(solo_dev, EE_ENB);
 134
 135        for (i = retval = 0; i < 10000 && !retval; i++)
 136                retval = solo_eeprom_reg_read(solo_dev);
 137
 138        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 139
 140        return !retval;
 141}
 142