linux/drivers/staging/media/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 * You should have received a copy of the GNU General Public License
  21 * along with this program; if not, write to the Free Software
  22 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  23 */
  24
  25#include <linux/kernel.h>
  26#include <linux/delay.h>
  27
  28#include "solo6x10.h"
  29
  30/* Control */
  31#define EE_SHIFT_CLK    0x04
  32#define EE_CS           0x08
  33#define EE_DATA_WRITE   0x02
  34#define EE_DATA_READ    0x01
  35#define EE_ENB          (0x80 | EE_CS)
  36
  37#define eeprom_delay()  udelay(100)
  38#if 0
  39#define eeprom_delay()  solo_reg_read(solo_dev, SOLO_EEPROM_CTRL)
  40#define eeprom_delay()  ({                              \
  41        int i, ret;                                     \
  42        udelay(100);                                    \
  43        for (i = ret = 0; i < 1000 && !ret; i++)        \
  44                ret = solo_eeprom_reg_read(solo_dev);   \
  45})
  46#endif
  47#define ADDR_LEN        6
  48
  49/* Commands */
  50#define EE_EWEN_CMD     4
  51#define EE_EWDS_CMD     4
  52#define EE_WRITE_CMD    5
  53#define EE_READ_CMD     6
  54#define EE_ERASE_CMD    7
  55
  56static unsigned int solo_eeprom_reg_read(struct solo_dev *solo_dev)
  57{
  58        return solo_reg_read(solo_dev, SOLO_EEPROM_CTRL) & EE_DATA_READ;
  59}
  60
  61static void solo_eeprom_reg_write(struct solo_dev *solo_dev, u32 data)
  62{
  63        solo_reg_write(solo_dev, SOLO_EEPROM_CTRL, data);
  64        eeprom_delay();
  65}
  66
  67static void solo_eeprom_cmd(struct solo_dev *solo_dev, int cmd)
  68{
  69        int i;
  70
  71        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ACCESS_EN);
  72        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  73
  74        for (i = 4 + ADDR_LEN; i >= 0; i--) {
  75                int dataval = (cmd & (1 << i)) ? EE_DATA_WRITE : 0;
  76
  77                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE | dataval);
  78                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  79                                      EE_SHIFT_CLK | dataval);
  80        }
  81
  82        solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  83}
  84
  85unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
  86{
  87        int ewen_cmd = (w_en ? 0x3f : 0) | (EE_EWEN_CMD << ADDR_LEN);
  88        unsigned int retval = 0;
  89        int i;
  90
  91        solo_eeprom_cmd(solo_dev, ewen_cmd);
  92
  93        for (i = 0; i < 16; i++) {
  94                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
  95                                      EE_SHIFT_CLK);
  96                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  97                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
  98                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
  99        }
 100
 101        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 102        retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
 103
 104        return retval;
 105}
 106
 107unsigned short solo_eeprom_read(struct solo_dev *solo_dev, int loc)
 108{
 109        int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
 110        unsigned short retval = 0;
 111        int i;
 112
 113        solo_eeprom_cmd(solo_dev, read_cmd);
 114
 115        for (i = 0; i < 16; i++) {
 116                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE |
 117                                      EE_SHIFT_CLK);
 118                retval = (retval << 1) | solo_eeprom_reg_read(solo_dev);
 119                solo_eeprom_reg_write(solo_dev, SOLO_EEPROM_ENABLE);
 120        }
 121
 122        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 123
 124        return retval;
 125}
 126
 127int solo_eeprom_write(struct solo_dev *solo_dev, int loc,
 128                      unsigned short data)
 129{
 130        int write_cmd = loc | (EE_WRITE_CMD << ADDR_LEN);
 131        unsigned int retval;
 132        int i;
 133
 134        solo_eeprom_cmd(solo_dev, write_cmd);
 135
 136        for (i = 15; i >= 0; i--) {
 137                unsigned int dataval = (data >> i) & 1;
 138
 139                solo_eeprom_reg_write(solo_dev, EE_ENB);
 140                solo_eeprom_reg_write(solo_dev,
 141                                      EE_ENB | (dataval << 1) | EE_SHIFT_CLK);
 142        }
 143
 144        solo_eeprom_reg_write(solo_dev, EE_ENB);
 145        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 146        solo_eeprom_reg_write(solo_dev, EE_ENB);
 147
 148        for (i = retval = 0; i < 10000 && !retval; i++)
 149                retval = solo_eeprom_reg_read(solo_dev);
 150
 151        solo_eeprom_reg_write(solo_dev, ~EE_CS);
 152
 153        return !retval;
 154}
 155