linux/drivers/media/pci/solo6x10/solo6x10-eeprom.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010-2013 Bluecherry, LLC <http://www.bluecherrydvr.com>
   3 *
   4 * Original author:
   5 * Ben Collins <bcollins@ubuntu.com>
   6 *
   7 * Additional work by:
   8 * John Brooks <john.brooks@bluecherry.net>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License as published by
  12 * the Free Software Foundation; either version 2 of the License, or
  13 * (at your option) any later version.
  14 *
  15 * This program is distributed in the hope that it will be useful,
  16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18 * GNU General Public License for more details.
  19 */
  20
  21#include <linux/kernel.h>
  22#include <linux/delay.h>
  23
  24#include "solo6x10.h"
  25
  26/* Control */
  27#define EE_SHIFT_CLK    0x04
  28#define EE_CS           0x08
  29#define EE_DATA_WRITE   0x02
  30#define EE_DATA_READ    0x01
  31#define EE_ENB          (0x80 | EE_CS)
  32
  33#define eeprom_delay()  udelay(100)
  34#if 0
  35#define eeprom_delay()  solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
  36#define eeprom_delay()  ({                              \
  37        int i, ret;                                     \
  38        udelay(100);                                    \
  39        for (i = ret = 0; i < 1000 && !ret; i++)        \
  40                ret = solo_eeprom_reg_read(solo_dev);   \
  41})
  42#endif
  43#define ADDR_LEN        6
  44
  45/* Commands */
  46#define EE_EWEN_CMD     4
  47#define EE_EWDS_CMD     4
  48#define EE_WRITE_CMD    5
  49#define EE_READ_CMD     6
  50#define EE_ERASE_CMD    7
  51
  52static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
  53{
  54        return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
  55}
  56
  57static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
  58{
  59        solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
  60        eeprom_delay();
  61}
  62
  63static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
  64{
  65        int i;
  66
  67        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
  68        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  69
  70        for (i = 4 + ADDR_LEN; i >= 0; i--) {
  71                int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
  72
  73                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
  74                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  75                                      EE_SHIFT_CLK | dataval);
  76        }
  77
  78        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  79}
  80
  81unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
  82{
  83        int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
  84        unsigned int retval = 0;
  85        int i;
  86
  87        solo_eeprom_cmd(solo_dev, ewen_cmd);
  88
  89        for (i = 0; i < 16; i++) {
  90                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  91                                      EE_SHIFT_CLK);
  92                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  93                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  94                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  95        }
  96
  97        solo_eeprom_reg_write(solo_dev, ~EE_CS);
  98        retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  99
 100        return retval;
 101}
 102
 103__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 104{
 105        int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
 106        u16 retval = 0;
 107        int i;
 108
 109        solo_eeprom_cmd(solo_dev, read_cmd);
 110
 111        for (i = 0; i < 16; i++) {
 112                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
 113                                      EE_SHIFT_CLK);
 114                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
 115                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
 116        }
 117
 118        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 119
 120        return (__force __be16)retval;
 121}
 122
 123int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
 124                      __be16 data)
 125{
 126        int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
 127        unsigned int retval;
 128        int i;
 129
 130        solo_eeprom_cmd(solo_dev, write_cmd);
 131
 132        for (i = 15; i >= 0; i--) {
 133                unsigned int dataval = ((__force unsigned)data >> i) & 1;
 134
 135                solo_eeprom_reg_write(solo_dev, EE_ENB);
 136                solo_eeprom_reg_write(solo_dev,
 137                                      EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
 138        }
 139
 140        solo_eeprom_reg_write(solo_dev, EE_ENB);
 141        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 142        solo_eeprom_reg_write(solo_dev, EE_ENB);
 143
 144        for (i = retval = 0; i < 10000 && !retval; i++)
 145                retval = solo_eeprom_reg_read(solo_dev);
 146
 147        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 148
 149        return !retval;
 150}
 151