mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-09 14:43:16 +00:00
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:
commit
76c97e6c75
@ -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 = {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user