at v3.1-rc5 467 lines 12 kB view raw
1// #define DEBUG 2 3/* ToDo list (incomplete, unorderd) 4 - convert mouse, keyboard, and power to platform devices 5*/ 6 7#include <asm/io.h> 8#include <asm/irq.h> 9#include <linux/completion.h> 10#include <linux/interrupt.h> 11#include <linux/irq.h> 12#include <linux/slab.h> 13#include <linux/gpio.h> 14#include <linux/serio.h> 15#include <linux/delay.h> 16#include <linux/input.h> 17#include <linux/workqueue.h> 18#include <linux/clk.h> 19#include <mach/iomap.h> 20#include <mach/clk.h> 21#include <linux/semaphore.h> 22#include <linux/list.h> 23#include <linux/notifier.h> 24#include <linux/platform_device.h> 25#include "nvec.h" 26 27static unsigned char EC_DISABLE_EVENT_REPORTING[] = {'\x04','\x00','\x00'}; 28static unsigned char EC_ENABLE_EVENT_REPORTING[] = {'\x04','\x00','\x01'}; 29static unsigned char EC_GET_FIRMWARE_VERSION[] = {'\x07','\x15'}; 30 31static struct nvec_chip *nvec_power_handle; 32 33int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb, 34 unsigned int events) 35{ 36 return atomic_notifier_chain_register(&nvec->notifier_list, nb); 37} 38EXPORT_SYMBOL_GPL(nvec_register_notifier); 39 40static int nvec_status_notifier(struct notifier_block *nb, unsigned long event_type, 41 void *data) 42{ 43 unsigned char *msg = (unsigned char *)data; 44 int i; 45 46 if(event_type != NVEC_CNTL) 47 return NOTIFY_DONE; 48 49 printk("unhandled msg type %ld, payload: ", event_type); 50 for (i = 0; i < msg[1]; i++) 51 printk("%0x ", msg[i+2]); 52 printk("\n"); 53 54 return NOTIFY_OK; 55} 56 57void nvec_write_async(struct nvec_chip *nvec, unsigned char *data, short size) 58{ 59 struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT); 60 61 msg->data = kzalloc(size, GFP_NOWAIT); 62 msg->data[0] = size; 63 memcpy(msg->data + 1, data, size); 64 msg->size = size + 1; 65 msg->pos = 0; 66 INIT_LIST_HEAD(&msg->node); 67 68 list_add_tail(&msg->node, &nvec->tx_data); 69 70 gpio_set_value(nvec->gpio, 0); 71} 72EXPORT_SYMBOL(nvec_write_async); 73 74static void nvec_request_master(struct work_struct *work) 75{ 76 struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work); 77 78 if(!list_empty(&nvec->tx_data)) { 79 gpio_set_value(nvec->gpio, 0); 80 } 81} 82 83static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg) 84{ 85 int i; 86 87 if((msg->data[0] & 1<<7) == 0 && msg->data[3]) { 88 dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n", msg->data[0], 89 msg->data[1], msg->data[2], msg->data[3]); 90 return -EINVAL; 91 } 92 93 if ((msg->data[0] >> 7 ) == 1 && (msg->data[0] & 0x0f) == 5) 94 { 95 dev_warn(nvec->dev, "ec system event "); 96 for (i=0; i < msg->data[1]; i++) 97 dev_warn(nvec->dev, "%02x ", msg->data[2+i]); 98 dev_warn(nvec->dev, "\n"); 99 } 100 101 atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f, msg->data); 102 103 return 0; 104} 105 106static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec, unsigned char *data, short size) 107{ 108 down(&nvec->sync_write_mutex); 109 110 nvec->sync_write_pending = (data[1] << 8) + data[0]; 111 nvec_write_async(nvec, data, size); 112 113 dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n", nvec->sync_write_pending); 114 wait_for_completion(&nvec->sync_write); 115 dev_dbg(nvec->dev, "nvec_sync_write: pong!\n"); 116 117 up(&nvec->sync_write_mutex); 118 119 return nvec->last_sync_msg; 120} 121 122/* RX worker */ 123static void nvec_dispatch(struct work_struct *work) 124{ 125 struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work); 126 struct nvec_msg *msg; 127 128 while(!list_empty(&nvec->rx_data)) 129 { 130 msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node); 131 list_del_init(&msg->node); 132 133 if(nvec->sync_write_pending == (msg->data[2] << 8) + msg->data[0]) 134 { 135 dev_dbg(nvec->dev, "sync write completed!\n"); 136 nvec->sync_write_pending = 0; 137 nvec->last_sync_msg = msg; 138 complete(&nvec->sync_write); 139 } else { 140 parse_msg(nvec, msg); 141 if((!msg) || (!msg->data)) 142 dev_warn(nvec->dev, "attempt access zero pointer"); 143 else { 144 kfree(msg->data); 145 kfree(msg); 146 } 147 } 148 } 149} 150 151static irqreturn_t i2c_interrupt(int irq, void *dev) 152{ 153 unsigned long status; 154 unsigned long received; 155 unsigned char to_send; 156 struct nvec_msg *msg; 157 struct nvec_chip *nvec = (struct nvec_chip *)dev; 158 unsigned char *i2c_regs = nvec->i2c_regs; 159 160 status = readl(i2c_regs + I2C_SL_STATUS); 161 162 if(!(status & I2C_SL_IRQ)) 163 { 164 dev_warn(nvec->dev, "nvec Spurious IRQ\n"); 165 //Yup, handled. ahum. 166 goto handled; 167 } 168 if(status & END_TRANS && !(status & RCVD)) 169 { 170 //Reenable IRQ only when even has been sent 171 //printk("Write sequence ended !\n"); 172 //parse_msg(nvec); 173 nvec->state = NVEC_WAIT; 174 if(nvec->rx->size > 1) 175 { 176 list_add_tail(&nvec->rx->node, &nvec->rx_data); 177 schedule_work(&nvec->rx_work); 178 } else { 179 kfree(nvec->rx->data); 180 kfree(nvec->rx); 181 } 182 return IRQ_HANDLED; 183 } else if(status & RNW) 184 { 185 // Work around for AP20 New Slave Hw Bug. Give 1us extra. 186 // nvec/smbus/nvec_i2c_transport.c in NV`s crap for reference 187 if(status & RCVD) 188 udelay(3); 189 190 if(status & RCVD) 191 { 192 nvec->state = NVEC_WRITE; 193 //Master wants something from us. New communication 194// dev_dbg(nvec->dev, "New read comm!\n"); 195 } else { 196 //Master wants something from us from a communication we've already started 197// dev_dbg(nvec->dev, "Read comm cont !\n"); 198 } 199 //if(msg_pos<msg_size) { 200 if(list_empty(&nvec->tx_data)) 201 { 202 dev_err(nvec->dev, "nvec empty tx - sending no-op\n"); 203 to_send = 0x8a; 204 nvec_write_async(nvec, "\x07\x02", 2); 205// to_send = 0x01; 206 } else { 207 msg = list_first_entry(&nvec->tx_data, struct nvec_msg, node); 208 if(msg->pos < msg->size) { 209 to_send = msg->data[msg->pos]; 210 msg->pos++; 211 } else { 212 dev_err(nvec->dev, "nvec crap! %d\n", msg->size); 213 to_send = 0x01; 214 } 215 216 if(msg->pos >= msg->size) 217 { 218 list_del_init(&msg->node); 219 kfree(msg->data); 220 kfree(msg); 221 schedule_work(&nvec->tx_work); 222 nvec->state = NVEC_WAIT; 223 } 224 } 225 writel(to_send, i2c_regs + I2C_SL_RCVD); 226 227 gpio_set_value(nvec->gpio, 1); 228 229 dev_dbg(nvec->dev, "nvec sent %x\n", to_send); 230 231 goto handled; 232 } else { 233 received = readl(i2c_regs + I2C_SL_RCVD); 234 //Workaround? 235 if(status & RCVD) { 236 writel(0, i2c_regs + I2C_SL_RCVD); 237 goto handled; 238 } 239 240 if (nvec->state == NVEC_WAIT) 241 { 242 nvec->state = NVEC_READ; 243 msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT); 244 msg->data = kzalloc(32, GFP_NOWAIT); 245 INIT_LIST_HEAD(&msg->node); 246 nvec->rx = msg; 247 } else 248 msg = nvec->rx; 249 250 BUG_ON(msg->pos > 32); 251 252 msg->data[msg->pos] = received; 253 msg->pos++; 254 msg->size = msg->pos; 255 dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n", received, msg->pos); 256 } 257handled: 258 return IRQ_HANDLED; 259} 260 261static int __devinit nvec_add_subdev(struct nvec_chip *nvec, struct nvec_subdev *subdev) 262{ 263 struct platform_device *pdev; 264 265 pdev = platform_device_alloc(subdev->name, subdev->id); 266 pdev->dev.parent = nvec->dev; 267 pdev->dev.platform_data = subdev->platform_data; 268 269 return platform_device_add(pdev); 270} 271 272static void tegra_init_i2c_slave(struct nvec_platform_data *pdata, unsigned char *i2c_regs, 273 struct clk *i2c_clk) 274{ 275 u32 val; 276 277 clk_enable(i2c_clk); 278 tegra_periph_reset_assert(i2c_clk); 279 udelay(2); 280 tegra_periph_reset_deassert(i2c_clk); 281 282 writel(pdata->i2c_addr>>1, i2c_regs + I2C_SL_ADDR1); 283 writel(0, i2c_regs + I2C_SL_ADDR2); 284 285 writel(0x1E, i2c_regs + I2C_SL_DELAY_COUNT); 286 val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | 287 (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); 288 writel(val, i2c_regs + I2C_CNFG); 289 writel(I2C_SL_NEWL, i2c_regs + I2C_SL_CNFG); 290 291 clk_disable(i2c_clk); 292} 293 294static void nvec_power_off(void) 295{ 296 nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3); 297 nvec_write_async(nvec_power_handle, "\x04\x01", 2); 298} 299 300static int __devinit tegra_nvec_probe(struct platform_device *pdev) 301{ 302 int err, i, ret; 303 struct clk *i2c_clk; 304 struct nvec_platform_data *pdata = pdev->dev.platform_data; 305 struct nvec_chip *nvec; 306 struct nvec_msg *msg; 307 unsigned char *i2c_regs; 308 309 nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL); 310 if(nvec == NULL) { 311 dev_err(&pdev->dev, "failed to reserve memory\n"); 312 return -ENOMEM; 313 } 314 platform_set_drvdata(pdev, nvec); 315 nvec->dev = &pdev->dev; 316 nvec->gpio = pdata->gpio; 317 nvec->irq = pdata->irq; 318 319/* 320 i2c_clk=clk_get_sys(NULL, "i2c"); 321 if(IS_ERR_OR_NULL(i2c_clk)) 322 printk(KERN_ERR"No such clock tegra-i2c.2\n"); 323 else 324 clk_enable(i2c_clk); 325*/ 326 i2c_regs = ioremap(pdata->base, pdata->size); 327 if(!i2c_regs) { 328 dev_err(nvec->dev, "failed to ioremap registers\n"); 329 goto failed; 330 } 331 332 nvec->i2c_regs = i2c_regs; 333 334 i2c_clk = clk_get_sys(pdata->clock, NULL); 335 if(IS_ERR_OR_NULL(i2c_clk)) { 336 dev_err(nvec->dev, "failed to get clock tegra-i2c.2\n"); 337 goto failed; 338 } 339 340 tegra_init_i2c_slave(pdata, i2c_regs, i2c_clk); 341 342 err = request_irq(nvec->irq, i2c_interrupt, IRQF_DISABLED, "nvec", nvec); 343 if(err) { 344 dev_err(nvec->dev, "couldn't request irq"); 345 goto failed; 346 } 347 348 clk_enable(i2c_clk); 349 clk_set_rate(i2c_clk, 8*80000); 350 351 /* Set the gpio to low when we've got something to say */ 352 err = gpio_request(nvec->gpio, "nvec gpio"); 353 if(err < 0) 354 dev_err(nvec->dev, "couldn't request gpio\n"); 355 356 tegra_gpio_enable(nvec->gpio); 357 gpio_direction_output(nvec->gpio, 1); 358 gpio_set_value(nvec->gpio, 1); 359 360 ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list); 361 362 init_completion(&nvec->sync_write); 363 sema_init(&nvec->sync_write_mutex, 1); 364 INIT_LIST_HEAD(&nvec->tx_data); 365 INIT_LIST_HEAD(&nvec->rx_data); 366 INIT_WORK(&nvec->rx_work, nvec_dispatch); 367 INIT_WORK(&nvec->tx_work, nvec_request_master); 368 369 /* enable event reporting */ 370 nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 371 sizeof(EC_ENABLE_EVENT_REPORTING)); 372 373 nvec_kbd_init(nvec); 374#ifdef CONFIG_SERIO_NVEC_PS2 375 nvec_ps2(nvec); 376#endif 377 378 /* setup subdevs */ 379 for (i = 0; i < pdata->num_subdevs; i++) { 380 ret = nvec_add_subdev(nvec, &pdata->subdevs[i]); 381 } 382 383 nvec->nvec_status_notifier.notifier_call = nvec_status_notifier; 384 nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0); 385 386 nvec_power_handle = nvec; 387 pm_power_off = nvec_power_off; 388 389 /* Get Firmware Version */ 390 msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION, 391 sizeof(EC_GET_FIRMWARE_VERSION)); 392 393 dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n", 394 msg->data[4], msg->data[5], msg->data[6], msg->data[7]); 395 396 kfree(msg->data); 397 kfree(msg); 398 399 /* unmute speakers? */ 400 nvec_write_async(nvec, "\x0d\x10\x59\x94", 4); 401 402 /* enable lid switch event */ 403 nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x02\x00", 7); 404 405 /* enable power button event */ 406 nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7); 407 408 return 0; 409 410failed: 411 kfree(nvec); 412 return -ENOMEM; 413} 414 415static int __devexit tegra_nvec_remove(struct platform_device *pdev) 416{ 417 // TODO: unregister 418 return 0; 419} 420 421#ifdef CONFIG_PM 422 423static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state) 424{ 425 struct nvec_chip *nvec = platform_get_drvdata(pdev); 426 427 dev_dbg(nvec->dev, "suspending\n"); 428 nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3); 429 nvec_write_async(nvec, "\x04\x02", 2); 430 431 return 0; 432} 433 434static int tegra_nvec_resume(struct platform_device *pdev) { 435 436 struct nvec_chip *nvec = platform_get_drvdata(pdev); 437 438 dev_dbg(nvec->dev, "resuming\n"); 439 nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3); 440 441 return 0; 442} 443 444#else 445#define tegra_nvec_suspend NULL 446#define tegra_nvec_resume NULL 447#endif 448 449static struct platform_driver nvec_device_driver = 450{ 451 .probe = tegra_nvec_probe, 452 .remove = __devexit_p(tegra_nvec_remove), 453 .suspend = tegra_nvec_suspend, 454 .resume = tegra_nvec_resume, 455 .driver = { 456 .name = "nvec", 457 .owner = THIS_MODULE, 458 } 459}; 460 461static int __init tegra_nvec_init(void) 462{ 463 return platform_driver_register(&nvec_device_driver); 464} 465 466module_init(tegra_nvec_init); 467MODULE_ALIAS("platform:nvec");