1108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/* 2e7eacd36865ae0707f5efae8e4dda421ffcd1b66Ralph Campbell * Copyright (c) 2006, 2007, 2008 QLogic Corporation. All rights reserved. 3108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Copyright (c) 2003, 2004, 2005, 2006 PathScale, Inc. All rights reserved. 4108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 5108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * This software is available to you under a choice of one of two 6108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * licenses. You may choose to be licensed under the terms of the GNU 7108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * General Public License (GPL) Version 2, available from the file 8108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * COPYING in the main directory of this source tree, or the 9108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * OpenIB.org BSD license below: 10108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 11108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Redistribution and use in source and binary forms, with or 12108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * without modification, are permitted provided that the following 13108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * conditions are met: 14108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 15108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * - Redistributions of source code must retain the above 16108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * copyright notice, this list of conditions and the following 17108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * disclaimer. 18108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 19108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * - Redistributions in binary form must reproduce the above 20108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * copyright notice, this list of conditions and the following 21108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * disclaimer in the documentation and/or other materials 22108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * provided with the distribution. 23108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 24108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 27108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 28108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 29108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 30108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 31108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * SOFTWARE. 32108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 33108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 34108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/delay.h> 35108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/pci.h> 36108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include <linux/vmalloc.h> 37108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 38108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#include "ipath_kernel.h" 39108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 40108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/* 41108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * InfiniPath I2C driver for a serial eeprom. This is not a generic 42108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * I2C interface. For a start, the device we're using (Atmel AT24C11) 43108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * doesn't work like a regular I2C device. It looks like one 44108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * electrically, but not logically. Normal I2C devices have a single 45108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 7-bit or 10-bit I2C address that they respond to. Valid 7-bit 46108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * addresses range from 0x03 to 0x77. Addresses 0x00 to 0x02 and 0x78 47108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * to 0x7F are special reserved addresses (e.g. 0x00 is the "general 48108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * call" address.) The Atmel device, on the other hand, responds to ALL 49108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 7-bit addresses. It's designed to be the only device on a given I2C 50108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * bus. A 7-bit address corresponds to the memory address within the 51108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Atmel device itself. 52108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 53108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Also, the timing requirements mean more than simple software 54108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * bitbanging, with readbacks from chip to ensure timing (simple udelay 55108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * is not enough). 56108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 57108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * This all means that accessing the device is specialized enough 58108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * that using the standard kernel I2C bitbanging interface would be 59108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * impossible. For example, the core I2C eeprom driver expects to find 60108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * a device at one or more of a limited set of addresses only. It doesn't 61108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * allow writing to an eeprom. It also doesn't provide any means of 62108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * accessing eeprom contents from within the kernel, only via sysfs. 63108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 64108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 65d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/* Added functionality for IBA7220-based cards */ 66d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_EEPROM_DEV_V1 0xA0 67d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_EEPROM_DEV_V2 0xA2 68d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_TEMP_DEV 0x98 69d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_BAD_DEV (IPATH_EEPROM_DEV_V2+2) 70d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define IPATH_NO_DEV (0xFF) 71d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 72d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/* 73d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * The number of I2C chains is proliferating. Table below brings 74d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * some order to the madness. The basic principle is that the 75d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * table is scanned from the top, and a "probe" is made to the 76d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * device probe_dev. If that succeeds, the chain is considered 77d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * to be of that type, and dd->i2c_chain_type is set to the index+1 78d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * of the entry. 79d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * The +1 is so static initialization can mean "unknown, do probe." 80d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 81d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic struct i2c_chain_desc { 82d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh u8 probe_dev; /* If seen at probe, chain is this type */ 83d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh u8 eeprom_dev; /* Dev addr (if any) for EEPROM */ 84d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh u8 temp_dev; /* Dev Addr (if any) for Temp-sense */ 85d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} i2c_chains[] = { 86d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh { IPATH_BAD_DEV, IPATH_NO_DEV, IPATH_NO_DEV }, /* pre-iba7220 bds */ 87d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh { IPATH_EEPROM_DEV_V1, IPATH_EEPROM_DEV_V1, IPATH_TEMP_DEV}, /* V1 */ 88d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh { IPATH_EEPROM_DEV_V2, IPATH_EEPROM_DEV_V2, IPATH_TEMP_DEV}, /* V2 */ 89d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh { IPATH_NO_DEV } 90d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh}; 91d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 92108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanenum i2c_type { 93108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_line_scl = 0, 94108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_line_sda 95108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}; 96108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 97108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanenum i2c_state { 98108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_line_low = 0, 99108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_line_high 100108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan}; 101108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 102108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#define READ_CMD 1 103108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan#define WRITE_CMD 0 104108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 105108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 106108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_gpio_set - set a GPIO line 107108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 108108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @line: the line to set 109108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @new_line_state: the state to set 110108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 111108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if the line was set to the new state successfully, non-zero 112108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * on error. 113108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 114108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_gpio_set(struct ipath_devdata *dd, 115108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan enum i2c_type line, 116108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan enum i2c_state new_line_state) 117108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 11817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh u64 out_mask, dir_mask, *gpioval; 11917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh unsigned long flags = 0; 120108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 121108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan gpioval = &dd->ipath_gpio_out; 122108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 12317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh if (line == i2c_line_scl) { 12417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dir_mask = dd->ipath_gpio_scl; 12517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh out_mask = (1UL << dd->ipath_gpio_scl_num); 12617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh } else { 12717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dir_mask = dd->ipath_gpio_sda; 12817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh out_mask = (1UL << dd->ipath_gpio_sda_num); 12917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh } 13017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh 13117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_lock_irqsave(&dd->ipath_gpio_lock, flags); 13217b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh if (new_line_state == i2c_line_high) { 133108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* tri-state the output rather than force high */ 13417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dd->ipath_extctrl &= ~dir_mask; 13517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh } else { 136108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* config line to be an output */ 13717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dd->ipath_extctrl |= dir_mask; 13817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh } 13917b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl); 140108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 14117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh /* set output as well (no real verify) */ 142108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (new_line_state == i2c_line_high) 14317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh *gpioval |= out_mask; 144108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan else 14517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh *gpioval &= ~out_mask; 146108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 147108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_write_kreg(dd, dd->ipath_kregs->kr_gpio_out, *gpioval); 14817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); 149108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 150108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return 0; 151108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 152108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 153108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 154108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_gpio_get - get a GPIO line state 155108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 156108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @line: the line to get 157108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @curr_statep: where to put the line state 158108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 159108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if the line was set to the new state successfully, non-zero 160108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * on error. curr_state is not set on error. 161108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 162108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_gpio_get(struct ipath_devdata *dd, 163108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan enum i2c_type line, 164108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan enum i2c_state *curr_statep) 165108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 16617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh u64 read_val, mask; 167108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int ret; 16817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh unsigned long flags = 0; 169108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 170108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* check args */ 171108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (curr_statep == NULL) { 172108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 1; 173108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 174108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 175108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 176108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* config line to be an input */ 177108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (line == i2c_line_scl) 178f62fe77ad26b9c89c2028d96709f0f28793fe6cdBryan O'Sullivan mask = dd->ipath_gpio_scl; 179108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan else 180f62fe77ad26b9c89c2028d96709f0f28793fe6cdBryan O'Sullivan mask = dd->ipath_gpio_sda; 18117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh 18217b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_lock_irqsave(&dd->ipath_gpio_lock, flags); 18317b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dd->ipath_extctrl &= ~mask; 18417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh ipath_write_kreg(dd, dd->ipath_kregs->kr_extctrl, dd->ipath_extctrl); 18517b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh /* 18617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh * Below is very unlikely to reflect true input state if Output 18717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh * Enable actually changed. 18817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh */ 189108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan read_val = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extstatus); 19017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); 191108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 192108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (read_val & mask) 193108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *curr_statep = i2c_line_high; 194108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan else 195108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *curr_statep = i2c_line_low; 196108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 197108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 0; 198108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 199108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail: 200108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return ret; 201108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 202108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 203108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 204108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_wait_for_writes - wait for a write 205108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 206108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 207108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * We use this instead of udelay directly, so we can make sure 208108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * that previous register writes have been flushed all the way 209108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * to the chip. Since we are delaying anyway, the cost doesn't 210108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * hurt, and makes the bit twiddling more regular 211108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 212108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void i2c_wait_for_writes(struct ipath_devdata *dd) 213108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 214108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan (void)ipath_read_kreg32(dd, dd->ipath_kregs->kr_scratch); 2151a4e74a08788db913486cb9a3dc30984c55e9897Bryan O'Sullivan rmb(); 216108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 217108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 218108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void scl_out(struct ipath_devdata *dd, u8 bit) 219108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 22017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh udelay(1); 221108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_gpio_set(dd, i2c_line_scl, bit ? i2c_line_high : i2c_line_low); 222108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 223108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_wait_for_writes(dd); 224108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 225108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 226108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void sda_out(struct ipath_devdata *dd, u8 bit) 227108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 228108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_gpio_set(dd, i2c_line_sda, bit ? i2c_line_high : i2c_line_low); 229108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 230108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_wait_for_writes(dd); 231108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 232108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 233108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic u8 sda_in(struct ipath_devdata *dd, int wait) 234108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 235108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan enum i2c_state bit; 236108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 237108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (i2c_gpio_get(dd, i2c_line_sda, &bit)) 238108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dbg("get bit failed!\n"); 239108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 240108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (wait) 241108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan i2c_wait_for_writes(dd); 242108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 243108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return bit == i2c_line_high ? 1U : 0; 244108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 245108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 246108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 247108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_ackrcv - see if ack following write is true 248108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 249108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 250108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_ackrcv(struct ipath_devdata *dd) 251108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 252108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u8 ack_received; 253108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 254108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* AT ENTRY SCL = LOW */ 255108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* change direction, ignore data */ 256108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ack_received = sda_in(dd, 1); 257108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 258108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ack_received = sda_in(dd, 1) == 0; 259108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 260108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return ack_received; 261108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 262108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 263108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 264d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * rd_byte - read a byte, leaving ACK, STOP, etc up to caller 265d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device 266d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * 267d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Returns byte shifted out of device 268d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 269d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int rd_byte(struct ipath_devdata *dd) 270d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 271d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int bit_cntr, data; 272d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 273d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh data = 0; 274d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 275d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh for (bit_cntr = 7; bit_cntr >= 0; --bit_cntr) { 276d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh data <<= 1; 277d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh scl_out(dd, i2c_line_high); 278d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh data |= sda_in(dd, 0); 279d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh scl_out(dd, i2c_line_low); 280d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 281d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return data; 282d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 283d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 284d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/** 285108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * wr_byte - write a byte, one bit at a time 286108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 287108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @data: the byte to write 288108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 289108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * Returns 0 if we got the following ack, otherwise 1 290108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 291108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int wr_byte(struct ipath_devdata *dd, u8 data) 292108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 293108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int bit_cntr; 294108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u8 bit; 295108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 296108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan for (bit_cntr = 7; bit_cntr >= 0; bit_cntr--) { 297108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bit = (data >> bit_cntr) & 1; 298108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, bit); 299108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 300108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 301108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 302108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return (!i2c_ackrcv(dd)) ? 1 : 0; 303108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 304108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 305108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void send_ack(struct ipath_devdata *dd) 306108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 307108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_low); 308108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 309108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 310108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_high); 311108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 312108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 313108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 314108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * i2c_startcmd - transmit the start condition, followed by address/cmd 315108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 316108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @offset_dir: direction byte 317108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 318108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * (both clock/data high, clock high, data low while clock is high) 319108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 320108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int i2c_startcmd(struct ipath_devdata *dd, u8 offset_dir) 321108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 322108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int res; 323108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 324108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* issue start sequence */ 325108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_high); 326108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 327108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_low); 328108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 329108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 330108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* issue length and direction byte */ 331108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan res = wr_byte(dd, offset_dir); 332108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 333108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (res) 334108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_cdbg(VERBOSE, "No ack to complete start\n"); 335108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 336108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return res; 337108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 338108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 339108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 340108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * stop_cmd - transmit the stop condition 341108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 342108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 343108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * (both clock/data low, clock high, data high while clock is high) 344108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 345108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic void stop_cmd(struct ipath_devdata *dd) 346108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 347108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 348108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_low); 349108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 350108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_high); 351108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan udelay(2); 352108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 353108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 354108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 355108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * eeprom_reset - reset I2C communication 356108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 357108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 358108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 359108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic int eeprom_reset(struct ipath_devdata *dd) 360108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 361108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int clock_cycles_left = 9; 362108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u64 *gpioval = &dd->ipath_gpio_out; 363108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int ret; 36417b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh unsigned long flags; 365108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 36617b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_lock_irqsave(&dd->ipath_gpio_lock, flags); 36717b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh /* Make sure shadows are consistent */ 36817b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh dd->ipath_extctrl = ipath_read_kreg64(dd, dd->ipath_kregs->kr_extctrl); 369108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *gpioval = ipath_read_kreg64(dd, dd->ipath_kregs->kr_gpio_out); 37017b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh spin_unlock_irqrestore(&dd->ipath_gpio_lock, flags); 37117b2eb9fe6bfadcb3ece308ed50193d10b71ba6eMichael Albaugh 372108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_cdbg(VERBOSE, "Resetting i2c eeprom; initial gpioout reg " 373108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "is %llx\n", (unsigned long long) *gpioval); 374108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 375108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* 376108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * This is to get the i2c into a known state, by first going low, 377108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * then tristate sda (and then tristate scl as first thing 378108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * in loop) 379108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 380108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 381108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_high); 382108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 383d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* Clock up to 9 cycles looking for SDA hi, then issue START and STOP */ 384108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan while (clock_cycles_left--) { 385108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_high); 386108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 387d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* SDA seen high, issue START by dropping it while SCL high */ 388108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (sda_in(dd, 0)) { 389108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sda_out(dd, i2c_line_low); 390108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 391d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* ATMEL spec says must be followed by STOP. */ 392d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh scl_out(dd, i2c_line_high); 393d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh sda_out(dd, i2c_line_high); 394108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 0; 395108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 396108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 397108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 398108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan scl_out(dd, i2c_line_low); 399108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 400108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 401108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 1; 402108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 403108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail: 404108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return ret; 405108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 406108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 407d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/* 408d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Probe for I2C device at specified address. Returns 0 for "success" 409d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * to match rest of this file. 410d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Leave bus in "reasonable" state for further commands. 411108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 412d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int i2c_probe(struct ipath_devdata *dd, int devaddr) 413d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 414d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int ret = 0; 415d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 416d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = eeprom_reset(dd); 417d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 418d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed reset probing device 0x%02X\n", 419d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh devaddr); 420d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 421d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 422d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 423d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Reset no longer leaves bus in start condition, so normal 424d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * i2c_startcmd() will do. 425d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 426d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = i2c_startcmd(dd, devaddr | READ_CMD); 427d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) 428d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_cdbg(VERBOSE, "Failed startcmd for device 0x%02X\n", 429d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh devaddr); 430d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh else { 431d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 432d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Device did respond. Complete a single-byte read, because some 433d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * devices apparently cannot handle STOP immediately after they 434d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ACK the start-cmd. 435d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 436d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int data; 437d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh data = rd_byte(dd); 438d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 439d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_cdbg(VERBOSE, "Response from device 0x%02X\n", devaddr); 440d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 441d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 442d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 443d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 444d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/* 445d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Returns the "i2c type". This is a pointer to a struct that describes 446d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * the I2C chain on this board. To minimize impact on struct ipath_devdata, 447d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * the (small integer) index into the table is actually memoized, rather 448d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * then the pointer. 449d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Memoization is because the type is determined on the first call per chip. 450d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * An alternative would be to move type determination to early 451d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * init code. 452d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 453d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic struct i2c_chain_desc *ipath_i2c_type(struct ipath_devdata *dd) 454d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 455d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int idx; 456d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 457d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* Get memoized index, from previous successful probes */ 458d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh idx = dd->ipath_i2c_chain_type - 1; 459d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (idx >= 0 && idx < (ARRAY_SIZE(i2c_chains) - 1)) 460d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto done; 461d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 462d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh idx = 0; 463d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh while (i2c_chains[idx].probe_dev != IPATH_NO_DEV) { 464d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* if probe succeeds, this is type */ 465d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!i2c_probe(dd, i2c_chains[idx].probe_dev)) 466d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh break; 467d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ++idx; 468d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 469d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 470d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 471d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * Old EEPROM (first entry) may require a reset after probe, 472d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * rather than being able to "start" after "stop" 473d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 474d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (idx == 0) 475d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh eeprom_reset(dd); 476d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 477d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_chains[idx].probe_dev == IPATH_NO_DEV) 478d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh idx = -1; 479d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh else 480d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh dd->ipath_i2c_chain_type = idx + 1; 481d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughdone: 482d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return (idx >= 0) ? i2c_chains + idx : NULL; 483d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 484108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 485aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughstatic int ipath_eeprom_internal_read(struct ipath_devdata *dd, 486aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh u8 eeprom_offset, void *buffer, int len) 487108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 488108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int ret; 489d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh struct i2c_chain_desc *icd; 490d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh u8 *bp = buffer; 491108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 492d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = 1; 493d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh icd = ipath_i2c_type(dd); 494d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!icd) 495d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 496108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 497d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (icd->eeprom_dev == IPATH_NO_DEV) { 498d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* legacy not-really-I2C */ 499d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_cdbg(VERBOSE, "Start command only address\n"); 500d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh eeprom_offset = (eeprom_offset << 1) | READ_CMD; 501d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = i2c_startcmd(dd, eeprom_offset); 502d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } else { 503d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* Actual I2C */ 504d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_cdbg(VERBOSE, "Start command uses devaddr\n"); 505d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) { 506d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed EEPROM startcmd\n"); 507d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 508d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = 1; 509d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 510d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 511d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = wr_byte(dd, eeprom_offset); 512d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 513d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 514d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed to write EEPROM address\n"); 515d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = 1; 516d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 517d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 518d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = i2c_startcmd(dd, icd->eeprom_dev | READ_CMD); 519d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 520d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 521d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed startcmd for dev %02X\n", icd->eeprom_dev); 522108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 523108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 1; 524108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 525108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 526108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 527108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* 528108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * eeprom keeps clocking data out as long as we ack, automatically 529108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * incrementing the address. 530108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 531108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan while (len-- > 0) { 532d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* get and store data */ 533d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh *bp++ = rd_byte(dd); 534108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* send ack if not the last byte */ 535108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (len) 536108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan send_ack(dd); 537108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 538108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 539108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 540108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 541108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 0; 542108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 543108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail: 544108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return ret; 545108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 546108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 547da9aec7b627c0369b955f82e855508c6711929acRoland Dreierstatic int ipath_eeprom_internal_write(struct ipath_devdata *dd, u8 eeprom_offset, 548da9aec7b627c0369b955f82e855508c6711929acRoland Dreier const void *buffer, int len) 549108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 550108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int sub_len; 551108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan const u8 *bp = buffer; 552108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int max_wait_time, i; 553108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int ret; 554d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh struct i2c_chain_desc *icd; 555108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 556d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = 1; 557d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh icd = ipath_i2c_type(dd); 558d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!icd) 559d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 560108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 561108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan while (len > 0) { 562d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (icd->eeprom_dev == IPATH_NO_DEV) { 563d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, 564d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh (eeprom_offset << 1) | WRITE_CMD)) { 565d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed to start cmd offset %u\n", 566d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh eeprom_offset); 567d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto failed_write; 568d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 569d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } else { 570d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* Real I2C */ 571d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, icd->eeprom_dev | WRITE_CMD)) { 572d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed EEPROM startcmd\n"); 573d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto failed_write; 574d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 575d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = wr_byte(dd, eeprom_offset); 576d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 577d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed to write EEPROM " 578d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh "address\n"); 579d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto failed_write; 580d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 581108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 582108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 583108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan sub_len = min(len, 4); 584108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan eeprom_offset += sub_len; 585108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan len -= sub_len; 586108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 587108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan for (i = 0; i < sub_len; i++) { 588108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (wr_byte(dd, *bp++)) { 589108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dbg("no ack after byte %u/%u (%u " 590108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "total remain)\n", i, sub_len, 591108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan len + sub_len - i); 592108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto failed_write; 593108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 594108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 595108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 596108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 597108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 598108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* 599108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * wait for write complete by waiting for a successful 600108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * read (the chip replies with a zero after the write 601108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * cmd completes, and before it writes to the eeprom. 602108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * The startcmd for the read will fail the ack until 603108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * the writes have completed. We do this inline to avoid 604108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * the debug prints that are in the real read routine 605108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * if the startcmd fails. 606d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * We also use the proper device address, so it doesn't matter 607d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * whether we have real eeprom_dev. legacy likes any address. 608108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 609108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan max_wait_time = 100; 610d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh while (i2c_startcmd(dd, icd->eeprom_dev | READ_CMD)) { 611108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 612108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (!--max_wait_time) { 613108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dbg("Did not get successful read to " 614108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "complete write\n"); 615108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto failed_write; 616108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 617108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 618d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* now read (and ignore) the resulting byte */ 619d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh rd_byte(dd); 620108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 621108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 622108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 623108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 0; 624108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 625108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 626108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanfailed_write: 627108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan stop_cmd(dd); 628108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ret = 1; 629108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 630108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail: 631108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return ret; 632108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 633108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 634d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/** 635d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_eeprom_read - receives bytes from the eeprom via I2C 636d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device 637d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @eeprom_offset: address to read from 638d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @buffer: where to store result 639d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @len: number of bytes to receive 640aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 641aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_eeprom_read(struct ipath_devdata *dd, u8 eeprom_offset, 642aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh void *buff, int len) 643aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{ 644aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int ret; 645aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 6462c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke ret = mutex_lock_interruptible(&dd->ipath_eep_lock); 647aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (!ret) { 648aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = ipath_eeprom_internal_read(dd, eeprom_offset, buff, len); 6492c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 650aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 651aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 652aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh return ret; 653aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh} 654aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 655d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/** 656d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_eeprom_write - writes data to the eeprom via I2C 657d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device 658d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @eeprom_offset: where to place data 659d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @buffer: data to write 660d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @len: number of bytes to write 661d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 662aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_eeprom_write(struct ipath_devdata *dd, u8 eeprom_offset, 663aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh const void *buff, int len) 664aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{ 665aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int ret; 666aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 6672c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke ret = mutex_lock_interruptible(&dd->ipath_eep_lock); 668aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (!ret) { 669aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = ipath_eeprom_internal_write(dd, eeprom_offset, buff, len); 6702c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 671aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 672aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 673aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh return ret; 674aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh} 675aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 676108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanstatic u8 flash_csum(struct ipath_flash *ifp, int adjust) 677108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 678108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u8 *ip = (u8 *) ifp; 679108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u8 csum = 0, len; 680108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 681627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh /* 682627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh * Limit length checksummed to max length of actual data. 683627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh * Checksum of erased eeprom will still be bad, but we avoid 684627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh * reading past the end of the buffer we were passed. 685627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh */ 686627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh len = ifp->if_length; 687627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh if (len > sizeof(struct ipath_flash)) 688627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh len = sizeof(struct ipath_flash); 689627934448ec80f823eafd0a7d4b7541515d543a3Michael Albaugh while (len--) 690108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan csum += *ip++; 691108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan csum -= ifp->if_csum; 692108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan csum = ~csum; 693108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (adjust) 694108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ifp->if_csum = csum; 695108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 696108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan return csum; 697108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 698108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 699108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan/** 700108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * ipath_get_guid - get the GUID from the i2c device 701108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * @dd: the infinipath device 702108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 703f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivan * We have the capability to use the ipath_nguid field, and get 704f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivan * the guid from the first chip's flash, to use for all of them. 705108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan */ 706f2080fa3c6098dedfb9b599bdaedd07be2ea4646Bryan O'Sullivanvoid ipath_get_eeprom_info(struct ipath_devdata *dd) 707108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan{ 708108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan void *buf; 709108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan struct ipath_flash *ifp; 710108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan __be64 guid; 711aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int len, eep_stat; 712108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan u8 csum, *bguid; 713108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan int t = dd->ipath_unit; 714108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan struct ipath_devdata *dd0 = ipath_lookup(0); 715108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 716108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (t && dd0->ipath_nguid > 1 && t <= dd0->ipath_nguid) { 717cf9542aa923982428fbf6a6f815c32ae2c3da8c7Roland Dreier u8 oguid; 718108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd->ipath_guid = dd0->ipath_guid; 719108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid = (u8 *) & dd->ipath_guid; 720108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 721108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan oguid = bguid[7]; 722108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[7] += t; 723108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (oguid > bguid[7]) { 724108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (bguid[6] == 0xff) { 725108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (bguid[5] == 0xff) { 726108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dev_err( 727108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd, 728108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "Can't set %s GUID from " 729108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "base, wraps to OUI!\n", 730108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_get_unit_name(t)); 731108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd->ipath_guid = 0; 732108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 733108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 734108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[5]++; 735108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 736108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[6]++; 737108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 738108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd->ipath_nguid = 1; 739108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 740108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dbg("nguid %u, so adding %u to device 0 guid, " 741108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "for %llx\n", 742108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd0->ipath_nguid, t, 743108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan (unsigned long long) be64_to_cpu(dd->ipath_guid)); 744108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 745108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 746108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 747d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson /* 748d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson * read full flash, not just currently used part, since it may have 749d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson * been written with a newer definition 750d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson * */ 751d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson len = sizeof(struct ipath_flash); 752108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan buf = vmalloc(len); 753108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (!buf) { 754108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dev_err(dd, "Couldn't allocate memory to read %u " 755108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "bytes from eeprom for GUID\n", len); 756108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto bail; 757108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 758108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 7592c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_lock(&dd->ipath_eep_lock); 760aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh eep_stat = ipath_eeprom_internal_read(dd, 0, buf, len); 7612c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 762aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 763aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (eep_stat) { 764108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dev_err(dd, "Failed reading GUID from eeprom\n"); 765108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto done; 766108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 767108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ifp = (struct ipath_flash *)buf; 768108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 769108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan csum = flash_csum(ifp, 0); 770108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (csum != ifp->if_csum) { 771108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dev_info(&dd->pcidev->dev, "Bad I2C flash checksum: " 772108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "0x%x, not 0x%x\n", csum, ifp->if_csum); 773108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto done; 774108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 7759c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison if (*(__be64 *) ifp->if_guid == cpu_to_be64(0) || 7769c3da0991754d480328eeaa2b90cb231a1cea9b6Harvey Harrison *(__be64 *) ifp->if_guid == ~cpu_to_be64(0)) { 777108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_dev_err(dd, "Invalid GUID %llx from flash; " 778108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "ignoring\n", 779108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *(unsigned long long *) ifp->if_guid); 780108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* don't allow GUID if all 0 or all 1's */ 781108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan goto done; 782108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } 783108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 784108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* complain, but allow it */ 785108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (*(u64 *) ifp->if_guid == 0x100007511000000ULL) 786108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dev_info(&dd->pcidev->dev, "Warning, GUID %llx is " 787108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "default, probably not correct!\n", 788108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan *(unsigned long long *) ifp->if_guid); 789108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 790108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid = ifp->if_guid; 791108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan if (!bguid[0] && !bguid[1] && !bguid[2]) { 792108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan /* original incorrect GUID format in flash; fix in 793108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * core copy, by shifting up 2 octets; don't need to 794108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * change top octet, since both it and shifted are 795108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan * 0.. */ 796108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[1] = bguid[3]; 797108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[2] = bguid[4]; 798108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan bguid[3] = bguid[4] = 0; 799108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan guid = *(__be64 *) ifp->if_guid; 800108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_cdbg(VERBOSE, "Old GUID format in flash, top 3 zero, " 801108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan "shifting 2 octets\n"); 802108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan } else 803108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan guid = *(__be64 *) ifp->if_guid; 804108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd->ipath_guid = guid; 805108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan dd->ipath_nguid = ifp->if_numguid; 8068307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan /* 8078307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan * Things are slightly complicated by the desire to transparently 8088307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan * support both the Pathscale 10-digit serial number and the QLogic 8098307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan * 13-character version. 8108307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan */ 8118307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan if ((ifp->if_fversion > 1) && ifp->if_sprefix[0] 8128307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan && ((u8 *)ifp->if_sprefix)[0] != 0xFF) { 8138307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan /* This board has a Serial-prefix, which is stored 8148307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan * elsewhere for backward-compatibility. 8158307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan */ 8168307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan char *snp = dd->ipath_serial; 8178307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix); 8188307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan snp[sizeof ifp->if_sprefix] = '\0'; 8198307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan len = strlen(snp); 8208307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan snp += len; 8218307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan len = (sizeof dd->ipath_serial) - len; 8228307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan if (len > sizeof ifp->if_serial) { 8238307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan len = sizeof ifp->if_serial; 8248307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan } 8258307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan memcpy(snp, ifp->if_serial, len); 8268307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan } else 8278307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan memcpy(dd->ipath_serial, ifp->if_serial, 8288307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan sizeof ifp->if_serial); 8299783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan if (!strstr(ifp->if_comment, "Tested successfully")) 8309783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan ipath_dev_err(dd, "Board SN %s did not pass functional " 8319783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan "test: %s\n", dd->ipath_serial, 8329783ab405844202b452ac673677e6c8f8c9a6a99Bryan O'Sullivan ifp->if_comment); 8338307c28eecea917c4754075fbb85eb398a3bc516Bryan O'Sullivan 834108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan ipath_cdbg(VERBOSE, "Initted GUID to %llx from eeprom\n", 835108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan (unsigned long long) be64_to_cpu(dd->ipath_guid)); 836108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 837aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh memcpy(&dd->ipath_eep_st_errs, &ifp->if_errcntp, IPATH_EEP_LOG_CNT); 838aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 839aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Power-on (actually "active") hours are kept as little-endian value 840aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * in EEPROM, but as seconds in a (possibly as small as 24-bit) 841aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * atomic_t while running. 842aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 843aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh atomic_set(&dd->ipath_active_time, 0); 844aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh dd->ipath_eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8); 845aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 846108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivandone: 847108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan vfree(buf); 848108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan 849108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivanbail:; 850108ecf0d90655055d5a7db8d3a7239133b4d52b7Bryan O'Sullivan} 851aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 852aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh/** 853aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * ipath_update_eeprom_log - copy active-time and error counters to eeprom 854aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @dd: the infinipath device 855aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * 856aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Although the time is kept as seconds in the ipath_devdata struct, it is 857aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * rounded to hours for re-write, as we have only 16 bits in EEPROM. 858aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * First-cut code reads whole (expected) struct ipath_flash, modifies, 859aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * re-writes. Future direction: read/write only what we need, assuming 860aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * that the EEPROM had to have been "good enough" for driver init, and 861aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * if not, we aren't making it worse. 862aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * 863aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 864aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 865aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughint ipath_update_eeprom_log(struct ipath_devdata *dd) 866aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{ 867aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh void *buf; 868aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh struct ipath_flash *ifp; 869aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int len, hi_water; 870aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh uint32_t new_time, new_hrs; 871aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh u8 csum; 872aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int ret, idx; 873aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh unsigned long flags; 874aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 875aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* first, check if we actually need to do anything. */ 876aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = 0; 877aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) { 878aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (dd->ipath_eep_st_new_errs[idx]) { 879aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = 1; 880aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh break; 881aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 882aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 883aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_time = atomic_read(&dd->ipath_active_time); 884aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 885aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (ret == 0 && new_time < 3600) 886aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh return 0; 887aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 888aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 889aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * The quick-check above determined that there is something worthy 890aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * of logging, so get current contents and do a more detailed idea. 891d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson * read full flash, not just currently used part, since it may have 892d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson * been written with a newer definition 893aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 894d29cc6efb9731a415957b8d0ff16e31729ed6837Dave Olson len = sizeof(struct ipath_flash); 895aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh buf = vmalloc(len); 896aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = 1; 897aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (!buf) { 898aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ipath_dev_err(dd, "Couldn't allocate memory to read %u " 899aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh "bytes from eeprom for logging\n", len); 900aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh goto bail; 901aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 902aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 903aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* Grab semaphore and read current EEPROM. If we get an 904aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * error, let go, but if not, keep it until we finish write. 905aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 9062c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke ret = mutex_lock_interruptible(&dd->ipath_eep_lock); 907aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (ret) { 908aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ipath_dev_err(dd, "Unable to acquire EEPROM for logging\n"); 909aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh goto free_bail; 910aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 911aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = ipath_eeprom_internal_read(dd, 0, buf, len); 912aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (ret) { 9132c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 914aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ipath_dev_err(dd, "Unable read EEPROM for logging\n"); 915aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh goto free_bail; 916aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 917aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ifp = (struct ipath_flash *)buf; 918aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 919aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh csum = flash_csum(ifp, 0); 920aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (csum != ifp->if_csum) { 9212c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 922aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ipath_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n", 923aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh csum, ifp->if_csum); 924aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = 1; 925aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh goto free_bail; 926aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 927aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh hi_water = 0; 928aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); 929aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh for (idx = 0; idx < IPATH_EEP_LOG_CNT; ++idx) { 930aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh int new_val = dd->ipath_eep_st_new_errs[idx]; 931aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (new_val) { 932aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 933aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * If we have seen any errors, add to EEPROM values 934aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * We need to saturate at 0xFF (255) and we also 935aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * would need to adjust the checksum if we were 936aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * trying to minimize EEPROM traffic 937aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Note that we add to actual current count in EEPROM, 938aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * in case it was altered while we were running. 939aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 940aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_val += ifp->if_errcntp[idx]; 941aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (new_val > 0xFF) 942aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_val = 0xFF; 943aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (ifp->if_errcntp[idx] != new_val) { 944aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ifp->if_errcntp[idx] = new_val; 945aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh hi_water = offsetof(struct ipath_flash, 946aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if_errcntp) + idx; 947aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 948aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 949aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * update our shadow (used to minimize EEPROM 950aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * traffic), to match what we are about to write. 951aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 952aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh dd->ipath_eep_st_errs[idx] = new_val; 953aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh dd->ipath_eep_st_new_errs[idx] = 0; 954aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 955aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 956aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 957aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * now update active-time. We would like to round to the nearest hour 958aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * but unless atomic_t are sure to be proper signed ints we cannot, 959aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * because we need to account for what we "transfer" to EEPROM and 960aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * if we log an hour at 31 minutes, then we would need to set 961aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * active_time to -29 to accurately count the _next_ hour. 962aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 963d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (new_time >= 3600) { 964aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_hrs = new_time / 3600; 965aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh atomic_sub((new_hrs * 3600), &dd->ipath_active_time); 966aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_hrs += dd->ipath_eep_hrs; 967aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (new_hrs > 0xFFFF) 968aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_hrs = 0xFFFF; 969aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh dd->ipath_eep_hrs = new_hrs; 970aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) { 971aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ifp->if_powerhour[0] = new_hrs & 0xFF; 972aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh hi_water = offsetof(struct ipath_flash, if_powerhour); 973aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 974aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if ((new_hrs >> 8) != ifp->if_powerhour[1]) { 975aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ifp->if_powerhour[1] = new_hrs >> 8; 976aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh hi_water = offsetof(struct ipath_flash, if_powerhour) 977aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh + 1; 978aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 979aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 980aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* 981aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * There is a tiny possibility that we could somehow fail to write 982aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * the EEPROM after updating our shadows, but problems from holding 983aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * the spinlock too long are a much bigger issue. 984aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 985aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); 986aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (hi_water) { 987aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh /* we made some change to the data, uopdate cksum and write */ 988aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh csum = flash_csum(ifp, 1); 989aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ret = ipath_eeprom_internal_write(dd, 0, buf, hi_water + 1); 990aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh } 9912c45688faed1b19583c388694025e39001b68c8dMatthias Kaehlcke mutex_unlock(&dd->ipath_eep_lock); 992aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (ret) 993aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh ipath_dev_err(dd, "Failed updating EEPROM\n"); 994aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 995aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughfree_bail: 996aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh vfree(buf); 997aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughbail: 998aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh return ret; 999aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 1000aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh} 1001aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 1002aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh/** 1003aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * ipath_inc_eeprom_err - increment one of the four error counters 1004aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * that are logged to EEPROM. 1005aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @dd: the infinipath device 1006aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @eidx: 0..3, the counter to increment 1007aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * @incr: how much to add 1008aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * 1009aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * Each counter is 8-bits, and saturates at 255 (0xFF). They 1010aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * are copied to the EEPROM (aka flash) whenever ipath_update_eeprom_log() 1011aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * is called, but it can only be called in a context that allows sleep. 1012aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh * This function can be called even at interrupt level. 1013aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh */ 1014aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 1015aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaughvoid ipath_inc_eeprom_err(struct ipath_devdata *dd, u32 eidx, u32 incr) 1016aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh{ 1017aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh uint new_val; 1018aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh unsigned long flags; 1019aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh 1020aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh spin_lock_irqsave(&dd->ipath_eep_st_lock, flags); 1021aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_val = dd->ipath_eep_st_new_errs[eidx] + incr; 1022aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh if (new_val > 255) 1023aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh new_val = 255; 1024aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh dd->ipath_eep_st_new_errs[eidx] = new_val; 1025aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh spin_unlock_irqrestore(&dd->ipath_eep_st_lock, flags); 1026aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh return; 1027aecd3b5ab19624ca9644b9df9c61615282d8923fMichael Albaugh} 1028d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1029d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int ipath_tempsense_internal_read(struct ipath_devdata *dd, u8 regnum) 1030d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 1031d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int ret; 1032d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh struct i2c_chain_desc *icd; 1033d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1034d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENOENT; 1035d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1036d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh icd = ipath_i2c_type(dd); 1037d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!icd) 1038d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1039d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1040d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (icd->temp_dev == IPATH_NO_DEV) { 1041d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* tempsense only exists on new, real-I2C boards */ 1042d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1043d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1044d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1045d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1046d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) { 1047d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed tempsense startcmd\n"); 1048d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1049d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1050d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1051d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1052d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = wr_byte(dd, regnum); 1053d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1054d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 1055d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed tempsense WR command %02X\n", 1056d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh regnum); 1057d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1058d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1059d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1060d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, icd->temp_dev | READ_CMD)) { 1061d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed tempsense RD startcmd\n"); 1062d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1063d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1064d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1065d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1066d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 1067d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * We can only clock out one byte per command, sensibly 1068d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 1069d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = rd_byte(dd); 1070d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1071d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1072d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughbail: 1073d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 1074d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 1075d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1076d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define VALID_TS_RD_REG_MASK 0xBF 1077d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1078d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/** 1079d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_tempsense_read - read register of temp sensor via I2C 1080d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device 1081d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @regnum: register to read from 1082d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * 1083d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * returns reg contents (0..255) or < 0 for error 1084d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 1085d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughint ipath_tempsense_read(struct ipath_devdata *dd, u8 regnum) 1086d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 1087d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int ret; 1088d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1089d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (regnum > 7) 1090d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return -EINVAL; 1091d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1092d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* return a bogus value for (the one) register we do not have */ 1093d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!((1 << regnum) & VALID_TS_RD_REG_MASK)) 1094d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return 0; 1095d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1096d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = mutex_lock_interruptible(&dd->ipath_eep_lock); 1097d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!ret) { 1098d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = ipath_tempsense_internal_read(dd, regnum); 1099d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh mutex_unlock(&dd->ipath_eep_lock); 1100d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1101d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1102d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 1103d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * There are three possibilities here: 1104d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is actual value (0..255) 1105d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is -ENXIO or -EINVAL from code in this file 1106d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is -EINTR from mutex_lock_interruptible. 1107d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 1108d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 1109d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 1110d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1111d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughstatic int ipath_tempsense_internal_write(struct ipath_devdata *dd, 1112d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh u8 regnum, u8 data) 1113d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 1114d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int ret = -ENOENT; 1115d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh struct i2c_chain_desc *icd; 1116d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1117d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh icd = ipath_i2c_type(dd); 1118d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!icd) 1119d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1120d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1121d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (icd->temp_dev == IPATH_NO_DEV) { 1122d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* tempsense only exists on new, real-I2C boards */ 1123d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1124d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1125d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1126d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (i2c_startcmd(dd, icd->temp_dev | WRITE_CMD)) { 1127d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dbg("Failed tempsense startcmd\n"); 1128d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1129d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1130d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1131d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1132d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = wr_byte(dd, regnum); 1133d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 1134d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1135d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed to write tempsense command %02X\n", 1136d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh regnum); 1137d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1138d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh goto bail; 1139d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1140d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = wr_byte(dd, data); 1141d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh stop_cmd(dd); 1142d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = i2c_startcmd(dd, icd->temp_dev | READ_CMD); 1143d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (ret) { 1144d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ipath_dev_err(dd, "Failed tempsense data wrt to %02X\n", 1145d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh regnum); 1146d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = -ENXIO; 1147d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1148d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1149d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughbail: 1150d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 1151d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 1152d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1153d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh#define VALID_TS_WR_REG_MASK ((1 << 9) | (1 << 0xB) | (1 << 0xD)) 1154d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1155d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh/** 1156d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ipath_tempsense_write - write register of temp sensor via I2C 1157d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @dd: the infinipath device 1158d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @regnum: register to write 1159d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * @data: data to write 1160d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * 1161d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * returns 0 for success or < 0 for error 1162d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 1163d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaughint ipath_tempsense_write(struct ipath_devdata *dd, u8 regnum, u8 data) 1164d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh{ 1165d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh int ret; 1166d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1167d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (regnum > 15 || !((1 << regnum) & VALID_TS_WR_REG_MASK)) 1168d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return -EINVAL; 1169d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1170d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = mutex_lock_interruptible(&dd->ipath_eep_lock); 1171d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh if (!ret) { 1172d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh ret = ipath_tempsense_internal_write(dd, regnum, data); 1173d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh mutex_unlock(&dd->ipath_eep_lock); 1174d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh } 1175d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh 1176d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh /* 1177d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * There are three possibilities here: 1178d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is 0 for success 1179d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is -ENXIO or -EINVAL from code in this file 1180d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh * ret is -EINTR from mutex_lock_interruptible. 1181d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh */ 1182d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh return ret; 1183d84e0b28d3a0b41fc574ea50d60522ae0fba75f4Michael Albaugh} 1184