cregit-Linux how code gets into the kernel

Release 4.11 drivers/staging/sm750fb/ddk750_swi2c.c

/*
 *         Copyright (c) 2007 by Silicon Motion, Inc. (SMI)
 *
 *  All rights are reserved. Reproduction or in part is prohibited
 *  without the written consent of the copyright owner.
 *
 *  swi2c.c --- SM750/SM718 DDK
 *  This file contains the source code for I2C using software
 *  implementation.
 */

#include "ddk750_chip.h"
#include "ddk750_reg.h"
#include "ddk750_swi2c.h"
#include "ddk750_power.h"

/*
 * I2C Software Master Driver:
 * ===========================
 * Each i2c cycle is split into 4 sections. Each of these section marks
 * a point in time where the SCL or SDA may be changed.
 *
 * 1 Cycle == |  Section I. |  Section 2. |  Section 3. |  Section 4. |
 *            +-------------+-------------+-------------+-------------+
 *            | SCL set LOW |SCL no change| SCL set HIGH|SCL no change|
 *
 *                                          ____________ _____________
 * SCL == XXXX _____________ ____________ /
 *
 * I.e. the SCL may only be changed in section 1. and section 3. while
 * the SDA may only be changed in section 2. and section 4. The table
 * below gives the changes for these 2 lines in the varios sections.
 *
 * Section changes Table:
 * ======================
 * blank = no change, L = set bit LOW, H = set bit HIGH
 *
 *                                | 1.| 2.| 3.| 4.|
 *                 ---------------+---+---+---+---+
 *                 Tx Start   SDA |   | H |   | L |
 *                            SCL | L |   | H |   |
 *                 ---------------+---+---+---+---+
 *                 Tx Stop    SDA |   | L |   | H |
 *                            SCL | L |   | H |   |
 *                 ---------------+---+---+---+---+
 *                 Tx bit H   SDA |   | H |   |   |
 *                            SCL | L |   | H |   |
 *                 ---------------+---+---+---+---+
 *                 Tx bit L   SDA |   | L |   |   |
 *                            SCL | L |   | H |   |
 *                 ---------------+---+---+---+---+
 *
 */

/* GPIO pins used for this I2C. It ranges from 0 to 63. */

static unsigned char sw_i2c_clk_gpio = DEFAULT_I2C_SCL;

static unsigned char sw_i2c_data_gpio = DEFAULT_I2C_SDA;

/*
 *  Below is the variable declaration for the GPIO pin register usage
 *  for the i2c Clock and i2c Data.
 *
 *  Note:
 *      Notice that the GPIO usage for the i2c clock and i2c Data are
 *      separated. This is to make this code flexible enough when
 *      two separate GPIO pins for the clock and data are located
 *      in two different GPIO register set (worst case).
 */

/* i2c Clock GPIO Register usage */

static unsigned long sw_i2c_clk_gpio_mux_reg = GPIO_MUX;

static unsigned long sw_i2c_clk_gpio_data_reg = GPIO_DATA;

static unsigned long sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION;

/* i2c Data GPIO Register usage */

static unsigned long sw_i2c_data_gpio_mux_reg = GPIO_MUX;

static unsigned long sw_i2c_data_gpio_data_reg = GPIO_DATA;

static unsigned long sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION;

/*
 *  This function puts a delay between command
 */

static void sw_i2c_wait(void) { /* find a bug: * peekIO method works well before suspend/resume * but after suspend, peekIO(0x3ce,0x61) & 0x10 * always be non-zero,which makes the while loop * never finish. * use non-ultimate for loop below is safe */ /* Change wait algorithm to use PCI bus clock, * it's more reliable than counter loop .. * write 0x61 to 0x3ce and read from 0x3cf */ int i, tmp; for (i = 0; i < 600; i++) { tmp = i; tmp += i; } }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee3284.21%125.00%
Mike Rapoport410.53%250.00%
Elizabeth Ferdman25.26%125.00%
Total38100.00%4100.00%

/* * This function set/reset the SCL GPIO pin * * Parameters: * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) * * Notes: * When setting SCL to high, just set the GPIO as input where the pull up * resistor will pull the signal up. Do not use software to pull up the * signal because the i2c will fail when other device try to drive the * signal due to SM50x will drive the signal to always high. */
static void sw_i2c_scl(unsigned char value) { unsigned long gpio_data; unsigned long gpio_dir; gpio_dir = peek32(sw_i2c_clk_gpio_data_dir_reg); if (value) { /* High */ /* * Set direction as input. This will automatically * pull the signal up. */ gpio_dir &= ~(1 << sw_i2c_clk_gpio); poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir); } else { /* Low */ /* Set the signal down */ gpio_data = peek32(sw_i2c_clk_gpio_data_reg); gpio_data &= ~(1 << sw_i2c_clk_gpio); poke32(sw_i2c_clk_gpio_data_reg, gpio_data); /* Set direction as output */ gpio_dir |= (1 << sw_i2c_clk_gpio); poke32(sw_i2c_clk_gpio_data_dir_reg, gpio_dir); } }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee6569.89%112.50%
Mike Rapoport2122.58%562.50%
Matthieu Simon55.38%112.50%
Isaac Assegai22.15%112.50%
Total93100.00%8100.00%

/* * This function set/reset the SDA GPIO pin * * Parameters: * value - Bit value to set to the SCL or SDA (0 = low, 1 = high) * * Notes: * When setting SCL to high, just set the GPIO as input where the pull up * resistor will pull the signal up. Do not use software to pull up the * signal because the i2c will fail when other device try to drive the * signal due to SM50x will drive the signal to always high. */
static void sw_i2c_sda(unsigned char value) { unsigned long gpio_data; unsigned long gpio_dir; gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg); if (value) { /* High */ /* * Set direction as input. This will automatically * pull the signal up. */ gpio_dir &= ~(1 << sw_i2c_data_gpio); poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir); } else { /* Low */ /* Set the signal down */ gpio_data = peek32(sw_i2c_data_gpio_data_reg); gpio_data &= ~(1 << sw_i2c_data_gpio); poke32(sw_i2c_data_gpio_data_reg, gpio_data); /* Set direction as output */ gpio_dir |= (1 << sw_i2c_data_gpio); poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir); } }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee6569.89%112.50%
Mike Rapoport2122.58%562.50%
Matthieu Simon55.38%112.50%
Isaac Assegai22.15%112.50%
Total93100.00%8100.00%

/* * This function read the data from the SDA GPIO pin * * Return Value: * The SDA data bit sent by the Slave */
static unsigned char sw_i2c_read_sda(void) { unsigned long gpio_dir; unsigned long gpio_data; unsigned long dir_mask = 1 << sw_i2c_data_gpio; /* Make sure that the direction is input (High) */ gpio_dir = peek32(sw_i2c_data_gpio_data_dir_reg); if ((gpio_dir & dir_mask) != ~dir_mask) { gpio_dir &= ~(1 << sw_i2c_data_gpio); poke32(sw_i2c_data_gpio_data_dir_reg, gpio_dir); } /* Now read the SDA line */ gpio_data = peek32(sw_i2c_data_gpio_data_reg); if (gpio_data & (1 << sw_i2c_data_gpio)) return 1; else return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee6068.97%116.67%
Mike Rapoport2427.59%466.67%
Matthieu Simon33.45%116.67%
Total87100.00%6100.00%

/* * This function sends ACK signal */
static void sw_i2c_ack(void) { return; /* Single byte read is ok without it. */ }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee990.00%150.00%
Mike Rapoport110.00%150.00%
Total10100.00%2100.00%

/* * This function sends the start command to the slave device */
static void sw_i2c_start(void) { /* Start I2C */ sw_i2c_sda(1); sw_i2c_scl(1); sw_i2c_sda(0); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee1979.17%133.33%
Mike Rapoport416.67%133.33%
Ricardo Ribalda Delgado14.17%133.33%
Total24100.00%3100.00%

/* * This function sends the stop command to the slave device */
static void sw_i2c_stop(void) { /* Stop the I2C */ sw_i2c_scl(1); sw_i2c_sda(0); sw_i2c_sda(1); }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee1979.17%133.33%
Mike Rapoport416.67%133.33%
Ricardo Ribalda Delgado14.17%133.33%
Total24100.00%3100.00%

/* * This function writes one byte to the slave device * * Parameters: * data - Data to be write to the slave device * * Return Value: * 0 - Success * -1 - Fail to write byte */
static long sw_i2c_write_byte(unsigned char data) { unsigned char value = data; int i; /* Sending the data bit by bit */ for (i = 0; i < 8; i++) { /* Set SCL to low */ sw_i2c_scl(0); /* Send data bit */ if ((value & 0x80) != 0) sw_i2c_sda(1); else sw_i2c_sda(0); sw_i2c_wait(); /* Toggle clk line to one */ sw_i2c_scl(1); sw_i2c_wait(); /* Shift byte to be sent */ value = value << 1; } /* Set the SCL Low and SDA High (prepare to get input) */ sw_i2c_scl(0); sw_i2c_sda(1); /* Set the SCL High for ack */ sw_i2c_wait(); sw_i2c_scl(1); sw_i2c_wait(); /* Read SDA, until SDA==0 */ for (i = 0; i < 0xff; i++) { if (!sw_i2c_read_sda()) break; sw_i2c_scl(0); sw_i2c_wait(); sw_i2c_scl(1); sw_i2c_wait(); } /* Set the SCL Low and SDA High */ sw_i2c_scl(0); sw_i2c_sda(1); if (i < 0xff) return 0; else return -1; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee14988.17%133.33%
Mike Rapoport1911.24%133.33%
Ricardo Ribalda Delgado10.59%133.33%
Total169100.00%3100.00%

/* * This function reads one byte from the slave device * * Parameters: * ack - Flag to indicate either to send the acknowledge * message to the slave device or not * * Return Value: * One byte data read from the Slave device */
static unsigned char sw_i2c_read_byte(unsigned char ack) { int i; unsigned char data = 0; for (i = 7; i >= 0; i--) { /* Set the SCL to Low and SDA to High (Input) */ sw_i2c_scl(0); sw_i2c_sda(1); sw_i2c_wait(); /* Set the SCL High */ sw_i2c_scl(1); sw_i2c_wait(); /* Read data bits from SDA */ data |= (sw_i2c_read_sda() << i); } if (ack) sw_i2c_ack(); /* Set the SCL Low and SDA High */ sw_i2c_scl(0); sw_i2c_sda(1); return data; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee7887.64%133.33%
Mike Rapoport1011.24%133.33%
Ricardo Ribalda Delgado11.12%133.33%
Total89100.00%3100.00%

/* * This function initializes GPIO port for SW I2C communication. * * Parameters: * clk_gpio - The GPIO pin to be used as i2c SCL * data_gpio - The GPIO pin to be used as i2c SDA * * Return Value: * -1 - Fail to initialize the i2c * 0 - Success */
static long sm750le_i2c_init(unsigned char clk_gpio, unsigned char data_gpio) { int i; /* Initialize the GPIO pin for the i2c Clock Register */ sw_i2c_clk_gpio_data_reg = GPIO_DATA_SM750LE; sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE; /* Initialize the Clock GPIO Offset */ sw_i2c_clk_gpio = clk_gpio; /* Initialize the GPIO pin for the i2c Data Register */ sw_i2c_data_gpio_data_reg = GPIO_DATA_SM750LE; sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION_SM750LE; /* Initialize the Data GPIO Offset */ sw_i2c_data_gpio = data_gpio; /* Note that SM750LE don't have GPIO MUX and power is always on */ /* Clear the i2c lines. */ for (i = 0; i < 9; i++) sw_i2c_stop(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee5380.30%120.00%
Mike Rapoport1218.18%360.00%
Ricardo Ribalda Delgado11.52%120.00%
Total66100.00%5100.00%

/* * This function initializes the i2c attributes and bus * * Parameters: * clk_gpio - The GPIO pin to be used as i2c SCL * data_gpio - The GPIO pin to be used as i2c SDA * * Return Value: * -1 - Fail to initialize the i2c * 0 - Success */
long sm750_sw_i2c_init( unsigned char clk_gpio, unsigned char data_gpio ) { int i; /* * Return 0 if the GPIO pins to be used is out of range. The * range is only from [0..63] */ if ((clk_gpio > 31) || (data_gpio > 31)) return -1; if (sm750_get_chip_type() == SM750LE) return sm750le_i2c_init(clk_gpio, data_gpio); /* Initialize the GPIO pin for the i2c Clock Register */ sw_i2c_clk_gpio_mux_reg = GPIO_MUX; sw_i2c_clk_gpio_data_reg = GPIO_DATA; sw_i2c_clk_gpio_data_dir_reg = GPIO_DATA_DIRECTION; /* Initialize the Clock GPIO Offset */ sw_i2c_clk_gpio = clk_gpio; /* Initialize the GPIO pin for the i2c Data Register */ sw_i2c_data_gpio_mux_reg = GPIO_MUX; sw_i2c_data_gpio_data_reg = GPIO_DATA; sw_i2c_data_gpio_data_dir_reg = GPIO_DATA_DIRECTION; /* Initialize the Data GPIO Offset */ sw_i2c_data_gpio = data_gpio; /* Enable the GPIO pins for the i2c Clock and Data (GPIO MUX) */ poke32(sw_i2c_clk_gpio_mux_reg, peek32(sw_i2c_clk_gpio_mux_reg) & ~(1 << sw_i2c_clk_gpio)); poke32(sw_i2c_data_gpio_mux_reg, peek32(sw_i2c_data_gpio_mux_reg) & ~(1 << sw_i2c_data_gpio)); /* Enable GPIO power */ sm750_enable_gpio(1); /* Clear the i2c lines. */ for (i = 0; i < 9; i++) sw_i2c_stop(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee11578.23%111.11%
Mike Rapoport2617.69%555.56%
Matthieu Simon42.72%111.11%
Moshe Green10.68%111.11%
Arnd Bergmann10.68%111.11%
Total147100.00%9100.00%

/* * This function reads the slave device's register * * Parameters: * addr - i2c Slave device address which register * to be read from * reg - Slave device's register to be read * * Return Value: * Register value */
unsigned char sm750_sw_i2c_read_reg( unsigned char addr, unsigned char reg ) { unsigned char data; /* Send the Start signal */ sw_i2c_start(); /* Send the device address */ sw_i2c_write_byte(addr); /* Send the register index */ sw_i2c_write_byte(reg); /* Get the bus again and get the data from the device read address */ sw_i2c_start(); sw_i2c_write_byte(addr + 1); data = sw_i2c_read_byte(1); /* Stop swI2C and release the bus */ sw_i2c_stop(); return data; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee4677.97%125.00%
Mike Rapoport1322.03%375.00%
Total59100.00%4100.00%

/* * This function writes a value to the slave device's register * * Parameters: * addr - i2c Slave device address which register * to be written * reg - Slave device's register to be written * data - Data to be written to the register * * Result: * 0 - Success * -1 - Fail */
long sm750_sw_i2c_write_reg( unsigned char addr, unsigned char reg, unsigned char data ) { long ret = 0; /* Send the Start signal */ sw_i2c_start(); /* Send the device address and read the data. All should return success * in order for the writing processed to be successful */ if ((sw_i2c_write_byte(addr) != 0) || (sw_i2c_write_byte(reg) != 0) || (sw_i2c_write_byte(data) != 0)) { ret = -1; } /* Stop i2c and release the bus */ sw_i2c_stop(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee5680.00%120.00%
Mike Rapoport1318.57%360.00%
Elizabeth Ferdman11.43%120.00%
Total70100.00%5100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Sudip Mukherjee83879.36%15.88%
Mike Rapoport18417.42%847.06%
Matthieu Simon171.61%15.88%
Ricardo Ribalda Delgado50.47%15.88%
Isaac Assegai40.38%15.88%
Elizabeth Ferdman30.28%15.88%
Eric S. Stone20.19%15.88%
Arnd Bergmann10.09%15.88%
Moshe Green10.09%15.88%
Elise Lennion10.09%15.88%
Total1056100.00%17100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.