Date: Wed, 8 Jun 2011 16:00:31 +0000 (UTC) From: Andreas Tobler <andreast@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r222860 - head/sys/dev/iicbus Message-ID: <201106081600.p58G0V6E037448@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: andreast Date: Wed Jun 8 16:00:30 2011 New Revision: 222860 URL: http://svn.freebsd.org/changeset/base/222860 Log: - Improve error handling. - Add retry loops in the i2c read/write functions. - Combied the ADC channel selection and readout of the value into one iicbus_transfer to avoid possible races. Reviewed by: nwhitehorn Modified: head/sys/dev/iicbus/ad7417.c Modified: head/sys/dev/iicbus/ad7417.c ============================================================================== --- head/sys/dev/iicbus/ad7417.c Wed Jun 8 13:23:35 2011 (r222859) +++ head/sys/dev/iicbus/ad7417.c Wed Jun 8 16:00:30 2011 (r222860) @@ -51,8 +51,6 @@ __FBSDID("$FreeBSD$"); #include <dev/ofw/ofw_bus.h> #include <powerpc/powermac/powermac_thermal.h> -#define FCU_ZERO_C_TO_K 2732 - /* CPU A/B sensors, temp and adc: AD7417. */ #define AD7417_TEMP 0x00 @@ -73,6 +71,16 @@ struct ad7417_sensor { } type; }; +struct write_data { + uint8_t reg; + uint8_t val; +}; + +struct read_data { + uint8_t reg; + uint16_t val; +}; + /* Regular bus attachment functions */ static int ad7417_probe(device_t); static int ad7417_attach(device_t); @@ -85,6 +93,8 @@ static int ad7417_read_1(device_t dev, u uint8_t *data); static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data); +static int ad7417_write_read(device_t dev, uint32_t addr, + struct write_data out, struct read_data *in); static int ad7417_diode_read(struct ad7417_sensor *sens); static int ad7417_adc_read(struct ad7417_sensor *sens); static int ad7417_sensor_read(struct ad7417_sensor *sens); @@ -118,6 +128,8 @@ static int ad7417_write(device_t dev, uint32_t addr, uint8_t reg, uint8_t *buff, int len) { unsigned char buf[4]; + int try = 0; + struct iic_msg msg[] = { { addr, IIC_M_WR, 0, buf } }; @@ -126,76 +138,134 @@ ad7417_write(device_t dev, uint32_t addr buf[0] = reg; memcpy(buf + 1, buff, len); - if (iicbus_transfer(dev, msg, 1) != 0) { - device_printf(dev, "iicbus write failed\n"); - return (EIO); + for (;;) + { + if (iicbus_transfer(dev, msg, 1) == 0) + return (0); + + if (++try > 5) { + device_printf(dev, "iicbus write failed\n"); + return (-1); + } + pause("ad7417_write", hz); } - - return (0); - } static int ad7417_read_1(device_t dev, uint32_t addr, uint8_t reg, uint8_t *data) { uint8_t buf[4]; + int err, try = 0; struct iic_msg msg[2] = { { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, { addr, IIC_M_RD, 1, buf }, }; - if (iicbus_transfer(dev, msg, 2) != 0) { - device_printf(dev, "iicbus read failed\n"); - return (EIO); + for (;;) + { + err = iicbus_transfer(dev, msg, 2); + if (err != 0) + goto retry; + + *data = *((uint8_t*)buf); + return (0); + retry: + if (++try > 5) { + device_printf(dev, "iicbus read failed\n"); + return (-1); + } + pause("ad7417_read_1", hz); } - - *data = *((uint8_t*)buf); - - return (0); } static int ad7417_read_2(device_t dev, uint32_t addr, uint8_t reg, uint16_t *data) { uint8_t buf[4]; + int err, try = 0; struct iic_msg msg[2] = { { addr, IIC_M_WR | IIC_M_NOSTOP, 1, ® }, { addr, IIC_M_RD, 2, buf }, }; - if (iicbus_transfer(dev, msg, 2) != 0) { - device_printf(dev, "iicbus read failed\n"); - return (EIO); + for (;;) + { + err = iicbus_transfer(dev, msg, 2); + if (err != 0) + goto retry; + + *data = *((uint16_t*)buf); + return (0); + retry: + if (++try > 5) { + device_printf(dev, "iicbus read failed\n"); + return (-1); + } + pause("ad7417_read_2", hz); } +} - *data = *((uint16_t*)buf); +static int +ad7417_write_read(device_t dev, uint32_t addr, struct write_data out, + struct read_data *in) +{ + uint8_t buf[4]; + int err, try = 0; - return (0); + /* Do a combined write/read. */ + struct iic_msg msg[3] = { + { addr, IIC_M_WR, 2, buf }, + { addr, IIC_M_WR | IIC_M_NOSTOP, 1, &in->reg }, + { addr, IIC_M_RD, 2, buf }, + }; + + /* Prepare the write msg. */ + buf[0] = out.reg; + buf[1] = out.val & 0xff; + + for (;;) + { + err = iicbus_transfer(dev, msg, 3); + if (err != 0) + goto retry; + + in->val = *((uint16_t*)buf); + return (0); + retry: + if (++try > 5) { + device_printf(dev, "iicbus write/read failed\n"); + return (-1); + } + pause("ad7417_write_read", hz); + } } static int ad7417_init_adc(device_t dev, uint32_t addr) { uint8_t buf; + int err; adc741x_config = 0; /* Clear Config2 */ buf = 0; - ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); + + err = ad7417_write(dev, addr, AD7417_CONFIG2, &buf, 1); /* Read & cache Config1 */ buf = 0; - ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); - - ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); + err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); + err = ad7417_read_1(dev, addr, AD7417_CONFIG, &buf); adc741x_config = (uint8_t)buf; /* Disable shutdown mode */ adc741x_config &= 0xfe; buf = adc741x_config; - ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); + err = ad7417_write(dev, addr, AD7417_CONFIG, &buf, 1); + if (err < 0) + return (-1); return (0); @@ -300,8 +370,8 @@ ad7417_fill_sensor_prop(device_t dev) continue; /* Make up some ranges */ - sc->sc_sensors[j].therm.target_temp = 500 + 2732; - sc->sc_sensors[j].therm.max_temp = 900 + 2732; + sc->sc_sensors[j].therm.target_temp = 500 + ZERO_C_TO_K; + sc->sc_sensors[j].therm.max_temp = 900 + ZERO_C_TO_K; pmac_thermal_sensor_register(&sc->sc_sensors[j].therm); } @@ -391,8 +461,13 @@ ad7417_get_temp(device_t dev, uint32_t a { uint16_t buf[2]; uint16_t read; + int err; + + err = ad7417_read_2(dev, addr, AD7417_TEMP, buf); + + if (err < 0) + return (-1); - ad7417_read_2(dev, addr, AD7417_TEMP, buf); read = *((int16_t*)buf); /* The ADC is 10 bit, the resolution is 0.25 C. @@ -406,22 +481,25 @@ static int ad7417_get_adc(device_t dev, uint32_t addr, unsigned int *value, uint8_t chan) { - uint8_t cfg1, tmp; - uint16_t read, buf[2]; - - ad7417_read_1(dev, addr, AD7417_CONFIG, &cfg1); + uint8_t tmp; + int err; + struct write_data config; + struct read_data data; tmp = chan << 5; + config.reg = AD7417_CONFIG; + data.reg = AD7417_ADC; + data.val = 0; - cfg1 = (cfg1 & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); + err = ad7417_read_1(dev, addr, AD7417_CONFIG, &config.val); - ad7417_write(dev, addr, AD7417_CONFIG, &cfg1, 1); + config.val = (config.val & ~AD7417_CONFMASK) | (tmp & AD7417_CONFMASK); - ad7417_read_2(dev, addr, AD7417_ADC, buf); + err = ad7417_write_read(dev, addr, config, &data); + if (err < 0) + return (-1); - read = *((uint16_t*)buf); - - *value = ((uint32_t)read) >> 6; + *value = ((uint32_t)data.val) >> 6; return (0); } @@ -444,6 +522,9 @@ ad7417_diode_read(struct ad7417_sensor * } rawval = ad7417_adc_read(sens); + if (rawval < 0) + return (-1); + if (strstr(sens->therm.name, "CPU B") != NULL) { diode_slope = eeprom[1][0x11] >> 16; diode_offset = (int16_t)(eeprom[1][0x11] & 0xffff) << 12; @@ -455,7 +536,7 @@ ad7417_diode_read(struct ad7417_sensor * temp = (rawval*diode_slope + diode_offset) >> 2; temp = (10*(temp >> 16)) + ((10*(temp & 0xffff)) >> 16); - return (temp + FCU_ZERO_C_TO_K); + return (temp + ZERO_C_TO_K); } static int @@ -488,7 +569,8 @@ ad7417_adc_read(struct ad7417_sensor *se chan = 1; } - ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan); + if (ad7417_get_adc(sc->sc_dev, sc->sc_addr, &temp, chan) < 0) + return (-1); return (temp); } @@ -503,11 +585,13 @@ ad7417_sensor_read(struct ad7417_sensor sc = device_get_softc(sens->dev); /* Init the ADC. */ - ad7417_init_adc(sc->sc_dev, sc->sc_addr); + if (ad7417_init_adc(sc->sc_dev, sc->sc_addr) < 0) + return (-1); if (sens->type == ADC7417_TEMP_SENSOR) { - ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp); - temp += FCU_ZERO_C_TO_K; + if (ad7417_get_temp(sc->sc_dev, sc->sc_addr, &temp) < 0) + return (-1); + temp += ZERO_C_TO_K; } else { temp = ad7417_adc_read(sens); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201106081600.p58G0V6E037448>