Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.1-rc8 289 lines 7.0 kB view raw
1/* 2 * Copyright 1998-2009 VIA Technologies, Inc. All Rights Reserved. 3 * Copyright 2001-2008 S3 Graphics, Inc. All Rights Reserved. 4 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public 7 * License as published by the Free Software Foundation; 8 * either version 2, or (at your option) any later version. 9 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTIES OR REPRESENTATIONS; without even 12 * the implied warranty of MERCHANTABILITY or FITNESS FOR 13 * A PARTICULAR PURPOSE.See the GNU General Public License 14 * 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., 19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 */ 21 22#include <linux/platform_device.h> 23#include <linux/delay.h> 24#include <linux/spinlock.h> 25#include <linux/module.h> 26#include <linux/via-core.h> 27#include <linux/via_i2c.h> 28 29/* 30 * There can only be one set of these, so there's no point in having 31 * them be dynamically allocated... 32 */ 33#define VIAFB_NUM_I2C 5 34static struct via_i2c_stuff via_i2c_par[VIAFB_NUM_I2C]; 35static struct viafb_dev *i2c_vdev; /* Passed in from core */ 36 37static void via_i2c_setscl(void *data, int state) 38{ 39 u8 val; 40 struct via_port_cfg *adap_data = data; 41 unsigned long flags; 42 43 spin_lock_irqsave(&i2c_vdev->reg_lock, flags); 44 val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; 45 if (state) 46 val |= 0x20; 47 else 48 val &= ~0x20; 49 switch (adap_data->type) { 50 case VIA_PORT_I2C: 51 val |= 0x01; 52 break; 53 case VIA_PORT_GPIO: 54 val |= 0x80; 55 break; 56 default: 57 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); 58 } 59 via_write_reg(adap_data->io_port, adap_data->ioport_index, val); 60 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); 61} 62 63static int via_i2c_getscl(void *data) 64{ 65 struct via_port_cfg *adap_data = data; 66 unsigned long flags; 67 int ret = 0; 68 69 spin_lock_irqsave(&i2c_vdev->reg_lock, flags); 70 if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x08) 71 ret = 1; 72 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); 73 return ret; 74} 75 76static int via_i2c_getsda(void *data) 77{ 78 struct via_port_cfg *adap_data = data; 79 unsigned long flags; 80 int ret = 0; 81 82 spin_lock_irqsave(&i2c_vdev->reg_lock, flags); 83 if (via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0x04) 84 ret = 1; 85 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); 86 return ret; 87} 88 89static void via_i2c_setsda(void *data, int state) 90{ 91 u8 val; 92 struct via_port_cfg *adap_data = data; 93 unsigned long flags; 94 95 spin_lock_irqsave(&i2c_vdev->reg_lock, flags); 96 val = via_read_reg(adap_data->io_port, adap_data->ioport_index) & 0xF0; 97 if (state) 98 val |= 0x10; 99 else 100 val &= ~0x10; 101 switch (adap_data->type) { 102 case VIA_PORT_I2C: 103 val |= 0x01; 104 break; 105 case VIA_PORT_GPIO: 106 val |= 0x40; 107 break; 108 default: 109 printk(KERN_ERR "viafb_i2c: specify wrong i2c type.\n"); 110 } 111 via_write_reg(adap_data->io_port, adap_data->ioport_index, val); 112 spin_unlock_irqrestore(&i2c_vdev->reg_lock, flags); 113} 114 115int viafb_i2c_readbyte(u8 adap, u8 slave_addr, u8 index, u8 *pdata) 116{ 117 int ret; 118 u8 mm1[] = {0x00}; 119 struct i2c_msg msgs[2]; 120 121 if (!via_i2c_par[adap].is_active) 122 return -ENODEV; 123 *pdata = 0; 124 msgs[0].flags = 0; 125 msgs[1].flags = I2C_M_RD; 126 msgs[0].addr = msgs[1].addr = slave_addr / 2; 127 mm1[0] = index; 128 msgs[0].len = 1; msgs[1].len = 1; 129 msgs[0].buf = mm1; msgs[1].buf = pdata; 130 ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); 131 if (ret == 2) 132 ret = 0; 133 else if (ret >= 0) 134 ret = -EIO; 135 136 return ret; 137} 138 139int viafb_i2c_writebyte(u8 adap, u8 slave_addr, u8 index, u8 data) 140{ 141 int ret; 142 u8 msg[2] = { index, data }; 143 struct i2c_msg msgs; 144 145 if (!via_i2c_par[adap].is_active) 146 return -ENODEV; 147 msgs.flags = 0; 148 msgs.addr = slave_addr / 2; 149 msgs.len = 2; 150 msgs.buf = msg; 151 ret = i2c_transfer(&via_i2c_par[adap].adapter, &msgs, 1); 152 if (ret == 1) 153 ret = 0; 154 else if (ret >= 0) 155 ret = -EIO; 156 157 return ret; 158} 159 160int viafb_i2c_readbytes(u8 adap, u8 slave_addr, u8 index, u8 *buff, int buff_len) 161{ 162 int ret; 163 u8 mm1[] = {0x00}; 164 struct i2c_msg msgs[2]; 165 166 if (!via_i2c_par[adap].is_active) 167 return -ENODEV; 168 msgs[0].flags = 0; 169 msgs[1].flags = I2C_M_RD; 170 msgs[0].addr = msgs[1].addr = slave_addr / 2; 171 mm1[0] = index; 172 msgs[0].len = 1; msgs[1].len = buff_len; 173 msgs[0].buf = mm1; msgs[1].buf = buff; 174 ret = i2c_transfer(&via_i2c_par[adap].adapter, msgs, 2); 175 if (ret == 2) 176 ret = 0; 177 else if (ret >= 0) 178 ret = -EIO; 179 180 return ret; 181} 182 183/* 184 * Allow other viafb subdevices to look up a specific adapter 185 * by port name. 186 */ 187struct i2c_adapter *viafb_find_i2c_adapter(enum viafb_i2c_adap which) 188{ 189 struct via_i2c_stuff *stuff = &via_i2c_par[which]; 190 191 return &stuff->adapter; 192} 193EXPORT_SYMBOL_GPL(viafb_find_i2c_adapter); 194 195 196static int create_i2c_bus(struct i2c_adapter *adapter, 197 struct i2c_algo_bit_data *algo, 198 struct via_port_cfg *adap_cfg, 199 struct pci_dev *pdev) 200{ 201 algo->setsda = via_i2c_setsda; 202 algo->setscl = via_i2c_setscl; 203 algo->getsda = via_i2c_getsda; 204 algo->getscl = via_i2c_getscl; 205 algo->udelay = 10; 206 algo->timeout = 2; 207 algo->data = adap_cfg; 208 209 sprintf(adapter->name, "viafb i2c io_port idx 0x%02x", 210 adap_cfg->ioport_index); 211 adapter->owner = THIS_MODULE; 212 adapter->class = I2C_CLASS_DDC; 213 adapter->algo_data = algo; 214 if (pdev) 215 adapter->dev.parent = &pdev->dev; 216 else 217 adapter->dev.parent = NULL; 218 /* i2c_set_adapdata(adapter, adap_cfg); */ 219 220 /* Raise SCL and SDA */ 221 via_i2c_setsda(adap_cfg, 1); 222 via_i2c_setscl(adap_cfg, 1); 223 udelay(20); 224 225 return i2c_bit_add_bus(adapter); 226} 227 228static int viafb_i2c_probe(struct platform_device *platdev) 229{ 230 int i, ret; 231 struct via_port_cfg *configs; 232 233 i2c_vdev = platdev->dev.platform_data; 234 configs = i2c_vdev->port_cfg; 235 236 for (i = 0; i < VIAFB_NUM_PORTS; i++) { 237 struct via_port_cfg *adap_cfg = configs++; 238 struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; 239 240 i2c_stuff->is_active = 0; 241 if (adap_cfg->type == 0 || adap_cfg->mode != VIA_MODE_I2C) 242 continue; 243 ret = create_i2c_bus(&i2c_stuff->adapter, 244 &i2c_stuff->algo, adap_cfg, 245 NULL); /* FIXME: PCIDEV */ 246 if (ret < 0) { 247 printk(KERN_ERR "viafb: cannot create i2c bus %u:%d\n", 248 i, ret); 249 continue; /* Still try to make the rest */ 250 } 251 i2c_stuff->is_active = 1; 252 } 253 254 return 0; 255} 256 257static int viafb_i2c_remove(struct platform_device *platdev) 258{ 259 int i; 260 261 for (i = 0; i < VIAFB_NUM_PORTS; i++) { 262 struct via_i2c_stuff *i2c_stuff = &via_i2c_par[i]; 263 /* 264 * Only remove those entries in the array that we've 265 * actually used (and thus initialized algo_data) 266 */ 267 if (i2c_stuff->is_active) 268 i2c_del_adapter(&i2c_stuff->adapter); 269 } 270 return 0; 271} 272 273static struct platform_driver via_i2c_driver = { 274 .driver = { 275 .name = "viafb-i2c", 276 }, 277 .probe = viafb_i2c_probe, 278 .remove = viafb_i2c_remove, 279}; 280 281int viafb_i2c_init(void) 282{ 283 return platform_driver_register(&via_i2c_driver); 284} 285 286void viafb_i2c_exit(void) 287{ 288 platform_driver_unregister(&via_i2c_driver); 289}