source: trunk/target/linux/ixp4xx/patches-2.6.37/020-gateworks_i2c_pld.patch @ 25725

Last change on this file since 25725 was 25725, checked in by nbd, 5 years ago

ixp4xx: fix the i2c pld driver for 2.6.37 - i2c uses a rt_mutex instead of a mutex now

File size: 9.4 KB
  • new file drivers/gpio/gw_i2c_pld.c

    - +  
     1/* 
     2 * Gateworks I2C PLD GPIO expander 
     3 * 
     4 * Copyright (C) 2009 Gateworks Corporation 
     5 * 
     6 * This program is free software; you can redistribute it and/or modify 
     7 * it under the terms of the GNU General Public License as published by 
     8 * the Free Software Foundation; either version 2 of the License, or 
     9 * (at your option) any later version. 
     10 * 
     11 * This program is distributed in the hope that it will be useful, 
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
     14 * GNU General Public License for more details. 
     15 * 
     16 * You should have received a copy of the GNU General Public License 
     17 * along with this program; if not, write to the Free Software 
     18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
     19 */ 
     20 
     21#include <linux/kernel.h> 
     22#include <linux/slab.h> 
     23#include <linux/hardirq.h> 
     24#include <linux/i2c.h> 
     25#include <linux/i2c/gw_i2c_pld.h> 
     26#include <asm/gpio.h> 
     27 
     28static const struct i2c_device_id gw_i2c_pld_id[] = { 
     29        { "gw_i2c_pld", 8 }, 
     30        { } 
     31}; 
     32MODULE_DEVICE_TABLE(i2c, gw_i2c_pld_id); 
     33 
     34/* 
     35 * The Gateworks I2C PLD chip only expose one read and one 
     36 * write register.  Writing a "one" bit (to match the reset state) lets 
     37 * that pin be used as an input. It is an open-drain model. 
     38 */ 
     39 
     40struct gw_i2c_pld { 
     41        struct gpio_chip        chip; 
     42        struct i2c_client       *client; 
     43        unsigned                out;            /* software latch */ 
     44}; 
     45 
     46/*-------------------------------------------------------------------------*/ 
     47 
     48/* 
     49 * The Gateworks I2C PLD chip does not properly send the acknowledge bit 
     50 * thus we cannot use standard i2c_smbus functions. We have recreated 
     51 * our own here, but we still use the rt_mutex_lock to lock the i2c_bus 
     52 * as the device still exists on the I2C bus. 
     53*/ 
     54 
     55#define PLD_SCL_GPIO 6 
     56#define PLD_SDA_GPIO 7 
     57 
     58#define SCL_LO()  gpio_line_set(PLD_SCL_GPIO, IXP4XX_GPIO_LOW) 
     59#define SCL_HI()  gpio_line_set(PLD_SCL_GPIO, IXP4XX_GPIO_HIGH) 
     60#define SCL_EN()  gpio_line_config(PLD_SCL_GPIO, IXP4XX_GPIO_OUT) 
     61#define SDA_LO()  gpio_line_set(PLD_SDA_GPIO, IXP4XX_GPIO_LOW) 
     62#define SDA_HI()  gpio_line_set(PLD_SDA_GPIO, IXP4XX_GPIO_HIGH) 
     63#define SDA_EN()  gpio_line_config(PLD_SDA_GPIO, IXP4XX_GPIO_OUT) 
     64#define SDA_DIS() gpio_line_config(PLD_SDA_GPIO, IXP4XX_GPIO_IN) 
     65#define SDA_IN(x) gpio_line_get(PLD_SDA_GPIO, &x); 
     66 
     67static int i2c_pld_write_byte(int address, int byte) 
     68{ 
     69        int i; 
     70 
     71        address = (address << 1) & ~0x1; 
     72 
     73        SDA_HI(); 
     74        SDA_EN(); 
     75        SCL_EN(); 
     76        SCL_HI(); 
     77        SDA_LO(); 
     78        SCL_LO(); 
     79 
     80        for (i = 7; i >= 0; i--) 
     81        { 
     82                if (address & (1 << i)) 
     83                        SDA_HI(); 
     84                else 
     85                        SDA_LO(); 
     86 
     87                SCL_HI(); 
     88                SCL_LO(); 
     89        } 
     90 
     91        SDA_DIS(); 
     92        SCL_HI(); 
     93        SDA_IN(i); 
     94        SCL_LO(); 
     95        SDA_EN(); 
     96 
     97        for (i = 7; i >= 0; i--) 
     98        { 
     99                if (byte & (1 << i)) 
     100      SDA_HI(); 
     101                else 
     102                        SDA_LO(); 
     103                SCL_HI(); 
     104                SCL_LO(); 
     105        } 
     106 
     107        SDA_DIS(); 
     108        SCL_HI(); 
     109        SDA_IN(i); 
     110        SCL_LO(); 
     111 
     112        SDA_HI(); 
     113        SDA_EN(); 
     114 
     115        SDA_LO(); 
     116        SCL_HI(); 
     117        SDA_HI(); 
     118        SCL_LO(); 
     119        SCL_HI(); 
     120 
     121        return 0; 
     122} 
     123 
     124static unsigned int i2c_pld_read_byte(int address) 
     125{ 
     126        int i = 0, byte = 0; 
     127        int bit; 
     128 
     129        address = (address << 1) | 0x1; 
     130 
     131        SDA_HI(); 
     132        SDA_EN(); 
     133        SCL_EN(); 
     134        SCL_HI(); 
     135        SDA_LO(); 
     136        SCL_LO(); 
     137 
     138        for (i = 7; i >= 0; i--) 
     139        { 
     140                if (address & (1 << i)) 
     141                        SDA_HI(); 
     142                else 
     143                        SDA_LO(); 
     144 
     145                SCL_HI(); 
     146                SCL_LO(); 
     147        } 
     148 
     149        SDA_DIS(); 
     150        SCL_HI(); 
     151        SDA_IN(i); 
     152        SCL_LO(); 
     153        SDA_EN(); 
     154 
     155        SDA_DIS(); 
     156        for (i = 7; i >= 0; i--) 
     157        { 
     158                SCL_HI(); 
     159                SDA_IN(bit); 
     160                byte |= bit << i; 
     161                SCL_LO(); 
     162        } 
     163 
     164        SDA_LO(); 
     165        SCL_HI(); 
     166        SDA_HI(); 
     167        SCL_LO(); 
     168        SCL_HI(); 
     169 
     170        return byte; 
     171} 
     172 
     173 
     174static int gw_i2c_pld_input8(struct gpio_chip *chip, unsigned offset) 
     175{ 
     176        int ret; 
     177        struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip); 
     178        struct i2c_adapter *adap = gpio->client->adapter; 
     179 
     180        if (in_atomic() || irqs_disabled()) { 
     181                ret = rt_mutex_trylock(&adap->bus_lock); 
     182                if (!ret) 
     183                        /* I2C activity is ongoing. */ 
     184                        return -EAGAIN; 
     185        } else { 
     186                rt_mutex_lock(&adap->bus_lock); 
     187        } 
     188 
     189        gpio->out |= (1 << offset); 
     190 
     191        ret = i2c_pld_write_byte(gpio->client->addr, gpio->out); 
     192 
     193        rt_mutex_unlock(&adap->bus_lock); 
     194 
     195        return ret; 
     196} 
     197 
     198static int gw_i2c_pld_get8(struct gpio_chip *chip, unsigned offset) 
     199{ 
     200        int ret; 
     201        s32     value; 
     202        struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip); 
     203        struct i2c_adapter *adap = gpio->client->adapter; 
     204 
     205        if (in_atomic() || irqs_disabled()) { 
     206                ret = rt_mutex_trylock(&adap->bus_lock); 
     207                if (!ret) 
     208                        /* I2C activity is ongoing. */ 
     209                        return -EAGAIN; 
     210        } else { 
     211                rt_mutex_lock(&adap->bus_lock); 
     212        } 
     213 
     214        value = i2c_pld_read_byte(gpio->client->addr); 
     215 
     216        rt_mutex_unlock(&adap->bus_lock); 
     217 
     218        return (value < 0) ? 0 : (value & (1 << offset)); 
     219} 
     220 
     221static int gw_i2c_pld_output8(struct gpio_chip *chip, unsigned offset, int value) 
     222{ 
     223        int ret; 
     224 
     225        struct gw_i2c_pld *gpio = container_of(chip, struct gw_i2c_pld, chip); 
     226        struct i2c_adapter *adap = gpio->client->adapter; 
     227 
     228        unsigned bit = 1 << offset; 
     229 
     230        if (in_atomic() || irqs_disabled()) { 
     231                ret = rt_mutex_trylock(&adap->bus_lock); 
     232                if (!ret) 
     233                        /* I2C activity is ongoing. */ 
     234                        return -EAGAIN; 
     235        } else { 
     236                rt_mutex_lock(&adap->bus_lock); 
     237        } 
     238 
     239 
     240        if (value) 
     241                gpio->out |= bit; 
     242        else 
     243                gpio->out &= ~bit; 
     244 
     245        ret = i2c_pld_write_byte(gpio->client->addr, gpio->out); 
     246 
     247        rt_mutex_unlock(&adap->bus_lock); 
     248 
     249        return ret; 
     250} 
     251 
     252static void gw_i2c_pld_set8(struct gpio_chip *chip, unsigned offset, int value) 
     253{ 
     254        gw_i2c_pld_output8(chip, offset, value); 
     255} 
     256 
     257/*-------------------------------------------------------------------------*/ 
     258 
     259static int gw_i2c_pld_probe(struct i2c_client *client, 
     260                         const struct i2c_device_id *id) 
     261{ 
     262        struct gw_i2c_pld_platform_data *pdata; 
     263        struct gw_i2c_pld *gpio; 
     264        int status; 
     265 
     266        pdata = client->dev.platform_data; 
     267        if (!pdata) 
     268                return -ENODEV; 
     269 
     270        /* Allocate, initialize, and register this gpio_chip. */ 
     271        gpio = kzalloc(sizeof *gpio, GFP_KERNEL); 
     272        if (!gpio) 
     273                return -ENOMEM; 
     274 
     275        gpio->chip.base = pdata->gpio_base; 
     276        gpio->chip.can_sleep = 1; 
     277        gpio->chip.dev = &client->dev; 
     278        gpio->chip.owner = THIS_MODULE; 
     279 
     280        gpio->chip.ngpio = pdata->nr_gpio; 
     281        gpio->chip.direction_input = gw_i2c_pld_input8; 
     282        gpio->chip.get = gw_i2c_pld_get8; 
     283        gpio->chip.direction_output = gw_i2c_pld_output8; 
     284        gpio->chip.set = gw_i2c_pld_set8; 
     285 
     286        gpio->chip.label = client->name; 
     287 
     288        gpio->client = client; 
     289        i2c_set_clientdata(client, gpio); 
     290 
     291        gpio->out = 0xFF; 
     292 
     293        status = gpiochip_add(&gpio->chip); 
     294        if (status < 0) 
     295                goto fail; 
     296 
     297        dev_info(&client->dev, "gpios %d..%d on a %s%s\n", 
     298                        gpio->chip.base, 
     299                        gpio->chip.base + gpio->chip.ngpio - 1, 
     300                        client->name, 
     301                        client->irq ? " (irq ignored)" : ""); 
     302 
     303        /* Let platform code set up the GPIOs and their users. 
     304         * Now is the first time anyone could use them. 
     305         */ 
     306        if (pdata->setup) { 
     307                status = pdata->setup(client, 
     308                                gpio->chip.base, gpio->chip.ngpio, 
     309                                pdata->context); 
     310                if (status < 0) 
     311                        dev_warn(&client->dev, "setup --> %d\n", status); 
     312        } 
     313 
     314        return 0; 
     315 
     316fail: 
     317        dev_dbg(&client->dev, "probe error %d for '%s'\n", 
     318                        status, client->name); 
     319        kfree(gpio); 
     320        return status; 
     321} 
     322 
     323static int gw_i2c_pld_remove(struct i2c_client *client) 
     324{ 
     325        struct gw_i2c_pld_platform_data *pdata = client->dev.platform_data; 
     326        struct gw_i2c_pld *gpio = i2c_get_clientdata(client); 
     327        int                             status = 0; 
     328 
     329        if (pdata->teardown) { 
     330                status = pdata->teardown(client, 
     331                                gpio->chip.base, gpio->chip.ngpio, 
     332                                pdata->context); 
     333                if (status < 0) { 
     334                        dev_err(&client->dev, "%s --> %d\n", 
     335                                        "teardown", status); 
     336                        return status; 
     337                } 
     338        } 
     339 
     340        status = gpiochip_remove(&gpio->chip); 
     341        if (status == 0) 
     342                kfree(gpio); 
     343        else 
     344                dev_err(&client->dev, "%s --> %d\n", "remove", status); 
     345        return status; 
     346} 
     347 
     348static struct i2c_driver gw_i2c_pld_driver = { 
     349        .driver = { 
     350                .name   = "gw_i2c_pld", 
     351                .owner  = THIS_MODULE, 
     352        }, 
     353        .probe  = gw_i2c_pld_probe, 
     354        .remove = gw_i2c_pld_remove, 
     355        .id_table = gw_i2c_pld_id, 
     356}; 
     357 
     358static int __init gw_i2c_pld_init(void) 
     359{ 
     360        return i2c_add_driver(&gw_i2c_pld_driver); 
     361} 
     362module_init(gw_i2c_pld_init); 
     363 
     364static void __exit gw_i2c_pld_exit(void) 
     365{ 
     366        i2c_del_driver(&gw_i2c_pld_driver); 
     367} 
     368module_exit(gw_i2c_pld_exit); 
     369 
     370MODULE_LICENSE("GPL"); 
     371MODULE_AUTHOR("Chris Lang"); 
  • drivers/gpio/Kconfig

    a b config GPIO_RDC321X 
    348348          Support for the RDC R321x SoC GPIOs over southbridge 
    349349          PCI configuration space. 
    350350 
     351config GPIO_GW_I2C_PLD 
     352        tristate "Gateworks I2C PLD GPIO Expander" 
     353        depends on I2C 
     354        help 
     355                Say yes here to provide access to the Gateworks I2C PLD GPIO 
     356                Expander. This is used at least on the GW2358-4. 
     357 
     358 
    351359comment "SPI GPIO expanders:" 
    352360 
    353361config GPIO_MAX7301 
  • drivers/gpio/Makefile

    a b obj-$(CONFIG_GPIO_RDC321X) += rdc321x-gp 
    4141obj-$(CONFIG_GPIO_JANZ_TTL)     += janz-ttl.o 
    4242obj-$(CONFIG_GPIO_SX150X)       += sx150x.o 
    4343obj-$(CONFIG_GPIO_VX855)        += vx855_gpio.o 
     44obj-$(CONFIG_GPIO_GW_I2C_PLD)   += gw_i2c_pld.o 
  • new file include/linux/i2c/gw_i2c_pld.h

    - +  
     1#ifndef __LINUX_GW_I2C_PLD_H 
     2#define __LINUX_GW_I2C_PLD_H 
     3 
     4/** 
     5 * The Gateworks I2C PLD Implements an additional 8 bits of GPIO through the PLD 
     6 */ 
     7 
     8struct gw_i2c_pld_platform_data { 
     9        unsigned gpio_base; 
     10        unsigned nr_gpio; 
     11        int             (*setup)(struct i2c_client *client, 
     12                                        int gpio, unsigned ngpio, 
     13                                        void *context); 
     14        int             (*teardown)(struct i2c_client *client, 
     15                                        int gpio, unsigned ngpio, 
     16                                        void *context); 
     17        void            *context; 
     18}; 
     19 
     20#endif /* __LINUX_GW_I2C_PLD_H */ 
Note: See TracBrowser for help on using the repository browser.