// SPDX-License-Identifier: GPL-2.0-or-later /* ------------------------------------------------------------------------ * * i2c-parport.c I2C bus over parallel port * * ------------------------------------------------------------------------ * Copyright (C) 2003-2011 Jean Delvare <jdelvare@suse.de>
Based on older i2c-philips-par.c driver Copyright (C) 1995-2000 Simon G. Vogl With some changes from: Frodo Looijaard <frodol@dds.nl> Kyösti Mälkki <kmalkki@cc.hut.fi>
#define MAX_DEVICE 4 staticint parport[MAX_DEVICE] = {0, -1, -1, -1};
module_param_array(parport, int, NULL, 0);
MODULE_PARM_DESC(parport, "List of parallel ports to bind to, by index.\n" " At most " __stringify(MAX_DEVICE) " devices are supported.\n" " Default is one device connected to parport0.\n"
);
staticint type = -1;
module_param(type, int, 0);
MODULE_PARM_DESC(type, "Type of adapter:\n" " 0 = Philips adapter\n" " 1 = home brew teletext adapter\n" " 2 = Velleman K8000 adapter\n" " 3 = ELV adapter\n" " 4 = ADM1032 evaluation board\n" " 5 = ADM1025, ADM1030 and ADM1031 evaluation boards\n" " 6 = Barco LPT->DVI (K5800236) adapter\n" " 7 = One For All JP1 parallel port adapter\n" " 8 = VCT-jig\n"
);
/* ----- Low-level parallel port access ----------------------------------- */
/* Encapsulate the functions above in the correct structure. Note that this is only a template, from which the real structures are copied. The attaching code will set getscl to NULL for adapters that cannot read SCL back, and will also make the data field point to
the parallel port structure. */ staticconststruct i2c_algo_bit_data parport_algo_data = {
.setsda = parport_setsda,
.setscl = parport_setscl,
.getsda = parport_getsda,
.getscl = parport_getscl,
.udelay = 10, /* ~50 kbps */
.timeout = HZ,
};
/* ----- I2c and parallel port call-back functions and structures --------- */
if (ara) {
dev_dbg(&ara->dev, "SMBus alert received\n");
i2c_handle_smbus_alert(ara);
} else
dev_dbg(&adapter->adapter.dev, "SMBus alert received but no ARA client!\n");
}
if (type < 0) {
pr_warn("adapter type unspecified\n"); return;
}
if (type >= ARRAY_SIZE(adapter_parm)) {
pr_warn("invalid type (%d)\n", type); return;
}
for (i = 0; i < MAX_DEVICE; i++) { if (parport[i] == -1) continue; if (port->number == parport[i]) break;
} if (i == MAX_DEVICE) {
pr_debug("Not using parport%d.\n", port->number); return;
}
pr_debug("attaching to %s\n", port->name);
parport_disable_irq(port);
adapter->pdev = parport_register_dev_model(port, "i2c-parport",
&i2c_parport_cb, i); if (!adapter->pdev) {
pr_err("Unable to register with parport\n"); goto err_free;
}
/* Fill the rest of the structure */
adapter->adapter.owner = THIS_MODULE;
adapter->adapter.class = I2C_CLASS_HWMON;
strscpy(adapter->adapter.name, "Parallel port adapter", sizeof(adapter->adapter.name));
adapter->algo_data = parport_algo_data; /* Slow down if we can't sense SCL */ if (!adapter_parm[type].getscl.val) {
adapter->algo_data.getscl = NULL;
adapter->algo_data.udelay = 50; /* ~10 kbps */
}
adapter->algo_data.data = port;
adapter->adapter.algo_data = &adapter->algo_data;
adapter->adapter.dev.parent = port->physport->dev;
if (parport_claim_or_block(adapter->pdev) < 0) {
dev_err(&adapter->pdev->dev, "Could not claim parallel port\n"); goto err_unregister;
}
/* Reset hardware to a sane state (SCL and SDA high) */
parport_setsda(port, 1);
parport_setscl(port, 1); /* Other init if needed (power on...) */ if (adapter_parm[type].init.val) {
line_set(port, 1, &adapter_parm[type].init); /* Give powered devices some time to settle */
msleep(100);
}
if (i2c_bit_add_bus(&adapter->adapter) < 0) {
dev_err(&adapter->pdev->dev, "Unable to register with I2C\n"); goto err_unregister;
}
/* Setup SMBus alert if supported */ if (adapter_parm[type].smbus_alert) { struct i2c_client *ara;
ara = i2c_new_smbus_alert_device(&adapter->adapter,
&adapter->alert_data); if (!IS_ERR(ara)) {
adapter->ara = ara;
parport_enable_irq(port);
} else {
dev_warn(&adapter->pdev->dev, "Failed to register ARA client\n");
}
}
/* Add the new adapter to the list */
mutex_lock(&adapter_list_lock);
list_add_tail(&adapter->node, &adapter_list);
mutex_unlock(&adapter_list_lock); return;
/* Walk the list */
mutex_lock(&adapter_list_lock);
list_for_each_entry_safe(adapter, _n, &adapter_list, node) { if (adapter->pdev->port == port) { if (adapter->ara) {
parport_disable_irq(port);
i2c_unregister_device(adapter->ara);
}
i2c_del_adapter(&adapter->adapter);
/* Un-init if needed (power off...) */ if (adapter_parm[type].init.val)
line_set(port, 0, &adapter_parm[type].init);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.