18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * linux/arch/arm/common/locomo.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Sharp LoCoMo support 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This file contains all generic LoCoMo support. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * All initialization functions provided here are intended to be called 108c2ecf20Sopenharmony_ci * from machine specific code with proper arguments when required. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * Based on sa1111.c 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/kernel.h> 188c2ecf20Sopenharmony_ci#include <linux/delay.h> 198c2ecf20Sopenharmony_ci#include <linux/errno.h> 208c2ecf20Sopenharmony_ci#include <linux/ioport.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/slab.h> 238c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 248c2ecf20Sopenharmony_ci#include <linux/io.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <mach/hardware.h> 278c2ecf20Sopenharmony_ci#include <asm/irq.h> 288c2ecf20Sopenharmony_ci#include <asm/mach/irq.h> 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#include <asm/hardware/locomo.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci/* LoCoMo Interrupts */ 338c2ecf20Sopenharmony_ci#define IRQ_LOCOMO_KEY (0) 348c2ecf20Sopenharmony_ci#define IRQ_LOCOMO_GPIO (1) 358c2ecf20Sopenharmony_ci#define IRQ_LOCOMO_LT (2) 368c2ecf20Sopenharmony_ci#define IRQ_LOCOMO_SPI (3) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci/* M62332 output channel selection */ 398c2ecf20Sopenharmony_ci#define M62332_EVR_CH 1 /* M62332 volume channel number */ 408c2ecf20Sopenharmony_ci /* 0 : CH.1 , 1 : CH. 2 */ 418c2ecf20Sopenharmony_ci/* DAC send data */ 428c2ecf20Sopenharmony_ci#define M62332_SLAVE_ADDR 0x4e /* Slave address */ 438c2ecf20Sopenharmony_ci#define M62332_W_BIT 0x00 /* W bit (0 only) */ 448c2ecf20Sopenharmony_ci#define M62332_SUB_ADDR 0x00 /* Sub address */ 458c2ecf20Sopenharmony_ci#define M62332_A_BIT 0x00 /* A bit (0 only) */ 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci/* DAC setup and hold times (expressed in us) */ 488c2ecf20Sopenharmony_ci#define DAC_BUS_FREE_TIME 5 /* 4.7 us */ 498c2ecf20Sopenharmony_ci#define DAC_START_SETUP_TIME 5 /* 4.7 us */ 508c2ecf20Sopenharmony_ci#define DAC_STOP_SETUP_TIME 4 /* 4.0 us */ 518c2ecf20Sopenharmony_ci#define DAC_START_HOLD_TIME 5 /* 4.7 us */ 528c2ecf20Sopenharmony_ci#define DAC_SCL_LOW_HOLD_TIME 5 /* 4.7 us */ 538c2ecf20Sopenharmony_ci#define DAC_SCL_HIGH_HOLD_TIME 4 /* 4.0 us */ 548c2ecf20Sopenharmony_ci#define DAC_DATA_SETUP_TIME 1 /* 250 ns */ 558c2ecf20Sopenharmony_ci#define DAC_DATA_HOLD_TIME 1 /* 300 ns */ 568c2ecf20Sopenharmony_ci#define DAC_LOW_SETUP_TIME 1 /* 300 ns */ 578c2ecf20Sopenharmony_ci#define DAC_HIGH_SETUP_TIME 1 /* 1000 ns */ 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci/* the following is the overall data for the locomo chip */ 608c2ecf20Sopenharmony_cistruct locomo { 618c2ecf20Sopenharmony_ci struct device *dev; 628c2ecf20Sopenharmony_ci unsigned long phys; 638c2ecf20Sopenharmony_ci unsigned int irq; 648c2ecf20Sopenharmony_ci int irq_base; 658c2ecf20Sopenharmony_ci spinlock_t lock; 668c2ecf20Sopenharmony_ci void __iomem *base; 678c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 688c2ecf20Sopenharmony_ci void *saved_state; 698c2ecf20Sopenharmony_ci#endif 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistruct locomo_dev_info { 738c2ecf20Sopenharmony_ci unsigned long offset; 748c2ecf20Sopenharmony_ci unsigned long length; 758c2ecf20Sopenharmony_ci unsigned int devid; 768c2ecf20Sopenharmony_ci unsigned int irq[1]; 778c2ecf20Sopenharmony_ci const char * name; 788c2ecf20Sopenharmony_ci}; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci/* All the locomo devices. If offset is non-zero, the mapbase for the 818c2ecf20Sopenharmony_ci * locomo_dev will be set to the chip base plus offset. If offset is 828c2ecf20Sopenharmony_ci * zero, then the mapbase for the locomo_dev will be set to zero. An 838c2ecf20Sopenharmony_ci * offset of zero means the device only uses GPIOs or other helper 848c2ecf20Sopenharmony_ci * functions inside this file */ 858c2ecf20Sopenharmony_cistatic struct locomo_dev_info locomo_devices[] = { 868c2ecf20Sopenharmony_ci { 878c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_KEYBOARD, 888c2ecf20Sopenharmony_ci .irq = { IRQ_LOCOMO_KEY }, 898c2ecf20Sopenharmony_ci .name = "locomo-keyboard", 908c2ecf20Sopenharmony_ci .offset = LOCOMO_KEYBOARD, 918c2ecf20Sopenharmony_ci .length = 16, 928c2ecf20Sopenharmony_ci }, 938c2ecf20Sopenharmony_ci { 948c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_FRONTLIGHT, 958c2ecf20Sopenharmony_ci .irq = {}, 968c2ecf20Sopenharmony_ci .name = "locomo-frontlight", 978c2ecf20Sopenharmony_ci .offset = LOCOMO_FRONTLIGHT, 988c2ecf20Sopenharmony_ci .length = 8, 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci }, 1018c2ecf20Sopenharmony_ci { 1028c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_BACKLIGHT, 1038c2ecf20Sopenharmony_ci .irq = {}, 1048c2ecf20Sopenharmony_ci .name = "locomo-backlight", 1058c2ecf20Sopenharmony_ci .offset = LOCOMO_BACKLIGHT, 1068c2ecf20Sopenharmony_ci .length = 8, 1078c2ecf20Sopenharmony_ci }, 1088c2ecf20Sopenharmony_ci { 1098c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_AUDIO, 1108c2ecf20Sopenharmony_ci .irq = {}, 1118c2ecf20Sopenharmony_ci .name = "locomo-audio", 1128c2ecf20Sopenharmony_ci .offset = LOCOMO_AUDIO, 1138c2ecf20Sopenharmony_ci .length = 4, 1148c2ecf20Sopenharmony_ci }, 1158c2ecf20Sopenharmony_ci { 1168c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_LED, 1178c2ecf20Sopenharmony_ci .irq = {}, 1188c2ecf20Sopenharmony_ci .name = "locomo-led", 1198c2ecf20Sopenharmony_ci .offset = LOCOMO_LED, 1208c2ecf20Sopenharmony_ci .length = 8, 1218c2ecf20Sopenharmony_ci }, 1228c2ecf20Sopenharmony_ci { 1238c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_UART, 1248c2ecf20Sopenharmony_ci .irq = {}, 1258c2ecf20Sopenharmony_ci .name = "locomo-uart", 1268c2ecf20Sopenharmony_ci .offset = 0, 1278c2ecf20Sopenharmony_ci .length = 0, 1288c2ecf20Sopenharmony_ci }, 1298c2ecf20Sopenharmony_ci { 1308c2ecf20Sopenharmony_ci .devid = LOCOMO_DEVID_SPI, 1318c2ecf20Sopenharmony_ci .irq = {}, 1328c2ecf20Sopenharmony_ci .name = "locomo-spi", 1338c2ecf20Sopenharmony_ci .offset = LOCOMO_SPI, 1348c2ecf20Sopenharmony_ci .length = 0x30, 1358c2ecf20Sopenharmony_ci }, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic void locomo_handler(struct irq_desc *desc) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci struct locomo *lchip = irq_desc_get_handler_data(desc); 1418c2ecf20Sopenharmony_ci int req, i; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci /* Acknowledge the parent IRQ */ 1448c2ecf20Sopenharmony_ci desc->irq_data.chip->irq_ack(&desc->irq_data); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* check why this interrupt was generated */ 1478c2ecf20Sopenharmony_ci req = locomo_readl(lchip->base + LOCOMO_ICR) & 0x0f00; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci if (req) { 1508c2ecf20Sopenharmony_ci unsigned int irq; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci /* generate the next interrupt(s) */ 1538c2ecf20Sopenharmony_ci irq = lchip->irq_base; 1548c2ecf20Sopenharmony_ci for (i = 0; i <= 3; i++, irq++) { 1558c2ecf20Sopenharmony_ci if (req & (0x0100 << i)) { 1568c2ecf20Sopenharmony_ci generic_handle_irq(irq); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic void locomo_ack_irq(struct irq_data *d) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_cistatic void locomo_mask_irq(struct irq_data *d) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci struct locomo *lchip = irq_data_get_irq_chip_data(d); 1708c2ecf20Sopenharmony_ci unsigned int r; 1718c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_ICR); 1728c2ecf20Sopenharmony_ci r &= ~(0x0010 << (d->irq - lchip->irq_base)); 1738c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_ICR); 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void locomo_unmask_irq(struct irq_data *d) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci struct locomo *lchip = irq_data_get_irq_chip_data(d); 1798c2ecf20Sopenharmony_ci unsigned int r; 1808c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_ICR); 1818c2ecf20Sopenharmony_ci r |= (0x0010 << (d->irq - lchip->irq_base)); 1828c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_ICR); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic struct irq_chip locomo_chip = { 1868c2ecf20Sopenharmony_ci .name = "LOCOMO", 1878c2ecf20Sopenharmony_ci .irq_ack = locomo_ack_irq, 1888c2ecf20Sopenharmony_ci .irq_mask = locomo_mask_irq, 1898c2ecf20Sopenharmony_ci .irq_unmask = locomo_unmask_irq, 1908c2ecf20Sopenharmony_ci}; 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_cistatic void locomo_setup_irq(struct locomo *lchip) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci int irq = lchip->irq_base; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* 1978c2ecf20Sopenharmony_ci * Install handler for IRQ_LOCOMO_HW. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci irq_set_irq_type(lchip->irq, IRQ_TYPE_EDGE_FALLING); 2008c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(lchip->irq, locomo_handler, lchip); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci /* Install handlers for IRQ_LOCOMO_* */ 2038c2ecf20Sopenharmony_ci for ( ; irq <= lchip->irq_base + 3; irq++) { 2048c2ecf20Sopenharmony_ci irq_set_chip_and_handler(irq, &locomo_chip, handle_level_irq); 2058c2ecf20Sopenharmony_ci irq_set_chip_data(irq, lchip); 2068c2ecf20Sopenharmony_ci irq_clear_status_flags(irq, IRQ_NOREQUEST | IRQ_NOPROBE); 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic void locomo_dev_release(struct device *_dev) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct locomo_dev *dev = LOCOMO_DEV(_dev); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci kfree(dev); 2168c2ecf20Sopenharmony_ci} 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic int 2198c2ecf20Sopenharmony_cilocomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci struct locomo_dev *dev; 2228c2ecf20Sopenharmony_ci int ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci dev = kzalloc(sizeof(struct locomo_dev), GFP_KERNEL); 2258c2ecf20Sopenharmony_ci if (!dev) { 2268c2ecf20Sopenharmony_ci ret = -ENOMEM; 2278c2ecf20Sopenharmony_ci goto out; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * If the parent device has a DMA mask associated with it, 2328c2ecf20Sopenharmony_ci * propagate it down to the children. 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ci if (lchip->dev->dma_mask) { 2358c2ecf20Sopenharmony_ci dev->dma_mask = *lchip->dev->dma_mask; 2368c2ecf20Sopenharmony_ci dev->dev.dma_mask = &dev->dma_mask; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci dev_set_name(&dev->dev, "%s", info->name); 2408c2ecf20Sopenharmony_ci dev->devid = info->devid; 2418c2ecf20Sopenharmony_ci dev->dev.parent = lchip->dev; 2428c2ecf20Sopenharmony_ci dev->dev.bus = &locomo_bus_type; 2438c2ecf20Sopenharmony_ci dev->dev.release = locomo_dev_release; 2448c2ecf20Sopenharmony_ci dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci if (info->offset) 2478c2ecf20Sopenharmony_ci dev->mapbase = lchip->base + info->offset; 2488c2ecf20Sopenharmony_ci else 2498c2ecf20Sopenharmony_ci dev->mapbase = 0; 2508c2ecf20Sopenharmony_ci dev->length = info->length; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev->irq[0] = (lchip->irq_base == NO_IRQ) ? 2538c2ecf20Sopenharmony_ci NO_IRQ : lchip->irq_base + info->irq[0]; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci ret = device_register(&dev->dev); 2568c2ecf20Sopenharmony_ci if (ret) { 2578c2ecf20Sopenharmony_ci out: 2588c2ecf20Sopenharmony_ci kfree(dev); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci return ret; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistruct locomo_save_data { 2668c2ecf20Sopenharmony_ci u16 LCM_GPO; 2678c2ecf20Sopenharmony_ci u16 LCM_SPICT; 2688c2ecf20Sopenharmony_ci u16 LCM_GPE; 2698c2ecf20Sopenharmony_ci u16 LCM_ASD; 2708c2ecf20Sopenharmony_ci u16 LCM_SPIMD; 2718c2ecf20Sopenharmony_ci}; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int locomo_suspend(struct platform_device *dev, pm_message_t state) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct locomo *lchip = platform_get_drvdata(dev); 2768c2ecf20Sopenharmony_ci struct locomo_save_data *save; 2778c2ecf20Sopenharmony_ci unsigned long flags; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL); 2808c2ecf20Sopenharmony_ci if (!save) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci lchip->saved_state = save; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */ 2888c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_GPO); 2898c2ecf20Sopenharmony_ci save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPICT); /* SPI */ 2908c2ecf20Sopenharmony_ci locomo_writel(0x40, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); 2918c2ecf20Sopenharmony_ci save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */ 2928c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_GPE); 2938c2ecf20Sopenharmony_ci save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */ 2948c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_ASD); 2958c2ecf20Sopenharmony_ci save->LCM_SPIMD = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); /* SPI */ 2968c2ecf20Sopenharmony_ci locomo_writel(0x3C14, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_PAIF); 2998c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_DAC); 3008c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if ((locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88)) 3038c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_C32K); /* CLK32 off */ 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci /* 18MHz already enabled, so no wait */ 3068c2ecf20Sopenharmony_ci locomo_writel(0xc1, lchip->base + LOCOMO_C32K); /* CLK32 on */ 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_TADC); /* 18MHz clock off*/ 3098c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC); /* 22MHz/24MHz clock off */ 3108c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); /* FL */ 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int locomo_resume(struct platform_device *dev) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci struct locomo *lchip = platform_get_drvdata(dev); 3208c2ecf20Sopenharmony_ci struct locomo_save_data *save; 3218c2ecf20Sopenharmony_ci unsigned long r; 3228c2ecf20Sopenharmony_ci unsigned long flags; 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci save = lchip->saved_state; 3258c2ecf20Sopenharmony_ci if (!save) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO); 3318c2ecf20Sopenharmony_ci locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); 3328c2ecf20Sopenharmony_ci locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE); 3338c2ecf20Sopenharmony_ci locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD); 3348c2ecf20Sopenharmony_ci locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci locomo_writel(0x00, lchip->base + LOCOMO_C32K); 3378c2ecf20Sopenharmony_ci locomo_writel(0x90, lchip->base + LOCOMO_TADC); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC); 3408c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); 3418c2ecf20Sopenharmony_ci r &= 0xFEFF; 3428c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); 3438c2ecf20Sopenharmony_ci locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci lchip->saved_state = NULL; 3488c2ecf20Sopenharmony_ci kfree(save); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci return 0; 3518c2ecf20Sopenharmony_ci} 3528c2ecf20Sopenharmony_ci#endif 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci/** 3568c2ecf20Sopenharmony_ci * locomo_probe - probe for a single LoCoMo chip. 3578c2ecf20Sopenharmony_ci * @phys_addr: physical address of device. 3588c2ecf20Sopenharmony_ci * 3598c2ecf20Sopenharmony_ci * Probe for a LoCoMo chip. This must be called 3608c2ecf20Sopenharmony_ci * before any other locomo-specific code. 3618c2ecf20Sopenharmony_ci * 3628c2ecf20Sopenharmony_ci * Returns: 3638c2ecf20Sopenharmony_ci * %-ENODEV device not found. 3648c2ecf20Sopenharmony_ci * %-EBUSY physical address already marked in-use. 3658c2ecf20Sopenharmony_ci * %0 successful. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_cistatic int 3688c2ecf20Sopenharmony_ci__locomo_probe(struct device *me, struct resource *mem, int irq) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct locomo_platform_data *pdata = me->platform_data; 3718c2ecf20Sopenharmony_ci struct locomo *lchip; 3728c2ecf20Sopenharmony_ci unsigned long r; 3738c2ecf20Sopenharmony_ci int i, ret = -ENODEV; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci lchip = kzalloc(sizeof(struct locomo), GFP_KERNEL); 3768c2ecf20Sopenharmony_ci if (!lchip) 3778c2ecf20Sopenharmony_ci return -ENOMEM; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci spin_lock_init(&lchip->lock); 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci lchip->dev = me; 3828c2ecf20Sopenharmony_ci dev_set_drvdata(lchip->dev, lchip); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci lchip->phys = mem->start; 3858c2ecf20Sopenharmony_ci lchip->irq = irq; 3868c2ecf20Sopenharmony_ci lchip->irq_base = (pdata) ? pdata->irq_base : NO_IRQ; 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci /* 3898c2ecf20Sopenharmony_ci * Map the whole region. This also maps the 3908c2ecf20Sopenharmony_ci * registers for our children. 3918c2ecf20Sopenharmony_ci */ 3928c2ecf20Sopenharmony_ci lchip->base = ioremap(mem->start, PAGE_SIZE); 3938c2ecf20Sopenharmony_ci if (!lchip->base) { 3948c2ecf20Sopenharmony_ci ret = -ENOMEM; 3958c2ecf20Sopenharmony_ci goto out; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* locomo initialize */ 3998c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_ICR); 4008c2ecf20Sopenharmony_ci /* KEYBOARD */ 4018c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci /* GPIO */ 4048c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_GPO); 4058c2ecf20Sopenharmony_ci locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) 4068c2ecf20Sopenharmony_ci , lchip->base + LOCOMO_GPE); 4078c2ecf20Sopenharmony_ci locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) 4088c2ecf20Sopenharmony_ci , lchip->base + LOCOMO_GPD); 4098c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_GIE); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* Frontlight */ 4128c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); 4138c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci /* Longtime timer */ 4168c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_LTINT); 4178c2ecf20Sopenharmony_ci /* SPI */ 4188c2ecf20Sopenharmony_ci locomo_writel(0, lchip->base + LOCOMO_SPI + LOCOMO_SPIIE); 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); 4218c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_ASD); 4228c2ecf20Sopenharmony_ci r |= 0x8000; 4238c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_ASD); 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); 4268c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_HSD); 4278c2ecf20Sopenharmony_ci r |= 0x8000; 4288c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_HSD); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci /* XON */ 4338c2ecf20Sopenharmony_ci locomo_writel(0x80, lchip->base + LOCOMO_TADC); 4348c2ecf20Sopenharmony_ci udelay(1000); 4358c2ecf20Sopenharmony_ci /* CLK9MEN */ 4368c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_TADC); 4378c2ecf20Sopenharmony_ci r |= 0x10; 4388c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_TADC); 4398c2ecf20Sopenharmony_ci udelay(100); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* init DAC */ 4428c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_DAC); 4438c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; 4448c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_DAC); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_VER); 4478c2ecf20Sopenharmony_ci printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff)); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * The interrupt controller must be initialised before any 4518c2ecf20Sopenharmony_ci * other device to ensure that the interrupts are available. 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci if (lchip->irq != NO_IRQ && lchip->irq_base != NO_IRQ) 4548c2ecf20Sopenharmony_ci locomo_setup_irq(lchip); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(locomo_devices); i++) 4578c2ecf20Sopenharmony_ci locomo_init_one_child(lchip, &locomo_devices[i]); 4588c2ecf20Sopenharmony_ci return 0; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci out: 4618c2ecf20Sopenharmony_ci kfree(lchip); 4628c2ecf20Sopenharmony_ci return ret; 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_cistatic int locomo_remove_child(struct device *dev, void *data) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci device_unregister(dev); 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci} 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic void __locomo_remove(struct locomo *lchip) 4728c2ecf20Sopenharmony_ci{ 4738c2ecf20Sopenharmony_ci device_for_each_child(lchip->dev, NULL, locomo_remove_child); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci if (lchip->irq != NO_IRQ) { 4768c2ecf20Sopenharmony_ci irq_set_chained_handler_and_data(lchip->irq, NULL, NULL); 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci iounmap(lchip->base); 4808c2ecf20Sopenharmony_ci kfree(lchip); 4818c2ecf20Sopenharmony_ci} 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_cistatic int locomo_probe(struct platform_device *dev) 4848c2ecf20Sopenharmony_ci{ 4858c2ecf20Sopenharmony_ci struct resource *mem; 4868c2ecf20Sopenharmony_ci int irq; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci mem = platform_get_resource(dev, IORESOURCE_MEM, 0); 4898c2ecf20Sopenharmony_ci if (!mem) 4908c2ecf20Sopenharmony_ci return -EINVAL; 4918c2ecf20Sopenharmony_ci irq = platform_get_irq(dev, 0); 4928c2ecf20Sopenharmony_ci if (irq < 0) 4938c2ecf20Sopenharmony_ci return -ENXIO; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci return __locomo_probe(&dev->dev, mem, irq); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic int locomo_remove(struct platform_device *dev) 4998c2ecf20Sopenharmony_ci{ 5008c2ecf20Sopenharmony_ci struct locomo *lchip = platform_get_drvdata(dev); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (lchip) { 5038c2ecf20Sopenharmony_ci __locomo_remove(lchip); 5048c2ecf20Sopenharmony_ci platform_set_drvdata(dev, NULL); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci/* 5118c2ecf20Sopenharmony_ci * Not sure if this should be on the system bus or not yet. 5128c2ecf20Sopenharmony_ci * We really want some way to register a system device at 5138c2ecf20Sopenharmony_ci * the per-machine level, and then have this driver pick 5148c2ecf20Sopenharmony_ci * up the registered devices. 5158c2ecf20Sopenharmony_ci */ 5168c2ecf20Sopenharmony_cistatic struct platform_driver locomo_device_driver = { 5178c2ecf20Sopenharmony_ci .probe = locomo_probe, 5188c2ecf20Sopenharmony_ci .remove = locomo_remove, 5198c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 5208c2ecf20Sopenharmony_ci .suspend = locomo_suspend, 5218c2ecf20Sopenharmony_ci .resume = locomo_resume, 5228c2ecf20Sopenharmony_ci#endif 5238c2ecf20Sopenharmony_ci .driver = { 5248c2ecf20Sopenharmony_ci .name = "locomo", 5258c2ecf20Sopenharmony_ci }, 5268c2ecf20Sopenharmony_ci}; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci/* 5298c2ecf20Sopenharmony_ci * Get the parent device driver (us) structure 5308c2ecf20Sopenharmony_ci * from a child function device 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_cistatic inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci return (struct locomo *)dev_get_drvdata(ldev->dev.parent); 5358c2ecf20Sopenharmony_ci} 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_civoid locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci struct locomo *lchip = dev_get_drvdata(dev); 5408c2ecf20Sopenharmony_ci unsigned long flags; 5418c2ecf20Sopenharmony_ci unsigned int r; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci if (!lchip) 5448c2ecf20Sopenharmony_ci return; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_GPD); 5498c2ecf20Sopenharmony_ci if (dir) 5508c2ecf20Sopenharmony_ci r |= bits; 5518c2ecf20Sopenharmony_ci else 5528c2ecf20Sopenharmony_ci r &= ~bits; 5538c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_GPD); 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_GPE); 5568c2ecf20Sopenharmony_ci if (dir) 5578c2ecf20Sopenharmony_ci r |= bits; 5588c2ecf20Sopenharmony_ci else 5598c2ecf20Sopenharmony_ci r &= ~bits; 5608c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_GPE); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 5638c2ecf20Sopenharmony_ci} 5648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_gpio_set_dir); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ciint locomo_gpio_read_level(struct device *dev, unsigned int bits) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct locomo *lchip = dev_get_drvdata(dev); 5698c2ecf20Sopenharmony_ci unsigned long flags; 5708c2ecf20Sopenharmony_ci unsigned int ret; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci if (!lchip) 5738c2ecf20Sopenharmony_ci return -ENODEV; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 5768c2ecf20Sopenharmony_ci ret = locomo_readl(lchip->base + LOCOMO_GPL); 5778c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci ret &= bits; 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci} 5828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_gpio_read_level); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ciint locomo_gpio_read_output(struct device *dev, unsigned int bits) 5858c2ecf20Sopenharmony_ci{ 5868c2ecf20Sopenharmony_ci struct locomo *lchip = dev_get_drvdata(dev); 5878c2ecf20Sopenharmony_ci unsigned long flags; 5888c2ecf20Sopenharmony_ci unsigned int ret; 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci if (!lchip) 5918c2ecf20Sopenharmony_ci return -ENODEV; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 5948c2ecf20Sopenharmony_ci ret = locomo_readl(lchip->base + LOCOMO_GPO); 5958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci ret &= bits; 5988c2ecf20Sopenharmony_ci return ret; 5998c2ecf20Sopenharmony_ci} 6008c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_gpio_read_output); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_civoid locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set) 6038c2ecf20Sopenharmony_ci{ 6048c2ecf20Sopenharmony_ci struct locomo *lchip = dev_get_drvdata(dev); 6058c2ecf20Sopenharmony_ci unsigned long flags; 6068c2ecf20Sopenharmony_ci unsigned int r; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci if (!lchip) 6098c2ecf20Sopenharmony_ci return; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci r = locomo_readl(lchip->base + LOCOMO_GPO); 6148c2ecf20Sopenharmony_ci if (set) 6158c2ecf20Sopenharmony_ci r |= bits; 6168c2ecf20Sopenharmony_ci else 6178c2ecf20Sopenharmony_ci r &= ~bits; 6188c2ecf20Sopenharmony_ci locomo_writel(r, lchip->base + LOCOMO_GPO); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_gpio_write); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_cistatic void locomo_m62332_sendbit(void *mapbase, int bit) 6258c2ecf20Sopenharmony_ci{ 6268c2ecf20Sopenharmony_ci unsigned int r; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6298c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 6308c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6318c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 6328c2ecf20Sopenharmony_ci udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ 6338c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6348c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 6358c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6368c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 6378c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci if (bit & 1) { 6408c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6418c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SDAOEB; 6428c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6438c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 6448c2ecf20Sopenharmony_ci } else { 6458c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6468c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SDAOEB); 6478c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6488c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 6498c2ecf20Sopenharmony_ci } 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci udelay(DAC_DATA_SETUP_TIME); /* 250 nsec */ 6528c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6538c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB; 6548c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6558c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 6568c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_civoid locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) 6608c2ecf20Sopenharmony_ci{ 6618c2ecf20Sopenharmony_ci struct locomo *lchip = locomo_chip_driver(ldev); 6628c2ecf20Sopenharmony_ci int i; 6638c2ecf20Sopenharmony_ci unsigned char data; 6648c2ecf20Sopenharmony_ci unsigned int r; 6658c2ecf20Sopenharmony_ci void *mapbase = lchip->base; 6668c2ecf20Sopenharmony_ci unsigned long flags; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci /* Start */ 6718c2ecf20Sopenharmony_ci udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ 6728c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6738c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; 6748c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6758c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 6768c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ 6778c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6788c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SDAOEB); 6798c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6808c2ecf20Sopenharmony_ci udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ 6818c2ecf20Sopenharmony_ci udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* Send slave address and W bit (LSB is W bit) */ 6848c2ecf20Sopenharmony_ci data = (M62332_SLAVE_ADDR << 1) | M62332_W_BIT; 6858c2ecf20Sopenharmony_ci for (i = 1; i <= 8; i++) { 6868c2ecf20Sopenharmony_ci locomo_m62332_sendbit(mapbase, data >> (8 - i)); 6878c2ecf20Sopenharmony_ci } 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* Check A bit */ 6908c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6918c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 6928c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6938c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 6948c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 6958c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 6968c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SDAOEB); 6978c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 6988c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 6998c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7008c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB; 7018c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7028c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 7038c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ 7048c2ecf20Sopenharmony_ci if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ 7058c2ecf20Sopenharmony_ci printk(KERN_WARNING "locomo: m62332_senddata Error 1\n"); 7068c2ecf20Sopenharmony_ci goto out; 7078c2ecf20Sopenharmony_ci } 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_ci /* Send Sub address (LSB is channel select) */ 7108c2ecf20Sopenharmony_ci /* channel = 0 : ch1 select */ 7118c2ecf20Sopenharmony_ci /* = 1 : ch2 select */ 7128c2ecf20Sopenharmony_ci data = M62332_SUB_ADDR + channel; 7138c2ecf20Sopenharmony_ci for (i = 1; i <= 8; i++) { 7148c2ecf20Sopenharmony_ci locomo_m62332_sendbit(mapbase, data >> (8 - i)); 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci 7178c2ecf20Sopenharmony_ci /* Check A bit */ 7188c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7198c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 7208c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7218c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 7228c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 7238c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7248c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SDAOEB); 7258c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7268c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 7278c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7288c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB; 7298c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7308c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 7318c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ 7328c2ecf20Sopenharmony_ci if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ 7338c2ecf20Sopenharmony_ci printk(KERN_WARNING "locomo: m62332_senddata Error 2\n"); 7348c2ecf20Sopenharmony_ci goto out; 7358c2ecf20Sopenharmony_ci } 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci /* Send DAC data */ 7388c2ecf20Sopenharmony_ci for (i = 1; i <= 8; i++) { 7398c2ecf20Sopenharmony_ci locomo_m62332_sendbit(mapbase, dac_data >> (8 - i)); 7408c2ecf20Sopenharmony_ci } 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci /* Check A bit */ 7438c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7448c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 7458c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7468c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 7478c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 7488c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7498c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SDAOEB); 7508c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7518c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 7528c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7538c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB; 7548c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7558c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 7568c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.7 usec */ 7578c2ecf20Sopenharmony_ci if (locomo_readl(mapbase + LOCOMO_DAC) & LOCOMO_DAC_SDAOEB) { /* High is error */ 7588c2ecf20Sopenharmony_ci printk(KERN_WARNING "locomo: m62332_senddata Error 3\n"); 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci 7618c2ecf20Sopenharmony_ciout: 7628c2ecf20Sopenharmony_ci /* stop */ 7638c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7648c2ecf20Sopenharmony_ci r &= ~(LOCOMO_DAC_SCLOEB); 7658c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7668c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ 7678c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 7688c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7698c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB; 7708c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7718c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 7728c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ 7738c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7748c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SDAOEB; 7758c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7768c2ecf20Sopenharmony_ci udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ 7778c2ecf20Sopenharmony_ci udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci r = locomo_readl(mapbase + LOCOMO_DAC); 7808c2ecf20Sopenharmony_ci r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; 7818c2ecf20Sopenharmony_ci locomo_writel(r, mapbase + LOCOMO_DAC); 7828c2ecf20Sopenharmony_ci udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ 7838c2ecf20Sopenharmony_ci udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 7868c2ecf20Sopenharmony_ci} 7878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_m62332_senddata); 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci/* 7908c2ecf20Sopenharmony_ci * Frontlight control 7918c2ecf20Sopenharmony_ci */ 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_civoid locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci unsigned long flags; 7968c2ecf20Sopenharmony_ci struct locomo *lchip = locomo_chip_driver(dev); 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci if (vr) 7998c2ecf20Sopenharmony_ci locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1); 8008c2ecf20Sopenharmony_ci else 8018c2ecf20Sopenharmony_ci locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0); 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci spin_lock_irqsave(&lchip->lock, flags); 8048c2ecf20Sopenharmony_ci locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); 8058c2ecf20Sopenharmony_ci udelay(100); 8068c2ecf20Sopenharmony_ci locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); 8078c2ecf20Sopenharmony_ci locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); 8088c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&lchip->lock, flags); 8098c2ecf20Sopenharmony_ci} 8108c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_frontlight_set); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci/* 8138c2ecf20Sopenharmony_ci * LoCoMo "Register Access Bus." 8148c2ecf20Sopenharmony_ci * 8158c2ecf20Sopenharmony_ci * We model this as a regular bus type, and hang devices directly 8168c2ecf20Sopenharmony_ci * off this. 8178c2ecf20Sopenharmony_ci */ 8188c2ecf20Sopenharmony_cistatic int locomo_match(struct device *_dev, struct device_driver *_drv) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct locomo_dev *dev = LOCOMO_DEV(_dev); 8218c2ecf20Sopenharmony_ci struct locomo_driver *drv = LOCOMO_DRV(_drv); 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci return dev->devid == drv->devid; 8248c2ecf20Sopenharmony_ci} 8258c2ecf20Sopenharmony_ci 8268c2ecf20Sopenharmony_cistatic int locomo_bus_probe(struct device *dev) 8278c2ecf20Sopenharmony_ci{ 8288c2ecf20Sopenharmony_ci struct locomo_dev *ldev = LOCOMO_DEV(dev); 8298c2ecf20Sopenharmony_ci struct locomo_driver *drv = LOCOMO_DRV(dev->driver); 8308c2ecf20Sopenharmony_ci int ret = -ENODEV; 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci if (drv->probe) 8338c2ecf20Sopenharmony_ci ret = drv->probe(ldev); 8348c2ecf20Sopenharmony_ci return ret; 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic int locomo_bus_remove(struct device *dev) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci struct locomo_dev *ldev = LOCOMO_DEV(dev); 8408c2ecf20Sopenharmony_ci struct locomo_driver *drv = LOCOMO_DRV(dev->driver); 8418c2ecf20Sopenharmony_ci int ret = 0; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci if (drv->remove) 8448c2ecf20Sopenharmony_ci ret = drv->remove(ldev); 8458c2ecf20Sopenharmony_ci return ret; 8468c2ecf20Sopenharmony_ci} 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_cistruct bus_type locomo_bus_type = { 8498c2ecf20Sopenharmony_ci .name = "locomo-bus", 8508c2ecf20Sopenharmony_ci .match = locomo_match, 8518c2ecf20Sopenharmony_ci .probe = locomo_bus_probe, 8528c2ecf20Sopenharmony_ci .remove = locomo_bus_remove, 8538c2ecf20Sopenharmony_ci}; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciint locomo_driver_register(struct locomo_driver *driver) 8568c2ecf20Sopenharmony_ci{ 8578c2ecf20Sopenharmony_ci driver->drv.bus = &locomo_bus_type; 8588c2ecf20Sopenharmony_ci return driver_register(&driver->drv); 8598c2ecf20Sopenharmony_ci} 8608c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_driver_register); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_civoid locomo_driver_unregister(struct locomo_driver *driver) 8638c2ecf20Sopenharmony_ci{ 8648c2ecf20Sopenharmony_ci driver_unregister(&driver->drv); 8658c2ecf20Sopenharmony_ci} 8668c2ecf20Sopenharmony_ciEXPORT_SYMBOL(locomo_driver_unregister); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_cistatic int __init locomo_init(void) 8698c2ecf20Sopenharmony_ci{ 8708c2ecf20Sopenharmony_ci int ret = bus_register(&locomo_bus_type); 8718c2ecf20Sopenharmony_ci if (ret == 0) 8728c2ecf20Sopenharmony_ci platform_driver_register(&locomo_device_driver); 8738c2ecf20Sopenharmony_ci return ret; 8748c2ecf20Sopenharmony_ci} 8758c2ecf20Sopenharmony_ci 8768c2ecf20Sopenharmony_cistatic void __exit locomo_exit(void) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci platform_driver_unregister(&locomo_device_driver); 8798c2ecf20Sopenharmony_ci bus_unregister(&locomo_bus_type); 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cimodule_init(locomo_init); 8838c2ecf20Sopenharmony_cimodule_exit(locomo_exit); 8848c2ecf20Sopenharmony_ci 8858c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Sharp LoCoMo core driver"); 8868c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 8878c2ecf20Sopenharmony_ciMODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); 888