// SPDX-License-Identifier: GPL-2.0-only /* * linux/arch/arm/common/locomo.c * * Sharp LoCoMo support * * This file contains all generic LoCoMo support. * * All initialization functions provided here are intended to be called * from machine specific code with proper arguments when required. * * Based on sa1111.c
*/
/* M62332 output channel selection */ #define M62332_EVR_CH 1 /* M62332 volume channel number */ /* 0 : CH.1 , 1 : CH. 2 */ /* DAC send data */ #define M62332_SLAVE_ADDR 0x4e /* Slave address */ #define M62332_W_BIT 0x00 /* W bit (0 only) */ #define M62332_SUB_ADDR 0x00 /* Sub address */ #define M62332_A_BIT 0x00 /* A bit (0 only) */
/* DAC setup and hold times (expressed in us) */ #define DAC_BUS_FREE_TIME 5 /* 4.7 us */ #define DAC_START_SETUP_TIME 5 /* 4.7 us */ #define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ #define DAC_START_HOLD_TIME 5 /* 4.7 us */ #define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ #define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ #define DAC_DATA_SETUP_TIME 1 /* 250 ns */ #define DAC_DATA_HOLD_TIME 1 /* 300 ns */ #define DAC_LOW_SETUP_TIME 1 /* 300 ns */ #define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */
/* the following is the overall data for the locomo chip */ struct locomo { struct device *dev; unsignedlong phys; unsignedint irq; int irq_base;
spinlock_t lock; void __iomem *base; #ifdef CONFIG_PM void *saved_state; #endif
};
/* All the locomo devices. If offset is non-zero, the mapbase for the * locomo_dev will be set to the chip base plus offset. If offset is * zero, then the mapbase for the locomo_dev will be set to zero. An * offset of zero means the device only uses GPIOs or other helper
* functions inside this file */ staticstruct locomo_dev_info locomo_devices[] = {
{
.devid = LOCOMO_DEVID_KEYBOARD,
.irq = { IRQ_LOCOMO_KEY },
.name = "locomo-keyboard",
.offset = LOCOMO_KEYBOARD,
.length = 16,
},
{
.devid = LOCOMO_DEVID_FRONTLIGHT,
.irq = {},
.name = "locomo-frontlight",
.offset = LOCOMO_FRONTLIGHT,
.length = 8,
dev = kzalloc(sizeof(struct locomo_dev), GFP_KERNEL); if (!dev) {
ret = -ENOMEM; goto out;
}
/* * If the parent device has a DMA mask associated with it, * propagate it down to the children.
*/ if (lchip->dev->dma_mask) {
dev->dma_mask = *lchip->dev->dma_mask;
dev->dev.dma_mask = &dev->dma_mask;
}
/* * Map the whole region. This also maps the * registers for our children.
*/
lchip->base = ioremap(mem->start, PAGE_SIZE); if (!lchip->base) {
ret = -ENOMEM; goto out;
}
/* * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available.
*/ if (lchip->irq != NO_IRQ && lchip->irq_base != NO_IRQ)
locomo_setup_irq(lchip);
for (i = 0; i < ARRAY_SIZE(locomo_devices); i++)
locomo_init_one_child(lchip, &locomo_devices[i]); return 0;
if (lchip->irq != NO_IRQ) {
irq_set_chained_handler_and_data(lchip->irq, NULL, NULL);
}
iounmap(lchip->base);
kfree(lchip);
}
/** * locomo_probe - probe for a single LoCoMo chip. * @dev: platform device * * Probe for a LoCoMo chip. This must be called * before any other locomo-specific code. * * Returns: * * %-EINVAL - device's IORESOURCE_MEM not found * * %-ENXIO - could not allocate an IRQ for the device * * %-ENODEV - device not found. * * %-EBUSY - physical address already marked in-use. * * %-ENOMEM - could not allocate or iomap memory. * * %0 - successful.
*/ staticint locomo_probe(struct platform_device *dev)
{ struct resource *mem; int irq;
mem = platform_get_resource(dev, IORESOURCE_MEM, 0); if (!mem) return -EINVAL;
irq = platform_get_irq(dev, 0); if (irq < 0) return -ENXIO;
if (lchip) {
__locomo_remove(lchip);
platform_set_drvdata(dev, NULL);
}
}
/* * Not sure if this should be on the system bus or not yet. * We really want some way to register a system device at * the per-machine level, and then have this driver pick * up the registered devices.
*/ staticstruct platform_driver locomo_device_driver = {
.probe = locomo_probe,
.remove = locomo_remove, #ifdef CONFIG_PM
.suspend = locomo_suspend,
.resume = locomo_resume, #endif
.driver = {
.name = "locomo",
},
};
/* * Get the parent device driver (us) structure * from a child function device
*/ staticinlinestruct locomo *locomo_chip_driver(struct locomo_dev *ldev)
{ return (struct locomo *)dev_get_drvdata(ldev->dev.parent);
}
/* Send slave address and W bit (LSB is W bit) */
data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; for (i = 1; i <= 8; i++) {
locomo_m62332_sendbit(mapbase, data >> (8 - i));
}
/* Check A bit */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SCLOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SDAOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r |= LOCOMO_DAC_SCLOEB;
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */
udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */
printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); goto out;
}
/* Send Sub address (LSB is channel select) */ /* channel = 0 : ch1 select */ /* = 1 : ch2 select */
data = M62332_SUB_ADDR + channel; for (i = 1; i <= 8; i++) {
locomo_m62332_sendbit(mapbase, data >> (8 - i));
}
/* Check A bit */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SCLOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SDAOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r |= LOCOMO_DAC_SCLOEB;
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */
udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */
printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); goto out;
}
/* Send DAC data */ for (i = 1; i <= 8; i++) {
locomo_m62332_sendbit(mapbase, dac_data >> (8 - i));
}
/* Check A bit */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SCLOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r &= ~(LOCOMO_DAC_SDAOEB);
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */
r = locomo_readl(mapbase + LOCOMO_DAC);
r |= LOCOMO_DAC_SCLOEB;
locomo_writel(r, mapbase + LOCOMO_DAC);
udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */
udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */
printk(KERN_WARNING "locomo: m62332_senddata Error 3\n");
}
/* * LoCoMo "Register Access Bus." * * We model this as a regular bus type, and hang devices directly * off this.
*/ staticint locomo_match(struct device *_dev, conststruct device_driver *_drv)
{ struct locomo_dev *dev = LOCOMO_DEV(_dev); conststruct locomo_driver *drv = LOCOMO_DRV(_drv);
return dev->devid == drv->devid;
}
staticint locomo_bus_probe(struct device *dev)
{ struct locomo_dev *ldev = LOCOMO_DEV(dev); struct locomo_driver *drv = LOCOMO_DRV(dev->driver); int ret = -ENODEV;
if (drv->probe)
ret = drv->probe(ldev); return ret;
}
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.