Fix timing problems in applesmc driver

Improve device removal in jc42 driver
 Fix build warning in acp_power_meter driver
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.11 (GNU/Linux)
 
 iQIcBAABAgAGBQJQFEikAAoJEMsfJm/On5mBZzMP/jMKhWUn+4p1a17NDj5hpdIF
 btCrsJvGN2ZyzzwzeB+3ymjDK83//yahH0heQFGhrhnIwFuevPX9wVmfU3roj20u
 Wpsc/9t1cBL17V0SDQ00lUAOcTRqinT7CHBPGExZLiwWZMNUF+SD/l5QEu64Oqav
 uFkF/a2yl6MullsOQfEVd2gziNI3GMf0mIXrvhN91qxCvCjBI+bzlIQuHU1nQfJG
 dX1zDdfKX9uXwtOOa2fTEpk8QXRduBa6v6hvW/jkW0OV6t4sLeM/iPIqH00I/Vq1
 SpO08R5dsjqBpCwp8zVKKfQQgRSJfilmJHH3bCTwx6NIPWEYY7ZHUMhrRJUQxGch
 okj0yVTGbcD8yr46HfauoNFpthp/AY9FFwwGBpObaS24SiUWySKxQS3lR7Wh7gfI
 tmNpejoU8eVhgtlN4TBPGQhFsiXewCDkuwd9ocoFJ3jvVggN6wP0ioAn7eFYBQJ3
 3Glp3ocSvY1VfJw2qJVRmsUroMNin12ORGrVeaprTPobFNN4FqSiPEcqAqitOS5T
 iFULihzrLz0eXuiQoispvI7gUnI7/NQZF/6L5UGadAX7kfKS9U40XdC5dp+H5FOx
 GR6RWqIASMAwKK+PHxjAZ0jnDQvFWM85QEZsnLwAT6zmlDgIGjgQsxUqqwOu281S
 xo8kV9ljhSYFD18q6lzv
 =nt8q
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - Fix timing problems in applesmc driver

 - Improve device removal in jc42 driver

 - Fix build warning in acp_power_meter driver

* tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (applesmc) Decode and act on read/write status codes
  hwmon: (jc42) Don't reset hysteresis on device removal
  hwmon: (jc42) Simplify hysteresis mask
  hwmon: (acpi_power_meter) Fix build warning
This commit is contained in:
Linus Torvalds 2012-07-30 09:58:10 -07:00
commit 76c97e6c75
3 changed files with 71 additions and 39 deletions

View file

@ -927,6 +927,8 @@ static int acpi_power_meter_remove(struct acpi_device *device, int type)
return 0;
}
#ifdef CONFIG_PM_SLEEP
static int acpi_power_meter_resume(struct device *dev)
{
struct acpi_power_meter_resource *resource;
@ -944,6 +946,8 @@ static int acpi_power_meter_resume(struct device *dev)
return 0;
}
#endif /* CONFIG_PM_SLEEP */
static SIMPLE_DEV_PM_OPS(acpi_power_meter_pm, NULL, acpi_power_meter_resume);
static struct acpi_driver acpi_power_meter_driver = {

View file

@ -55,9 +55,9 @@
/* wait up to 32 ms for a status change. */
#define APPLESMC_MIN_WAIT 0x0010
#define APPLESMC_RETRY_WAIT 0x0100
#define APPLESMC_MAX_WAIT 0x8000
#define APPLESMC_STATUS_MASK 0x0f
#define APPLESMC_READ_CMD 0x10
#define APPLESMC_WRITE_CMD 0x11
#define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12
@ -162,51 +162,68 @@ static unsigned int key_at_index;
static struct workqueue_struct *applesmc_led_wq;
/*
* __wait_status - Wait up to 32ms for the status port to get a certain value
* (masked with 0x0f), returning zero if the value is obtained. Callers must
* wait_read - Wait for a byte to appear on SMC port. Callers must
* hold applesmc_lock.
*/
static int __wait_status(u8 val)
static int wait_read(void)
{
u8 status;
int us;
val = val & APPLESMC_STATUS_MASK;
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
udelay(us);
if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == val)
status = inb(APPLESMC_CMD_PORT);
/* read: wait for smc to settle */
if (status & 0x01)
return 0;
}
pr_warn("wait_read() fail: 0x%02x\n", status);
return -EIO;
}
/*
* special treatment of command port - on newer macbooks, it seems necessary
* to resend the command byte before polling the status again. Callers must
* hold applesmc_lock.
* send_byte - Write to SMC port, retrying when necessary. Callers
* must hold applesmc_lock.
*/
static int send_byte(u8 cmd, u16 port)
{
u8 status;
int us;
outb(cmd, port);
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
udelay(us);
status = inb(APPLESMC_CMD_PORT);
/* write: wait for smc to settle */
if (status & 0x02)
continue;
/* ready: cmd accepted, return */
if (status & 0x04)
return 0;
/* timeout: give up */
if (us << 1 == APPLESMC_MAX_WAIT)
break;
/* busy: long wait and resend */
udelay(APPLESMC_RETRY_WAIT);
outb(cmd, port);
}
pr_warn("send_byte(0x%02x, 0x%04x) fail: 0x%02x\n", cmd, port, status);
return -EIO;
}
static int send_command(u8 cmd)
{
int us;
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
outb(cmd, APPLESMC_CMD_PORT);
udelay(us);
if ((inb(APPLESMC_CMD_PORT) & APPLESMC_STATUS_MASK) == 0x0c)
return 0;
}
return -EIO;
return send_byte(cmd, APPLESMC_CMD_PORT);
}
static int send_argument(const char *key)
{
int i;
for (i = 0; i < 4; i++) {
outb(key[i], APPLESMC_DATA_PORT);
if (__wait_status(0x04))
for (i = 0; i < 4; i++)
if (send_byte(key[i], APPLESMC_DATA_PORT))
return -EIO;
}
return 0;
}
@ -219,11 +236,14 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
return -EIO;
}
outb(len, APPLESMC_DATA_PORT);
if (send_byte(len, APPLESMC_DATA_PORT)) {
pr_warn("%.4s: read len fail\n", key);
return -EIO;
}
for (i = 0; i < len; i++) {
if (__wait_status(0x05)) {
pr_warn("%.4s: read data fail\n", key);
if (wait_read()) {
pr_warn("%.4s: read data[%d] fail\n", key, i);
return -EIO;
}
buffer[i] = inb(APPLESMC_DATA_PORT);
@ -241,14 +261,16 @@ static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
return -EIO;
}
outb(len, APPLESMC_DATA_PORT);
if (send_byte(len, APPLESMC_DATA_PORT)) {
pr_warn("%.4s: write len fail\n", key);
return -EIO;
}
for (i = 0; i < len; i++) {
if (__wait_status(0x04)) {
if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
pr_warn("%s: write data fail\n", key);
return -EIO;
}
outb(buffer[i], APPLESMC_DATA_PORT);
}
return 0;

View file

@ -57,7 +57,7 @@ static const unsigned short normal_i2c[] = {
#define JC42_CFG_EVENT_LOCK (1 << 7)
#define JC42_CFG_SHUTDOWN (1 << 8)
#define JC42_CFG_HYST_SHIFT 9
#define JC42_CFG_HYST_MASK 0x03
#define JC42_CFG_HYST_MASK (0x03 << 9)
/* Capabilities */
#define JC42_CAP_RANGE (1 << 2)
@ -287,8 +287,8 @@ static ssize_t show_temp_crit_hyst(struct device *dev,
return PTR_ERR(data);
temp = jc42_temp_from_reg(data->temp_crit);
hyst = jc42_hysteresis[(data->config >> JC42_CFG_HYST_SHIFT)
& JC42_CFG_HYST_MASK];
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
>> JC42_CFG_HYST_SHIFT];
return sprintf(buf, "%d\n", temp - hyst);
}
@ -302,8 +302,8 @@ static ssize_t show_temp_max_hyst(struct device *dev,
return PTR_ERR(data);
temp = jc42_temp_from_reg(data->temp_max);
hyst = jc42_hysteresis[(data->config >> JC42_CFG_HYST_SHIFT)
& JC42_CFG_HYST_MASK];
hyst = jc42_hysteresis[(data->config & JC42_CFG_HYST_MASK)
>> JC42_CFG_HYST_SHIFT];
return sprintf(buf, "%d\n", temp - hyst);
}
@ -362,8 +362,7 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
}
mutex_lock(&data->update_lock);
data->config = (data->config
& ~(JC42_CFG_HYST_MASK << JC42_CFG_HYST_SHIFT))
data->config = (data->config & ~JC42_CFG_HYST_MASK)
| (hyst << JC42_CFG_HYST_SHIFT);
err = i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG,
data->config);
@ -535,9 +534,16 @@ static int jc42_remove(struct i2c_client *client)
struct jc42_data *data = i2c_get_clientdata(client);
hwmon_device_unregister(data->hwmon_dev);
sysfs_remove_group(&client->dev.kobj, &jc42_group);
if (data->config != data->orig_config)
i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG,
data->orig_config);
/* Restore original configuration except hysteresis */
if ((data->config & ~JC42_CFG_HYST_MASK) !=
(data->orig_config & ~JC42_CFG_HYST_MASK)) {
int config;
config = (data->orig_config & ~JC42_CFG_HYST_MASK)
| (data->config & JC42_CFG_HYST_MASK);
i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
}
return 0;
}