#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/acpi.h>
-#include <asm/io.h>
+#include <linux/io.h>
/* I801 SMBus address offsets */
#define SMBHSTSTS (0 + i801_smba)
MODULE_DEVICE_TABLE (pci, i801_ids);
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+static unsigned char apanel_addr;
+
+/* Scan the system ROM for the signature "FJKEYINF" */
+static __init const void __iomem *bios_signature(const void __iomem *bios)
+{
+ ssize_t offset;
+ const unsigned char signature[] = "FJKEYINF";
+
+ for (offset = 0; offset < 0x10000; offset += 0x10) {
+ if (check_signature(bios + offset, signature,
+ sizeof(signature)-1))
+ return bios + offset;
+ }
+ return NULL;
+}
+
+static void __init input_apanel_init(void)
+{
+ void __iomem *bios;
+ const void __iomem *p;
+
+ bios = ioremap(0xF0000, 0x10000); /* Can't fail */
+ p = bios_signature(bios);
+ if (p) {
+ /* just use the first address */
+ apanel_addr = readb(p + 8 + 3) >> 1;
+ }
+ iounmap(bios);
+}
+#else
+static void __init input_apanel_init(void) {}
+#endif
+
static int __devinit i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
unsigned char temp;
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
goto exit_release;
}
+
+ /* Register optional slaves */
+#if defined CONFIG_INPUT_APANEL || defined CONFIG_INPUT_APANEL_MODULE
+ if (apanel_addr) {
+ struct i2c_board_info info;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ info.addr = apanel_addr;
+ strlcpy(info.type, "fujitsu_apanel", I2C_NAME_SIZE);
+ i2c_new_device(&i801_adapter, &info);
+ }
+#endif
+
return 0;
exit_release:
static int __init i2c_i801_init(void)
{
+ input_apanel_init();
return pci_register_driver(&i801_driver);
}
struct apanel {
struct input_polled_dev *ipdev;
- struct i2c_client client;
+ struct i2c_client *client;
unsigned short keymap[MAX_PANEL_KEYS];
u16 nkeys;
u16 led_bits;
};
-static int apanel_probe(struct i2c_adapter *, int, int);
-
-/* for now, we only support one address */
-static unsigned short normal_i2c[] = {0, I2C_CLIENT_END};
-static unsigned short ignore = I2C_CLIENT_END;
-static struct i2c_client_address_data addr_data = {
- .normal_i2c = normal_i2c,
- .probe = &ignore,
- .ignore = &ignore,
-};
+static int apanel_probe(struct i2c_client *, const struct i2c_device_id *);
static void report_key(struct input_dev *input, unsigned keycode)
{
s32 data;
int i;
- data = i2c_smbus_read_word_data(&ap->client, cmd);
+ data = i2c_smbus_read_word_data(ap->client, cmd);
if (data < 0)
return; /* ignore errors (due to ACPI??) */
/* write back to clear latch */
- i2c_smbus_write_word_data(&ap->client, cmd, 0);
+ i2c_smbus_write_word_data(ap->client, cmd, 0);
if (!data)
return;
{
struct apanel *ap = container_of(work, struct apanel, led_work);
- i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits);
+ i2c_smbus_write_word_data(ap->client, 0x10, ap->led_bits);
}
static void mail_led_set(struct led_classdev *led,
schedule_work(&ap->led_work);
}
-static int apanel_detach_client(struct i2c_client *client)
+static int apanel_remove(struct i2c_client *client)
{
struct apanel *ap = i2c_get_clientdata(client);
led_classdev_unregister(&ap->mail_led);
input_unregister_polled_device(ap->ipdev);
- i2c_detach_client(&ap->client);
input_free_polled_device(ap->ipdev);
return 0;
}
-/* Function is invoked for every i2c adapter. */
-static int apanel_attach_adapter(struct i2c_adapter *adap)
-{
- dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id);
-
- /* Our device is connected only to i801 on laptop */
- if (adap->id != I2C_HW_SMBUS_I801)
- return -ENODEV;
-
- return i2c_probe(adap, &addr_data, apanel_probe);
-}
-
static void apanel_shutdown(struct i2c_client *client)
{
- apanel_detach_client(client);
+ apanel_remove(client);
}
+static struct i2c_device_id apanel_id[] = {
+ { "fujitsu_apanel", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, apanel_id);
+
static struct i2c_driver apanel_driver = {
.driver = {
.name = APANEL,
},
- .attach_adapter = &apanel_attach_adapter,
- .detach_client = &apanel_detach_client,
+ .probe = &apanel_probe,
+ .remove = &apanel_remove,
.shutdown = &apanel_shutdown,
+ .id_table = apanel_id,
};
static struct apanel apanel = {
- .client = {
- .driver = &apanel_driver,
- .name = APANEL,
- },
.keymap = {
[0] = KEY_MAIL,
[1] = KEY_WWW,
};
/* NB: Only one panel on the i2c. */
-static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
+static int apanel_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct apanel *ap;
struct input_polled_dev *ipdev;
u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
int i, err = -ENOMEM;
- dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n",
- bus, address, kind);
-
ap = &apanel;
ipdev = input_allocate_polled_device();
goto out1;
ap->ipdev = ipdev;
- ap->client.adapter = bus;
- ap->client.addr = address;
-
- i2c_set_clientdata(&ap->client, ap);
+ ap->client = client;
- err = i2c_attach_client(&ap->client);
- if (err)
- goto out2;
+ i2c_set_clientdata(client, ap);
- err = i2c_smbus_write_word_data(&ap->client, cmd, 0);
+ err = i2c_smbus_write_word_data(client, cmd, 0);
if (err) {
- dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n",
+ dev_warn(&client->dev, APANEL ": smbus write error %d\n",
err);
goto out3;
}
idev->name = APANEL_NAME " buttons";
idev->phys = "apanel/input0";
idev->id.bustype = BUS_HOST;
- idev->dev.parent = &ap->client.dev;
+ idev->dev.parent = &client->dev;
set_bit(EV_KEY, idev->evbit);
INIT_WORK(&ap->led_work, led_update);
if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
- err = led_classdev_register(&ap->client.dev, &ap->mail_led);
+ err = led_classdev_register(&client->dev, &ap->mail_led);
if (err)
goto out4;
}
out4:
input_unregister_polled_device(ipdev);
out3:
- i2c_detach_client(&ap->client);
-out2:
input_free_polled_device(ipdev);
out1:
return err;
void __iomem *bios;
const void __iomem *p;
u8 devno;
+ unsigned char i2c_addr;
int found = 0;
bios = ioremap(0xF0000, 0x10000); /* Can't fail */
/* just use the first address */
p += 8;
- normal_i2c[0] = readb(p+3) >> 1;
+ i2c_addr = readb(p + 3) >> 1;
for ( ; (devno = readb(p)) & 0x7f; p += 4) {
unsigned char method, slave, chip;
chip = readb(p + 2);
slave = readb(p + 3) >> 1;
- if (slave != normal_i2c[0]) {
+ if (slave != i2c_addr) {
pr_notice(APANEL ": only one SMBus slave "
"address supported, skiping device...\n");
continue;