|
@@ -50,7 +50,6 @@ struct mcp23s08_ops {
|
|
|
};
|
|
|
|
|
|
struct mcp23s08 {
|
|
|
- struct spi_device *spi;
|
|
|
u8 addr;
|
|
|
|
|
|
u16 cache[11];
|
|
@@ -60,6 +59,7 @@ struct mcp23s08 {
|
|
|
struct gpio_chip chip;
|
|
|
|
|
|
const struct mcp23s08_ops *ops;
|
|
|
+ void *data; /* ops specific data */
|
|
|
};
|
|
|
|
|
|
/* A given spi_device can represent up to eight mcp23sxx chips
|
|
@@ -73,6 +73,8 @@ struct mcp23s08_driver_data {
|
|
|
struct mcp23s08 chip[];
|
|
|
};
|
|
|
|
|
|
+#ifdef CONFIG_SPI_MASTER
|
|
|
+
|
|
|
static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
|
|
|
{
|
|
|
u8 tx[2], rx[1];
|
|
@@ -80,7 +82,7 @@ static int mcp23s08_read(struct mcp23s08 *mcp, unsigned reg)
|
|
|
|
|
|
tx[0] = mcp->addr | 0x01;
|
|
|
tx[1] = reg;
|
|
|
- status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx);
|
|
|
+ status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
|
|
|
return (status < 0) ? status : rx[0];
|
|
|
}
|
|
|
|
|
@@ -91,7 +93,7 @@ static int mcp23s08_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
|
|
|
tx[0] = mcp->addr;
|
|
|
tx[1] = reg;
|
|
|
tx[2] = val;
|
|
|
- return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
|
|
|
+ return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -106,7 +108,7 @@ mcp23s08_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
|
|
|
tx[1] = reg;
|
|
|
|
|
|
tmp = (u8 *)vals;
|
|
|
- status = spi_write_then_read(mcp->spi, tx, sizeof tx, tmp, n);
|
|
|
+ status = spi_write_then_read(mcp->data, tx, sizeof tx, tmp, n);
|
|
|
if (status >= 0) {
|
|
|
while (n--)
|
|
|
vals[n] = tmp[n]; /* expand to 16bit */
|
|
@@ -121,7 +123,7 @@ static int mcp23s17_read(struct mcp23s08 *mcp, unsigned reg)
|
|
|
|
|
|
tx[0] = mcp->addr | 0x01;
|
|
|
tx[1] = reg << 1;
|
|
|
- status = spi_write_then_read(mcp->spi, tx, sizeof tx, rx, sizeof rx);
|
|
|
+ status = spi_write_then_read(mcp->data, tx, sizeof tx, rx, sizeof rx);
|
|
|
return (status < 0) ? status : (rx[0] | (rx[1] << 8));
|
|
|
}
|
|
|
|
|
@@ -133,7 +135,7 @@ static int mcp23s17_write(struct mcp23s08 *mcp, unsigned reg, unsigned val)
|
|
|
tx[1] = reg << 1;
|
|
|
tx[2] = val;
|
|
|
tx[3] = val >> 8;
|
|
|
- return spi_write_then_read(mcp->spi, tx, sizeof tx, NULL, 0);
|
|
|
+ return spi_write_then_read(mcp->data, tx, sizeof tx, NULL, 0);
|
|
|
}
|
|
|
|
|
|
static int
|
|
@@ -147,7 +149,7 @@ mcp23s17_read_regs(struct mcp23s08 *mcp, unsigned reg, u16 *vals, unsigned n)
|
|
|
tx[0] = mcp->addr | 0x01;
|
|
|
tx[1] = reg << 1;
|
|
|
|
|
|
- status = spi_write_then_read(mcp->spi, tx, sizeof tx,
|
|
|
+ status = spi_write_then_read(mcp->data, tx, sizeof tx,
|
|
|
(u8 *)vals, n * 2);
|
|
|
if (status >= 0) {
|
|
|
while (n--)
|
|
@@ -169,6 +171,7 @@ static const struct mcp23s08_ops mcp23s17_ops = {
|
|
|
.read_regs = mcp23s17_read_regs,
|
|
|
};
|
|
|
|
|
|
+#endif /* CONFIG_SPI_MASTER */
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
@@ -296,17 +299,16 @@ done:
|
|
|
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
|
-static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr,
|
|
|
+static int mcp23s08_probe_one(struct mcp23s08 *mcp, struct device *dev,
|
|
|
+ void *data, unsigned addr,
|
|
|
unsigned type, unsigned base, unsigned pullups)
|
|
|
{
|
|
|
- struct mcp23s08_driver_data *data = spi_get_drvdata(spi);
|
|
|
- struct mcp23s08 *mcp = data->mcp[addr];
|
|
|
- int status;
|
|
|
+ int status;
|
|
|
|
|
|
mutex_init(&mcp->lock);
|
|
|
|
|
|
- mcp->spi = spi;
|
|
|
- mcp->addr = 0x40 | (addr << 1);
|
|
|
+ mcp->data = data;
|
|
|
+ mcp->addr = addr;
|
|
|
|
|
|
mcp->chip.direction_input = mcp23s08_direction_input;
|
|
|
mcp->chip.get = mcp23s08_get;
|
|
@@ -314,18 +316,29 @@ static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr,
|
|
|
mcp->chip.set = mcp23s08_set;
|
|
|
mcp->chip.dbg_show = mcp23s08_dbg_show;
|
|
|
|
|
|
- if (type == MCP_TYPE_S17) {
|
|
|
- mcp->ops = &mcp23s17_ops;
|
|
|
- mcp->chip.ngpio = 16;
|
|
|
- mcp->chip.label = "mcp23s17";
|
|
|
- } else {
|
|
|
+ switch (type) {
|
|
|
+#ifdef CONFIG_SPI_MASTER
|
|
|
+ case MCP_TYPE_S08:
|
|
|
mcp->ops = &mcp23s08_ops;
|
|
|
mcp->chip.ngpio = 8;
|
|
|
mcp->chip.label = "mcp23s08";
|
|
|
+ break;
|
|
|
+
|
|
|
+ case MCP_TYPE_S17:
|
|
|
+ mcp->ops = &mcp23s17_ops;
|
|
|
+ mcp->chip.ngpio = 16;
|
|
|
+ mcp->chip.label = "mcp23s17";
|
|
|
+ break;
|
|
|
+#endif /* CONFIG_SPI_MASTER */
|
|
|
+
|
|
|
+ default:
|
|
|
+ dev_err(dev, "invalid device type (%d)\n", type);
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
+
|
|
|
mcp->chip.base = base;
|
|
|
mcp->chip.can_sleep = 1;
|
|
|
- mcp->chip.dev = &spi->dev;
|
|
|
+ mcp->chip.dev = dev;
|
|
|
mcp->chip.owner = THIS_MODULE;
|
|
|
|
|
|
/* verify MCP_IOCON.SEQOP = 0, so sequential reads work,
|
|
@@ -371,11 +384,13 @@ static int mcp23s08_probe_one(struct spi_device *spi, unsigned addr,
|
|
|
status = gpiochip_add(&mcp->chip);
|
|
|
fail:
|
|
|
if (status < 0)
|
|
|
- dev_dbg(&spi->dev, "can't setup chip %d, --> %d\n",
|
|
|
- addr, status);
|
|
|
+ dev_dbg(dev, "can't setup chip %d, --> %d\n",
|
|
|
+ addr, status);
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
+#ifdef CONFIG_SPI_MASTER
|
|
|
+
|
|
|
static int mcp23s08_probe(struct spi_device *spi)
|
|
|
{
|
|
|
struct mcp23s08_platform_data *pdata;
|
|
@@ -418,7 +433,8 @@ static int mcp23s08_probe(struct spi_device *spi)
|
|
|
continue;
|
|
|
chips--;
|
|
|
data->mcp[addr] = &data->chip[chips];
|
|
|
- status = mcp23s08_probe_one(spi, addr, type, base,
|
|
|
+ status = mcp23s08_probe_one(data->mcp[addr], &spi->dev, spi,
|
|
|
+ 0x40 | (addr << 1), type, base,
|
|
|
pdata->chip[addr].pullups);
|
|
|
if (status < 0)
|
|
|
goto fail;
|
|
@@ -488,11 +504,28 @@ static struct spi_driver mcp23s08_driver = {
|
|
|
},
|
|
|
};
|
|
|
|
|
|
+static int __init mcp23s08_spi_init(void)
|
|
|
+{
|
|
|
+ return spi_register_driver(&mcp23s08_driver);
|
|
|
+}
|
|
|
+
|
|
|
+static void mcp23s08_spi_exit(void)
|
|
|
+{
|
|
|
+ spi_unregister_driver(&mcp23s08_driver);
|
|
|
+}
|
|
|
+
|
|
|
+#else
|
|
|
+
|
|
|
+static int __init mcp23s08_spi_init(void) { return 0; }
|
|
|
+static void mcp23s08_spi_exit(void) { }
|
|
|
+
|
|
|
+#endif /* CONFIG_SPI_MASTER */
|
|
|
+
|
|
|
/*----------------------------------------------------------------------*/
|
|
|
|
|
|
static int __init mcp23s08_init(void)
|
|
|
{
|
|
|
- return spi_register_driver(&mcp23s08_driver);
|
|
|
+ return mcp23s08_spi_init();
|
|
|
}
|
|
|
/* register after spi postcore initcall and before
|
|
|
* subsys initcalls that may rely on these GPIOs
|
|
@@ -501,7 +534,7 @@ subsys_initcall(mcp23s08_init);
|
|
|
|
|
|
static void __exit mcp23s08_exit(void)
|
|
|
{
|
|
|
- spi_unregister_driver(&mcp23s08_driver);
|
|
|
+ mcp23s08_spi_exit();
|
|
|
}
|
|
|
module_exit(mcp23s08_exit);
|
|
|
|