nvec.c revision 93eff83ff1640bef8062568687b5e0e41a0d4c42
1162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich/* 2162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * NVEC: NVIDIA compliant embedded controller interface 3162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * 4162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net> 5162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * 6162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * Authors: Pierre-Hugues Husson <phhusson@free.fr> 7162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * Ilya Petrov <ilya.muromec@gmail.com> 8162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * Marc Dietrich <marvin24@gmx.de> 9791c4a642721552204d8defdbd6a3e93cd411f79Julian Andres Klode * Julian Andres Klode <jak@jak-linux.org> 10162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * 11162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * This file is subject to the terms and conditions of the GNU General Public 12162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * License. See the file "COPYING" in the main directory of this archive 13162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * for more details. 14162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich * 15162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich */ 16162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich 17162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich/* #define DEBUG */ 1832890b983086136fef8721363a2d3860f337ad53Marc Dietrich 1912b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/kernel.h> 203b769edd58371fb70417c3f43c6d4a2da075703aMarc Dietrich#include <linux/module.h> 210b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode#include <linux/atomic.h> 2212b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/clk.h> 2332890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/completion.h> 2412b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/delay.h> 2512b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/err.h> 2612b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/gpio.h> 2732890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/interrupt.h> 28162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich#include <linux/io.h> 2932890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/irq.h> 307990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich#include <linux/of.h> 317990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich#include <linux/of_gpio.h> 3232890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/list.h> 3312b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/mfd/core.h> 3412b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/mutex.h> 3532890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/notifier.h> 3632890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include <linux/platform_device.h> 3712b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/slab.h> 3812b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/spinlock.h> 3912b5a55d725579d0978da67f26577224a1c40640Julian Andres Klode#include <linux/workqueue.h> 40162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich 41162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich#include <mach/clk.h> 42162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich 4332890b983086136fef8721363a2d3860f337ad53Marc Dietrich#include "nvec.h" 4432890b983086136fef8721363a2d3860f337ad53Marc Dietrich 45391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_CNFG 0x00 46391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_CNFG_PACKET_MODE_EN (1<<10) 47391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_CNFG_NEW_MASTER_SFM (1<<11) 48391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 49391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode 50391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_CNFG 0x20 51d3f862aec400dd831a4bdbea107fd85419bddab1Julian Andres Klode#define I2C_SL_NEWSL (1<<2) 52391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_NACK (1<<1) 53391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_RESP (1<<0) 54391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_IRQ (1<<3) 55391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define END_TRANS (1<<4) 56391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define RCVD (1<<2) 57391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define RNW (1<<1) 58391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode 59391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_RCVD 0x24 60391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_STATUS 0x28 61391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_ADDR1 0x2c 62391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_ADDR2 0x30 63391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode#define I2C_SL_DELAY_COUNT 0x3c 64391d2fa95c8e5e5ad3b06af235ce4aeae6514966Julian Andres Klode 65bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode/** 66bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * enum nvec_msg_category - Message categories for nvec_msg_alloc() 67bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * @NVEC_MSG_RX: The message is an incoming message (from EC) 68bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * @NVEC_MSG_TX: The message is an outgoing message (to EC) 69bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode */ 70bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klodeenum nvec_msg_category { 71bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode NVEC_MSG_RX, 72bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode NVEC_MSG_TX, 73bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode}; 74bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode 75518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrichenum nvec_sleep_subcmds { 76518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich GLOBAL_EVENTS, 7793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich AP_PWR_DOWN, 7893eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich AP_SUSPEND, 79518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich}; 80518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich 8193eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich#define CNF_EVENT_REPORTING 0x01 8293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich#define GET_FIRMWARE_VERSION 0x15 8393eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich#define LID_SWITCH BIT(1) 8493eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich#define PWR_BUTTON BIT(15) 8532890b983086136fef8721363a2d3860f337ad53Marc Dietrich 8632890b983086136fef8721363a2d3860f337ad53Marc Dietrichstatic struct nvec_chip *nvec_power_handle; 8732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 88f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrichstatic struct mfd_cell nvec_devices[] = { 89f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich { 90162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .name = "nvec-kbd", 91162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .id = 1, 92f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich }, 93f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich { 94162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .name = "nvec-mouse", 95162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .id = 1, 96f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich }, 97f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich { 98162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .name = "nvec-power", 99162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .id = 1, 100f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich }, 101f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich { 102162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .name = "nvec-power", 103162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .id = 2, 104f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich }, 10597cc26576fa2b0eb1aad1b29515bb0a32f86c45cIlya Petrov { 106ac562680577a28fa98ebecebff5e5097ccf9a9d2Marc Dietrich .name = "nvec-paz00", 10797cc26576fa2b0eb1aad1b29515bb0a32f86c45cIlya Petrov .id = 1, 10897cc26576fa2b0eb1aad1b29515bb0a32f86c45cIlya Petrov }, 109f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich}; 110f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 111bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 112bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_register_notifier - Register a notifier with nvec 113bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 114bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nb: The notifier block to register 115bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 116bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Registers a notifier with @nvec. The notifier will be added to an atomic 117bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * notifier chain that is called for all received messages except those that 118bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * correspond to a request initiated by nvec_write_sync(). 119bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 12032890b983086136fef8721363a2d3860f337ad53Marc Dietrichint nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb, 121162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich unsigned int events) 12232890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 12332890b983086136fef8721363a2d3860f337ad53Marc Dietrich return atomic_notifier_chain_register(&nvec->notifier_list, nb); 12432890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 12532890b983086136fef8721363a2d3860f337ad53Marc DietrichEXPORT_SYMBOL_GPL(nvec_register_notifier); 12632890b983086136fef8721363a2d3860f337ad53Marc Dietrich 127bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 128bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_status_notifier - The final notifier 129bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 130bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Prints a message about control events not handled in the notifier 131bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * chain. 132bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 133162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrichstatic int nvec_status_notifier(struct notifier_block *nb, 134162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich unsigned long event_type, void *data) 13532890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 13650d4656a2304e48917a8e2b9df99f69d50b8a0aaMarc Dietrich struct nvec_chip *nvec = container_of(nb, struct nvec_chip, 13750d4656a2304e48917a8e2b9df99f69d50b8a0aaMarc Dietrich nvec_status_notifier); 13832890b983086136fef8721363a2d3860f337ad53Marc Dietrich unsigned char *msg = (unsigned char *)data; 13932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 140162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if (event_type != NVEC_CNTL) 14132890b983086136fef8721363a2d3860f337ad53Marc Dietrich return NOTIFY_DONE; 14232890b983086136fef8721363a2d3860f337ad53Marc Dietrich 14350d4656a2304e48917a8e2b9df99f69d50b8a0aaMarc Dietrich dev_warn(nvec->dev, "unhandled msg type %ld\n", event_type); 144a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich print_hex_dump(KERN_WARNING, "payload: ", DUMP_PREFIX_NONE, 16, 1, 145a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich msg, msg[1] + 2, true); 14632890b983086136fef8721363a2d3860f337ad53Marc Dietrich 14732890b983086136fef8721363a2d3860f337ad53Marc Dietrich return NOTIFY_OK; 14832890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 14932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 150bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 151bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_msg_alloc: 152bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 153bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * @category: Pool category, see &enum nvec_msg_category 154bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 155bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Allocate a single &struct nvec_msg object from the message pool of 156bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec. The result shall be passed to nvec_msg_free() if no longer 157bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * used. 158bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * 159bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * Outgoing messages are placed in the upper 75% of the pool, keeping the 160bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * lower 25% available for RX buffers only. The reason is to prevent a 161bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * situation where all buffers are full and a message is thus endlessly 162bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode * retried because the response could never be processed. 163bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 164bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klodestatic struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec, 165bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode enum nvec_msg_category category) 1660b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode{ 167bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode int i = (category == NVEC_MSG_TX) ? (NVEC_POOL_SIZE / 4) : 0; 1680b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode 169bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode for (; i < NVEC_POOL_SIZE; i++) { 1700b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode if (atomic_xchg(&nvec->msg_pool[i].used, 1) == 0) { 1710b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode dev_vdbg(nvec->dev, "INFO: Allocate %i\n", i); 1720b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode return &nvec->msg_pool[i]; 1730b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode } 1740b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode } 1750b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode 176bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode dev_err(nvec->dev, "could not allocate %s buffer\n", 177bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode (category == NVEC_MSG_TX) ? "TX" : "RX"); 1780b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode 1790b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode return NULL; 1800b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode} 1810b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode 182bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 183bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_msg_free: 184bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 185bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @msg: A message (must be allocated by nvec_msg_alloc() and belong to @nvec) 186bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 187bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Free the given message 188bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 189198dd26714ba4a60ccc5ce70bc4506613b4f0c2dJulian Andres Klodeinline void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg) 1900b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode{ 1917b77065793b8de101c7be3829b4ff8a4618a7172Julian Andres Klode if (msg != &nvec->tx_scratch) 1927b77065793b8de101c7be3829b4ff8a4618a7172Julian Andres Klode dev_vdbg(nvec->dev, "INFO: Free %ti\n", msg - nvec->msg_pool); 1930b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode atomic_set(&msg->used, 0); 1940b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode} 195198dd26714ba4a60ccc5ce70bc4506613b4f0c2dJulian Andres KlodeEXPORT_SYMBOL_GPL(nvec_msg_free); 1960b1076c4b2a06e517fafbb2b4704f23e69b05386Julian Andres Klode 1978517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode/** 1988517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * nvec_msg_is_event - Return %true if @msg is an event 1998517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * @msg: A message 2008517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode */ 2018517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klodestatic bool nvec_msg_is_event(struct nvec_msg *msg) 2028517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode{ 2038517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode return msg->data[0] >> 7; 2048517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode} 2058517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode 2068517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode/** 2078517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * nvec_msg_size - Get the size of a message 2088517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * @msg: The message to get the size for 2098517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * 2108517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode * This only works for received messages, not for outgoing messages. 2118517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode */ 2128517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klodestatic size_t nvec_msg_size(struct nvec_msg *msg) 2138517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode{ 2148517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode bool is_event = nvec_msg_is_event(msg); 2158517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode int event_length = (msg->data[0] & 0x60) >> 5; 2168517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode 2178517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode /* for variable size, payload size in byte 1 + count (1) + cmd (1) */ 2188517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode if (!is_event || event_length == NVEC_VAR_SIZE) 2198517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode return (msg->pos || msg->size) ? (msg->data[1] + 2) : 0; 2208517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode else if (event_length == NVEC_2BYTES) 2218517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode return 2; 2228517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode else if (event_length == NVEC_3BYTES) 2238517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode return 3; 2248517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode else 2258517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode return 0; 2268517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode} 2278517e879e0d11a277275616b9e1c749afe2fceffJulian Andres Klode 228bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 229bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_gpio_set_value - Set the GPIO value 230bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 231bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @value: The value to write (0 or 1) 232bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 233bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Like gpio_set_value(), but generating debugging information 234bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 235e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klodestatic void nvec_gpio_set_value(struct nvec_chip *nvec, int value) 236e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode{ 237e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode dev_dbg(nvec->dev, "GPIO changed from %u to %u\n", 238e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode gpio_get_value(nvec->gpio), value); 239e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode gpio_set_value(nvec->gpio, value); 240e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode} 241e7c40851fd7989dad297988b6343f4e3cb687292Julian Andres Klode 242bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 243bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_write_async - Asynchronously write a message to NVEC 244bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: An nvec_chip instance 245bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @data: The message data, starting with the request type 246bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @size: The size of @data 247bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 248bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Queue a single message to be transferred to the embedded controller 249bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * and return immediately. 250bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 251bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Returns: 0 on success, a negative error code on failure. If a failure 252bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * occured, the nvec driver may print an error. 253bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 2541b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klodeint nvec_write_async(struct nvec_chip *nvec, const unsigned char *data, 255162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich short size) 25632890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 2570cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode struct nvec_msg *msg; 2580cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned long flags; 25932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 260bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode msg = nvec_msg_alloc(nvec, NVEC_MSG_TX); 261bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode 2621b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode if (msg == NULL) 2631b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode return -ENOMEM; 2641b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode 26532890b983086136fef8721363a2d3860f337ad53Marc Dietrich msg->data[0] = size; 26632890b983086136fef8721363a2d3860f337ad53Marc Dietrich memcpy(msg->data + 1, data, size); 26732890b983086136fef8721363a2d3860f337ad53Marc Dietrich msg->size = size + 1; 26832890b983086136fef8721363a2d3860f337ad53Marc Dietrich 2690cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_irqsave(&nvec->tx_lock, flags); 27032890b983086136fef8721363a2d3860f337ad53Marc Dietrich list_add_tail(&msg->node, &nvec->tx_data); 2710cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock_irqrestore(&nvec->tx_lock, flags); 27232890b983086136fef8721363a2d3860f337ad53Marc Dietrich 273033d9959ed2dc1029217d4165f80a71702dc578eLinus Torvalds schedule_work(&nvec->tx_work); 2741b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode 2751b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode return 0; 27632890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 27732890b983086136fef8721363a2d3860f337ad53Marc DietrichEXPORT_SYMBOL(nvec_write_async); 27832890b983086136fef8721363a2d3860f337ad53Marc Dietrich 279bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 280bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_write_sync - Write a message to nvec and read the response 281bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: An &struct nvec_chip 282bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @data: The data to write 283bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @size: The size of @data 284bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 285bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * This is similar to nvec_write_async(), but waits for the 286bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * request to be answered before returning. This function 287bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * uses a mutex and can thus not be called from e.g. 288bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * interrupt handlers. 289bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 290bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Returns: A pointer to the response message on success, 291198dd26714ba4a60ccc5ce70bc4506613b4f0c2dJulian Andres Klode * %NULL on failure. Free with nvec_msg_free() once no longer 292198dd26714ba4a60ccc5ce70bc4506613b4f0c2dJulian Andres Klode * used. 293bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 2940cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klodestruct nvec_msg *nvec_write_sync(struct nvec_chip *nvec, 2950cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode const unsigned char *data, short size) 2960cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode{ 2970cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode struct nvec_msg *msg; 2980cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 2990cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode mutex_lock(&nvec->sync_write_mutex); 3000cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3010cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->sync_write_pending = (data[1] << 8) + data[0]; 3021b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode 3034b8bf03d7f775271c2016e76011b113bc5f83c14Marc Dietrich if (nvec_write_async(nvec, data, size) < 0) { 3044b8bf03d7f775271c2016e76011b113bc5f83c14Marc Dietrich mutex_unlock(&nvec->sync_write_mutex); 3051b9bf629ea42fdacd951b9190f86b028557bbe19Julian Andres Klode return NULL; 3064b8bf03d7f775271c2016e76011b113bc5f83c14Marc Dietrich } 3070cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3080cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n", 3090cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->sync_write_pending); 3100cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (!(wait_for_completion_timeout(&nvec->sync_write, 3110cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode msecs_to_jiffies(2000)))) { 3120cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_warn(nvec->dev, "timeout waiting for sync write to complete\n"); 3130cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode mutex_unlock(&nvec->sync_write_mutex); 3140cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode return NULL; 3150cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 3160cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3170cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_dbg(nvec->dev, "nvec_sync_write: pong!\n"); 3180cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3190cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode msg = nvec->last_sync_msg; 3200cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3210cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode mutex_unlock(&nvec->sync_write_mutex); 3220cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3230cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode return msg; 3240cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode} 3250cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres KlodeEXPORT_SYMBOL(nvec_write_sync); 3260cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 327bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 328518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich * nvec_toggle_global_events - enables or disables global event reporting 329518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich * @nvec: nvec handle 330518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich * @state: true for enable, false for disable 331518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich * 332518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich * This switches on/off global event reports by the embedded controller. 333518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich */ 334518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrichstatic void nvec_toggle_global_events(struct nvec_chip *nvec, bool state) 335518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich{ 336518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich unsigned char global_events[] = { NVEC_SLEEP, GLOBAL_EVENTS, state }; 337518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich 338518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich nvec_write_async(nvec, global_events, 3); 339518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich} 340518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich 341518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich/** 34293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * nvec_event_mask - fill the command string with event bitfield 34393eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * ev: points to event command string 34493eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * mask: bit to insert into the event mask 34593eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * 34693eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * Configure event command expects a 32 bit bitfield which describes 34793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * which events to enable. The bitfield has the following structure 34893eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * (from highest byte to lowest): 34993eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * system state bits 7-0 35093eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * system state bits 15-8 35193eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * oem system state bits 7-0 35293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich * oem system state bits 15-8 35393eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich */ 35493eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrichstatic void nvec_event_mask(char *ev, u32 mask) 35593eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich{ 35693eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich ev[3] = mask >> 16 && 0xff; 35793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich ev[4] = mask >> 24 && 0xff; 35893eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich ev[5] = mask >> 0 && 0xff; 35993eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich ev[6] = mask >> 8 && 0xff; 36093eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich} 36193eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich 36293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich/** 363bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_request_master - Process outgoing messages 364bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @work: A &struct work_struct (the tx_worker member of &struct nvec_chip) 365bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 366bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Processes all outgoing requests by sending the request and awaiting the 367bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * response, then continuing with the next request. Once a request has a 368bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * matching response, it will be freed and removed from the list. 369bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 37032890b983086136fef8721363a2d3860f337ad53Marc Dietrichstatic void nvec_request_master(struct work_struct *work) 37132890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 37232890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work); 3730cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned long flags; 3740cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode long err; 3750cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode struct nvec_msg *msg; 3760cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3770cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_irqsave(&nvec->tx_lock, flags); 3780cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode while (!list_empty(&nvec->tx_data)) { 3790cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode msg = list_first_entry(&nvec->tx_data, struct nvec_msg, node); 3800cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock_irqrestore(&nvec->tx_lock, flags); 3810cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_gpio_set_value(nvec, 0); 3820cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode err = wait_for_completion_interruptible_timeout( 3830cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode &nvec->ec_transfer, msecs_to_jiffies(5000)); 3840cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3850cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (err == 0) { 3860cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_warn(nvec->dev, "timeout waiting for ec transfer\n"); 3870cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_gpio_set_value(nvec, 1); 3880cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode msg->pos = 0; 3890cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 39032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 3910cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_irqsave(&nvec->tx_lock, flags); 3920cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 3930cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (err > 0) { 3940cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode list_del_init(&msg->node); 3950cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_msg_free(nvec, msg); 3960cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 3970cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 3980cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock_irqrestore(&nvec->tx_lock, flags); 39932890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 40032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 401bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 402bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * parse_msg - Print some information and call the notifiers on an RX message 403bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 404bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @msg: A message received by @nvec 405bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 406bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Paarse some pieces of the message and then call the chain of notifiers 407bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * registered via nvec_register_notifier. 408bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 40932890b983086136fef8721363a2d3860f337ad53Marc Dietrichstatic int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg) 41032890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 411162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) { 4126a371978836049656525bb0719187362c5114232Andy Shevchenko dev_err(nvec->dev, "ec responded %*ph\n", 4, msg->data); 41332890b983086136fef8721363a2d3860f337ad53Marc Dietrich return -EINVAL; 41432890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 41532890b983086136fef8721363a2d3860f337ad53Marc Dietrich 416a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich if ((msg->data[0] >> 7) == 1 && (msg->data[0] & 0x0f) == 5) 417a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich print_hex_dump(KERN_WARNING, "ec system event ", 418a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich DUMP_PREFIX_NONE, 16, 1, msg->data, 419a3a9aa1a41429b17aa1af20995850ea1b68d5ba2Marc Dietrich msg->data[1] + 2, true); 42032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 421162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f, 422162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich msg->data); 42332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 42432890b983086136fef8721363a2d3860f337ad53Marc Dietrich return 0; 42532890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 42632890b983086136fef8721363a2d3860f337ad53Marc Dietrich 427bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 428bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_dispatch - Process messages received from the EC 429bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @work: A &struct work_struct (the tx_worker member of &struct nvec_chip) 430bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 431bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Process messages previously received from the EC and put into the RX 432bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * queue of the &struct nvec_chip instance associated with @work. 433bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 43432890b983086136fef8721363a2d3860f337ad53Marc Dietrichstatic void nvec_dispatch(struct work_struct *work) 43532890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 43632890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work); 4370cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned long flags; 43832890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_msg *msg; 43932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 4400cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_irqsave(&nvec->rx_lock, flags); 441162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich while (!list_empty(&nvec->rx_data)) { 44232890b983086136fef8721363a2d3860f337ad53Marc Dietrich msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node); 44332890b983086136fef8721363a2d3860f337ad53Marc Dietrich list_del_init(&msg->node); 4440cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock_irqrestore(&nvec->rx_lock, flags); 44532890b983086136fef8721363a2d3860f337ad53Marc Dietrich 446162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if (nvec->sync_write_pending == 4470cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (msg->data[2] << 8) + msg->data[0]) { 44832890b983086136fef8721363a2d3860f337ad53Marc Dietrich dev_dbg(nvec->dev, "sync write completed!\n"); 44932890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec->sync_write_pending = 0; 45032890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec->last_sync_msg = msg; 45132890b983086136fef8721363a2d3860f337ad53Marc Dietrich complete(&nvec->sync_write); 45232890b983086136fef8721363a2d3860f337ad53Marc Dietrich } else { 45332890b983086136fef8721363a2d3860f337ad53Marc Dietrich parse_msg(nvec, msg); 4540cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_msg_free(nvec, msg); 45532890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 4560cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_irqsave(&nvec->rx_lock, flags); 45732890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 4580cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock_irqrestore(&nvec->rx_lock, flags); 45932890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 46032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 461bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 462bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_tx_completed - Complete the current transfer 463bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 464bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 465bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * This is called when we have received an END_TRANS on a TX transfer. 466bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 4670cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klodestatic void nvec_tx_completed(struct nvec_chip *nvec) 4680cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode{ 4690cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* We got an END_TRANS, let's skip this, maybe there's an event */ 4700cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (nvec->tx->pos != nvec->tx->size) { 4710cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "premature END_TRANS, resending\n"); 4720cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx->pos = 0; 4730cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_gpio_set_value(nvec, 0); 4740cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else { 4750cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 4760cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 4770cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode} 4780cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 479bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode/** 480bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * nvec_rx_completed - Complete the current transfer 481bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 482bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 483bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * This is called when we have received an END_TRANS on a RX transfer. 484bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode */ 4850cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klodestatic void nvec_rx_completed(struct nvec_chip *nvec) 4860cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode{ 487210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode if (nvec->rx->pos != nvec_msg_size(nvec->rx)) { 4880cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "RX incomplete: Expected %u bytes, got %u\n", 4890cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (uint) nvec_msg_size(nvec->rx), 4900cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (uint) nvec->rx->pos); 4910cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 492210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode nvec_msg_free(nvec, nvec->rx); 493210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode nvec->state = 0; 494d6bdcf2e1019351cbc176e963b7756766bdd8721Julian Andres Klode 495d6bdcf2e1019351cbc176e963b7756766bdd8721Julian Andres Klode /* Battery quirk - Often incomplete, and likes to crash */ 496d6bdcf2e1019351cbc176e963b7756766bdd8721Julian Andres Klode if (nvec->rx->data[0] == NVEC_BAT) 497d6bdcf2e1019351cbc176e963b7756766bdd8721Julian Andres Klode complete(&nvec->ec_transfer); 498d6bdcf2e1019351cbc176e963b7756766bdd8721Julian Andres Klode 499210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode return; 500210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode } 501210ceb4f68dcc7bede2e3af547abd6f661a7bfdaJulian Andres Klode 5020cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock(&nvec->rx_lock); 5030cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5040cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* add the received data to the work list 5050cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode and move the ring buffer pointer to the next entry */ 5060cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode list_add_tail(&nvec->rx->node, &nvec->rx_data); 5070cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5080cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock(&nvec->rx_lock); 5090cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5100cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 5110cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5120cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (!nvec_msg_is_event(nvec->rx)) 5130cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode complete(&nvec->ec_transfer); 5140cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 515033d9959ed2dc1029217d4165f80a71702dc578eLinus Torvalds schedule_work(&nvec->rx_work); 5160cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode} 5170cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5180cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode/** 5190cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * nvec_invalid_flags - Send an error message about invalid flags and jump 5200cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * @nvec: The nvec device 5210cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * @status: The status flags 5220cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * @reset: Whether we shall jump to state 0. 5230cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode */ 5240cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klodestatic void nvec_invalid_flags(struct nvec_chip *nvec, unsigned int status, 5250cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode bool reset) 5260cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode{ 5270cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "unexpected status flags 0x%02x during state %i\n", 5280cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode status, nvec->state); 5290cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (reset) 5300cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 5310cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode} 5320cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5330cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode/** 5340cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * nvec_tx_set - Set the message to transfer (nvec->tx) 535bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * @nvec: A &struct nvec_chip 536bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 537bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Gets the first entry from the tx_data list of @nvec and sets the 538bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * tx member to it. If the tx_data list is empty, this uses the 539bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * tx_scratch message to send a no operation message. 5400cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode */ 5410cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klodestatic void nvec_tx_set(struct nvec_chip *nvec) 5420cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode{ 5430cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock(&nvec->tx_lock); 5440cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (list_empty(&nvec->tx_data)) { 5450cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "empty tx - sending no-op\n"); 5460cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode memcpy(nvec->tx_scratch.data, "\x02\x07\x02", 3); 5470cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx_scratch.size = 3; 5480cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx_scratch.pos = 0; 5490cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx = &nvec->tx_scratch; 5500cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode list_add_tail(&nvec->tx->node, &nvec->tx_data); 5510cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else { 5520cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx = list_first_entry(&nvec->tx_data, struct nvec_msg, 5530cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode node); 5540cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx->pos = 0; 5550cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 5560cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_unlock(&nvec->tx_lock); 5570cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5580cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_dbg(nvec->dev, "Sending message of length %u, command 0x%x\n", 5590cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (uint)nvec->tx->size, nvec->tx->data[1]); 5600cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode} 5610cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 5620cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode/** 5630cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * nvec_interrupt - Interrupt handler 5640cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * @irq: The IRQ 5650cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode * @dev: The nvec device 566bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * 567bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * Interrupt handler that fills our RX buffers and empties our TX 568bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * buffers. This uses a finite state machine with ridiculous amounts 569bdf034d98676d143cb88f7b999a71fff5775fcd4Julian Andres Klode * of error checking, in order to be fairly reliable. 5700cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode */ 571f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrichstatic irqreturn_t nvec_interrupt(int irq, void *dev) 57232890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 57332890b983086136fef8721363a2d3860f337ad53Marc Dietrich unsigned long status; 5740cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned int received = 0; 5750cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned char to_send = 0xff; 5760cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode const unsigned long irq_mask = I2C_SL_IRQ | END_TRANS | RCVD | RNW; 5770cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode struct nvec_chip *nvec = dev; 5780cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode unsigned int state = nvec->state; 57932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 5800cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode status = readl(nvec->base + I2C_SL_STATUS); 58132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 5820cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* Filter out some errors */ 5830cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & irq_mask) == 0 && (status & ~irq_mask) != 0) { 5840cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "unexpected irq mask %lx\n", status); 5850cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode return IRQ_HANDLED; 58632890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 5870cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & I2C_SL_IRQ) == 0) { 5880cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "Spurious IRQ\n"); 58932890b983086136fef8721363a2d3860f337ad53Marc Dietrich return IRQ_HANDLED; 5900cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 59132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 5920cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* The EC did not request a read, so it send us something, read it */ 5930cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & RNW) == 0) { 5940cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode received = readl(nvec->base + I2C_SL_RCVD); 595162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if (status & RCVD) 5960cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode writel(0, nvec->base + I2C_SL_RCVD); 5970cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 598162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich 5990cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status == (I2C_SL_IRQ | RCVD)) 6000cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 6010cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 6020cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode switch (nvec->state) { 6030cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode case 0: /* Verify that its a transfer start, the rest later */ 6040cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status != (I2C_SL_IRQ | RCVD)) 6050cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_invalid_flags(nvec, status, false); 6060cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 6070cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode case 1: /* command byte */ 6080cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status != I2C_SL_IRQ) { 6090cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_invalid_flags(nvec, status, true); 61032890b983086136fef8721363a2d3860f337ad53Marc Dietrich } else { 611bb0590e2723eed53b524d61cf011d53fc7280949Julian Andres Klode nvec->rx = nvec_msg_alloc(nvec, NVEC_MSG_RX); 6128da798634343de8dbb8c1593923f8368db69f838Julian Andres Klode /* Should not happen in a normal world */ 6138da798634343de8dbb8c1593923f8368db69f838Julian Andres Klode if (unlikely(nvec->rx == NULL)) { 6148da798634343de8dbb8c1593923f8368db69f838Julian Andres Klode nvec->state = 0; 6158da798634343de8dbb8c1593923f8368db69f838Julian Andres Klode break; 6168da798634343de8dbb8c1593923f8368db69f838Julian Andres Klode } 6170cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx->data[0] = received; 6180cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx->pos = 1; 6190cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 2; 6200cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 6210cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 6220cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode case 2: /* first byte after command */ 6230cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status == (I2C_SL_IRQ | RNW | RCVD)) { 6240cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode udelay(33); 6250cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (nvec->rx->data[0] != 0x01) { 6260cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, 6270cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode "Read without prior read command\n"); 6280cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 6290cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 63032890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 6310cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_msg_free(nvec, nvec->rx); 6320cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 3; 6330cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_tx_set(nvec); 6340cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode BUG_ON(nvec->tx->size < 1); 6350cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode to_send = nvec->tx->data[0]; 6360cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx->pos = 1; 6370cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else if (status == (I2C_SL_IRQ)) { 6380cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode BUG_ON(nvec->rx == NULL); 6390cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx->data[1] = received; 6400cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx->pos = 2; 6410cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 4; 6420cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else { 6430cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_invalid_flags(nvec, status, true); 64432890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 6450cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 6460cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode case 3: /* EC does a block read, we transmit data */ 6470cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status & END_TRANS) { 6480cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_tx_completed(nvec); 6490cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else if ((status & RNW) == 0 || (status & RCVD)) { 6500cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_invalid_flags(nvec, status, true); 6510cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else if (nvec->tx && nvec->tx->pos < nvec->tx->size) { 6520cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode to_send = nvec->tx->data[nvec->tx->pos++]; 6530cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } else { 6540cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, "tx buffer underflow on %p (%u > %u)\n", 6550cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->tx, 6560cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (uint) (nvec->tx ? nvec->tx->pos : 0), 6570cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (uint) (nvec->tx ? nvec->tx->size : 0)); 6580cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 65932890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 6600cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 6610cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode case 4: /* EC does some write, we read the data */ 6620cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & (END_TRANS | RNW)) == END_TRANS) 6630cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_rx_completed(nvec); 6640cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode else if (status & (RNW | RCVD)) 6650cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_invalid_flags(nvec, status, true); 6660cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode else if (nvec->rx && nvec->rx->pos < NVEC_MSG_SIZE) 6670cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx->data[nvec->rx->pos++] = received; 6680cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode else 6690cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, 6700cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode "RX buffer overflow on %p: " 6710cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode "Trying to write byte %u of %u\n", 6720cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx, nvec->rx->pos, NVEC_MSG_SIZE); 6730cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode break; 6740cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode default: 6750cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 0; 6760cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 67732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 6780cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* If we are told that a new transfer starts, verify it */ 6790cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & (RCVD | RNW)) == RCVD) { 6800cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (received != nvec->i2c_addr) 6810cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_err(nvec->dev, 6820cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode "received address 0x%02x, expected 0x%02x\n", 6830cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode received, nvec->i2c_addr); 6840cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->state = 1; 68532890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 6860cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 6870cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* Send data if requested, but not on end of transmission */ 6880cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if ((status & (RNW | END_TRANS)) == RNW) 6890cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode writel(to_send, nvec->base + I2C_SL_RCVD); 6900cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 6910cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode /* If we have send the first byte */ 6920cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (status == (I2C_SL_IRQ | RNW | RCVD)) 6930cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_gpio_set_value(nvec, 1); 6940cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 6950cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_dbg(nvec->dev, 6960cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode "Handled: %s 0x%02x, %s 0x%02x in state %u [%s%s%s]\n", 6970cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (status & RNW) == 0 ? "received" : "R=", 6980cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode received, 6990cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode (status & (RNW | END_TRANS)) ? "sent" : "S=", 7000cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode to_send, 7010cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode state, 7020cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode status & END_TRANS ? " END_TRANS" : "", 7030cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode status & RCVD ? " RCVD" : "", 7040cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode status & RNW ? " RNW" : ""); 7050cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode 706de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode 707de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode /* 708de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode * TODO: A correct fix needs to be found for this. 709de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode * 710de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode * We experience less incomplete messages with this delay than without 711de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode * it, but we don't know why. Help is appreciated. 712de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode */ 713de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode udelay(100); 714de839b8f06bc5dd3f5037c4409a720cbb9bf21c3Julian Andres Klode 71532890b983086136fef8721363a2d3860f337ad53Marc Dietrich return IRQ_HANDLED; 71632890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 71732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 718f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrichstatic void tegra_init_i2c_slave(struct nvec_chip *nvec) 71932890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 72032890b983086136fef8721363a2d3860f337ad53Marc Dietrich u32 val; 72132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 72261c3b1971ad4c71c99919da949ac2043dfac8ee7Prashant Gaikwad clk_prepare_enable(nvec->i2c_clk); 723f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 724f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich tegra_periph_reset_assert(nvec->i2c_clk); 72532890b983086136fef8721363a2d3860f337ad53Marc Dietrich udelay(2); 726f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich tegra_periph_reset_deassert(nvec->i2c_clk); 72732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 72832890b983086136fef8721363a2d3860f337ad53Marc Dietrich val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN | 729ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT); 730f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich writel(val, nvec->base + I2C_CNFG); 731ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 732ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich clk_set_rate(nvec->i2c_clk, 8 * 80000); 733ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 734d3f862aec400dd831a4bdbea107fd85419bddab1Julian Andres Klode writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG); 735ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT); 736ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 737ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1); 738ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich writel(0, nvec->base + I2C_SL_ADDR2); 73932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 740ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich enable_irq(nvec->irq); 741ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 74261c3b1971ad4c71c99919da949ac2043dfac8ee7Prashant Gaikwad clk_disable_unprepare(nvec->i2c_clk); 743ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich} 744ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 745ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich#ifdef CONFIG_PM_SLEEP 746ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrichstatic void nvec_disable_i2c_slave(struct nvec_chip *nvec) 747ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich{ 748ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich disable_irq(nvec->irq); 749d3f862aec400dd831a4bdbea107fd85419bddab1Julian Andres Klode writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG); 75061c3b1971ad4c71c99919da949ac2043dfac8ee7Prashant Gaikwad clk_disable_unprepare(nvec->i2c_clk); 75132890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 752ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich#endif 75332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 75432890b983086136fef8721363a2d3860f337ad53Marc Dietrichstatic void nvec_power_off(void) 75532890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 75693eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich char ap_pwr_down[] = { NVEC_SLEEP, AP_PWR_DOWN }; 75793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich 758518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich nvec_toggle_global_events(nvec_power_handle, false); 75993eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_write_async(nvec_power_handle, ap_pwr_down, 2); 76032890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 76132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 76246620803c309d2bc10814b903b39d7647057b440Bill Pembertonstatic int tegra_nvec_probe(struct platform_device *pdev) 76332890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 764f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich int err, ret; 76532890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct clk *i2c_clk; 76632890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_platform_data *pdata = pdev->dev.platform_data; 76732890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_chip *nvec; 76832890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_msg *msg; 769f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich struct resource *res; 770f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich void __iomem *base; 77193eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich char get_firmware_version[] = { NVEC_CNTL, GET_FIRMWARE_VERSION }, 77293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich unmute_speakers[] = { NVEC_OEM0, 0x10, 0x59, 0x95 }, 77393eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich enable_event[7] = { NVEC_SYS, CNF_EVENT_REPORTING, true }; 77432890b983086136fef8721363a2d3860f337ad53Marc Dietrich 775f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich nvec = devm_kzalloc(&pdev->dev, sizeof(struct nvec_chip), GFP_KERNEL); 776162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if (nvec == NULL) { 77732890b983086136fef8721363a2d3860f337ad53Marc Dietrich dev_err(&pdev->dev, "failed to reserve memory\n"); 77832890b983086136fef8721363a2d3860f337ad53Marc Dietrich return -ENOMEM; 77932890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 78032890b983086136fef8721363a2d3860f337ad53Marc Dietrich platform_set_drvdata(pdev, nvec); 78132890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec->dev = &pdev->dev; 7827990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich 7837990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich if (pdata) { 7847990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich nvec->gpio = pdata->gpio; 7857990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich nvec->i2c_addr = pdata->i2c_addr; 7867990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich } else if (nvec->dev->of_node) { 787103b748e21ced078f868f9218cef85b0917cebb2Marc Dietrich nvec->gpio = of_get_named_gpio(nvec->dev->of_node, 788103b748e21ced078f868f9218cef85b0917cebb2Marc Dietrich "request-gpios", 0); 7897990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich if (nvec->gpio < 0) { 7907990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich dev_err(&pdev->dev, "no gpio specified"); 791f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 7927990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich } 793103b748e21ced078f868f9218cef85b0917cebb2Marc Dietrich if (of_property_read_u32(nvec->dev->of_node, 794103b748e21ced078f868f9218cef85b0917cebb2Marc Dietrich "slave-addr", &nvec->i2c_addr)) { 7957990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich dev_err(&pdev->dev, "no i2c address specified"); 796f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 7977990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich } 7987990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich } else { 7997990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich dev_err(&pdev->dev, "no platform data\n"); 800f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 8017990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich } 802f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 803f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 804f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich if (!res) { 805f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(&pdev->dev, "no mem resource?\n"); 806f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich return -ENODEV; 80732890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 80832890b983086136fef8721363a2d3860f337ad53Marc Dietrich 809f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich base = devm_request_and_ioremap(&pdev->dev, res); 810f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich if (!base) { 811f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(&pdev->dev, "Can't ioremap I2C region\n"); 812f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich return -ENOMEM; 81332890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 81432890b983086136fef8721363a2d3860f337ad53Marc Dietrich 815f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 816f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich if (!res) { 817f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(&pdev->dev, "no irq resource?\n"); 818f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 819f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich } 82032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 8214344379f63d3bf16d4f2cb3d6b3f3be12704173fMarc Dietrich i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk"); 822f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich if (IS_ERR(i2c_clk)) { 823f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(nvec->dev, "failed to get controller clock\n"); 824f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 82532890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 82632890b983086136fef8721363a2d3860f337ad53Marc Dietrich 827f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich nvec->base = base; 828f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich nvec->irq = res->start; 829f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich nvec->i2c_clk = i2c_clk; 8300cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec->rx = &nvec->msg_pool[0]; 831f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 83232890b983086136fef8721363a2d3860f337ad53Marc Dietrich ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list); 83332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 83432890b983086136fef8721363a2d3860f337ad53Marc Dietrich init_completion(&nvec->sync_write); 8350cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode init_completion(&nvec->ec_transfer); 8360cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode mutex_init(&nvec->sync_write_mutex); 8370cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_init(&nvec->tx_lock); 8380cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode spin_lock_init(&nvec->rx_lock); 83932890b983086136fef8721363a2d3860f337ad53Marc Dietrich INIT_LIST_HEAD(&nvec->rx_data); 8400cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode INIT_LIST_HEAD(&nvec->tx_data); 84132890b983086136fef8721363a2d3860f337ad53Marc Dietrich INIT_WORK(&nvec->rx_work, nvec_dispatch); 84232890b983086136fef8721363a2d3860f337ad53Marc Dietrich INIT_WORK(&nvec->tx_work, nvec_request_master); 84332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 844f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich err = devm_gpio_request_one(&pdev->dev, nvec->gpio, GPIOF_OUT_INIT_HIGH, 845f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich "nvec gpio"); 846aed92bbcf4ce760c4d7848013a0db3bdd4ae9492Julian Andres Klode if (err < 0) { 847aed92bbcf4ce760c4d7848013a0db3bdd4ae9492Julian Andres Klode dev_err(nvec->dev, "couldn't request gpio\n"); 848f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 849aed92bbcf4ce760c4d7848013a0db3bdd4ae9492Julian Andres Klode } 850aed92bbcf4ce760c4d7848013a0db3bdd4ae9492Julian Andres Klode 851f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich err = devm_request_irq(&pdev->dev, nvec->irq, nvec_interrupt, 0, 852f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich "nvec", nvec); 853f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich if (err) { 854f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(nvec->dev, "couldn't request irq\n"); 855f5e3352e5185ef37700da9a51c333559381fe8fdMarc Dietrich return -ENODEV; 856f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich } 857ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich disable_irq(nvec->irq); 858f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 859f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich tegra_init_i2c_slave(nvec); 860f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 86161c3b1971ad4c71c99919da949ac2043dfac8ee7Prashant Gaikwad clk_prepare_enable(i2c_clk); 862ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich 863f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 86432890b983086136fef8721363a2d3860f337ad53Marc Dietrich /* enable event reporting */ 865518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich nvec_toggle_global_events(nvec, true); 86632890b983086136fef8721363a2d3860f337ad53Marc Dietrich 86732890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec->nvec_status_notifier.notifier_call = nvec_status_notifier; 86832890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0); 86932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 87032890b983086136fef8721363a2d3860f337ad53Marc Dietrich nvec_power_handle = nvec; 87132890b983086136fef8721363a2d3860f337ad53Marc Dietrich pm_power_off = nvec_power_off; 87232890b983086136fef8721363a2d3860f337ad53Marc Dietrich 87332890b983086136fef8721363a2d3860f337ad53Marc Dietrich /* Get Firmware Version */ 87493eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich msg = nvec_write_sync(nvec, get_firmware_version, 2); 87532890b983086136fef8721363a2d3860f337ad53Marc Dietrich 8760cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode if (msg) { 8770cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n", 8780cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode msg->data[4], msg->data[5], msg->data[6], msg->data[7]); 87932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 8800cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode nvec_msg_free(nvec, msg); 8810cab4cb8526d7367c912c9a871d3ad1a9ac1fbf0Julian Andres Klode } 88232890b983086136fef8721363a2d3860f337ad53Marc Dietrich 883f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich ret = mfd_add_devices(nvec->dev, -1, nvec_devices, 8840848c94fb4a5cc213a7fb0fb3a5721ad6e16f096Mark Brown ARRAY_SIZE(nvec_devices), base, 0, NULL); 885162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich if (ret) 886f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich dev_err(nvec->dev, "error adding subdevices\n"); 887f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 88832890b983086136fef8721363a2d3860f337ad53Marc Dietrich /* unmute speakers? */ 88993eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_write_async(nvec, unmute_speakers, 4); 89032890b983086136fef8721363a2d3860f337ad53Marc Dietrich 89132890b983086136fef8721363a2d3860f337ad53Marc Dietrich /* enable lid switch event */ 89293eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_event_mask(enable_event, LID_SWITCH); 89393eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_write_async(nvec, enable_event, 7); 89432890b983086136fef8721363a2d3860f337ad53Marc Dietrich 89532890b983086136fef8721363a2d3860f337ad53Marc Dietrich /* enable power button event */ 89693eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_event_mask(enable_event, PWR_BUTTON); 89793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_write_async(nvec, enable_event, 7); 89832890b983086136fef8721363a2d3860f337ad53Marc Dietrich 89932890b983086136fef8721363a2d3860f337ad53Marc Dietrich return 0; 90032890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 90132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 9021a6a8a8414f740f1dfde762837eeb3f2ce835919Bill Pembertonstatic int tegra_nvec_remove(struct platform_device *pdev) 90332890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 904f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich struct nvec_chip *nvec = platform_get_drvdata(pdev); 905f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 906518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich nvec_toggle_global_events(nvec, false); 907f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich mfd_remove_devices(nvec->dev); 908eb1e40a4dd0fb4095900e085fdd3ed259acbee29Tejun Heo cancel_work_sync(&nvec->rx_work); 909eb1e40a4dd0fb4095900e085fdd3ed259acbee29Tejun Heo cancel_work_sync(&nvec->tx_work); 910f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich 91132890b983086136fef8721363a2d3860f337ad53Marc Dietrich return 0; 91232890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 91332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 914ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich#ifdef CONFIG_PM_SLEEP 915ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrichstatic int nvec_suspend(struct device *dev) 91632890b983086136fef8721363a2d3860f337ad53Marc Dietrich{ 917ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich struct platform_device *pdev = to_platform_device(dev); 91832890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_chip *nvec = platform_get_drvdata(pdev); 9199feeb0147fe6ae3158db5f319faded5e763744f9Marc Dietrich struct nvec_msg *msg; 92093eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich char ap_suspend[] = { NVEC_SLEEP, AP_SUSPEND }; 92132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 92232890b983086136fef8721363a2d3860f337ad53Marc Dietrich dev_dbg(nvec->dev, "suspending\n"); 9239feeb0147fe6ae3158db5f319faded5e763744f9Marc Dietrich 9249feeb0147fe6ae3158db5f319faded5e763744f9Marc Dietrich /* keep these sync or you'll break suspend */ 92593eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich nvec_toggle_global_events(nvec, false); 92693eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich 92793eff83ff1640bef8062568687b5e0e41a0d4c42Marc Dietrich msg = nvec_write_sync(nvec, ap_suspend, sizeof(ap_suspend)); 9289feeb0147fe6ae3158db5f319faded5e763744f9Marc Dietrich nvec_msg_free(nvec, msg); 9299feeb0147fe6ae3158db5f319faded5e763744f9Marc Dietrich 930ac8107599e47b0f4638f4f3fb0141bbcf0cb142bMarc Dietrich nvec_disable_i2c_slave(nvec); 93132890b983086136fef8721363a2d3860f337ad53Marc Dietrich 93232890b983086136fef8721363a2d3860f337ad53Marc Dietrich return 0; 93332890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 93432890b983086136fef8721363a2d3860f337ad53Marc Dietrich 935ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrichstatic int nvec_resume(struct device *dev) 936162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich{ 937ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich struct platform_device *pdev = to_platform_device(dev); 93832890b983086136fef8721363a2d3860f337ad53Marc Dietrich struct nvec_chip *nvec = platform_get_drvdata(pdev); 93932890b983086136fef8721363a2d3860f337ad53Marc Dietrich 94032890b983086136fef8721363a2d3860f337ad53Marc Dietrich dev_dbg(nvec->dev, "resuming\n"); 941f686e9affba24cfdf94fb155aaeb36a1e14719f1Marc Dietrich tegra_init_i2c_slave(nvec); 942518945fbfbe9e2bc39057115aa23e25b084a03e0Marc Dietrich nvec_toggle_global_events(nvec, true); 94332890b983086136fef8721363a2d3860f337ad53Marc Dietrich 94432890b983086136fef8721363a2d3860f337ad53Marc Dietrich return 0; 94532890b983086136fef8721363a2d3860f337ad53Marc Dietrich} 94632890b983086136fef8721363a2d3860f337ad53Marc Dietrich#endif 94732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 948ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrichstatic const SIMPLE_DEV_PM_OPS(nvec_pm_ops, nvec_suspend, nvec_resume); 949ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich 9507990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich/* Match table for of_platform binding */ 951063f9f6a8705c5da3ee46c667a3e6e01eaf31560Bill Pembertonstatic const struct of_device_id nvidia_nvec_of_match[] = { 9527990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich { .compatible = "nvidia,nvec", }, 9537990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich {}, 9547990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich}; 9557990b0d7ec449b10da383bab191eb487185aadceMarc DietrichMODULE_DEVICE_TABLE(of, nvidia_nvec_of_match); 9567990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich 957162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrichstatic struct platform_driver nvec_device_driver = { 958162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .probe = tegra_nvec_probe, 95944b90a3fbcac0f233b71b4041fa76ea325caca33Bill Pemberton .remove = tegra_nvec_remove, 960162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich .driver = { 96132890b983086136fef8721363a2d3860f337ad53Marc Dietrich .name = "nvec", 96232890b983086136fef8721363a2d3860f337ad53Marc Dietrich .owner = THIS_MODULE, 963ebefae28cea729cb1fa9c944179f62d7dd65b10fMarc Dietrich .pm = &nvec_pm_ops, 9647990b0d7ec449b10da383bab191eb487185aadceMarc Dietrich .of_match_table = nvidia_nvec_of_match, 96532890b983086136fef8721363a2d3860f337ad53Marc Dietrich } 96632890b983086136fef8721363a2d3860f337ad53Marc Dietrich}; 96732890b983086136fef8721363a2d3860f337ad53Marc Dietrich 9689891b1ce6276912c54f66b7b0c8c1bcc42ca75ebMarc Dietrichmodule_platform_driver(nvec_device_driver); 969162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc Dietrich 97032890b983086136fef8721363a2d3860f337ad53Marc DietrichMODULE_ALIAS("platform:nvec"); 971162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc DietrichMODULE_DESCRIPTION("NVIDIA compliant embedded controller interface"); 972162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc DietrichMODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>"); 973162c7d8c4be2d599583c42c2a8fe99bed6d87f67Marc DietrichMODULE_LICENSE("GPL"); 974