diff options
Diffstat (limited to 'recipes-kernel/linux/linux-handheld-4.0/locomo')
20 files changed, 5546 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0001-iio-add-m62332-DAC-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0001-iio-add-m62332-DAC-driver.patch new file mode 100644 index 0000000..d1cf814 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0001-iio-add-m62332-DAC-driver.patch @@ -0,0 +1,295 @@ +From 879c0ec1131e472f752d70ddf117dcabaf8ea106 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Sun, 23 Nov 2014 18:42:52 +0300 +Subject: [PATCH 01/20] iio: add m62332 DAC driver + +m62332 is a simple 2-channel DAC used on several Sharp Zaurus boards to +control LCD voltage, backlight and sound. The driver use regulators to +control the reference voltage and enabling/disabling the DAC. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/iio/dac/Kconfig | 10 ++ + drivers/iio/dac/Makefile | 1 + + drivers/iio/dac/m62332.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 247 insertions(+) + create mode 100644 drivers/iio/dac/m62332.c + +diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig +index 2236ea2..2ede061 100644 +--- a/drivers/iio/dac/Kconfig ++++ b/drivers/iio/dac/Kconfig +@@ -142,6 +142,16 @@ config AD7303 + To compile this driver as module choose M here: the module will be called + ad7303. + ++config M62332 ++ tristate "Mitsubishi M62332 DAC driver" ++ depends on I2C ++ help ++ If you say yes here you get support for the Mitsubishi M62332 ++ (I2C 8-Bit DACs with rail-to-rail outputs). ++ ++ This driver can also be built as a module. If so, the module ++ will be called m62332. ++ + config MAX517 + tristate "Maxim MAX517/518/519 DAC driver" + depends on I2C +diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile +index 52be7e1..63ae056 100644 +--- a/drivers/iio/dac/Makefile ++++ b/drivers/iio/dac/Makefile +@@ -16,6 +16,7 @@ obj-$(CONFIG_AD5764) += ad5764.o + obj-$(CONFIG_AD5791) += ad5791.o + obj-$(CONFIG_AD5686) += ad5686.o + obj-$(CONFIG_AD7303) += ad7303.o ++obj-$(CONFIG_M62332) += m62332.o + obj-$(CONFIG_MAX517) += max517.o + obj-$(CONFIG_MAX5821) += max5821.o + obj-$(CONFIG_MCP4725) += mcp4725.o +diff --git a/drivers/iio/dac/m62332.c b/drivers/iio/dac/m62332.c +new file mode 100644 +index 0000000..90574d7 +--- /dev/null ++++ b/drivers/iio/dac/m62332.c +@@ -0,0 +1,236 @@ ++/* ++ * m62332.c - Support for Mitsubishi m62332 DAC ++ * ++ * Copyright (c) 2014 Dmitry Eremin-Solenikov ++ * ++ * Based on max517 driver: ++ * Copyright (C) 2010, 2011 Roland Stigge <stigge@antcom.de> ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++ ++#include <linux/module.h> ++#include <linux/slab.h> ++#include <linux/jiffies.h> ++#include <linux/i2c.h> ++#include <linux/err.h> ++ ++#include <linux/iio/iio.h> ++#include <linux/iio/driver.h> ++ ++#include <linux/regulator/consumer.h> ++ ++struct m62332_data { ++ struct i2c_client *client; ++ unsigned short vref_mv; ++ unsigned char raw[2]; ++ struct regulator *vcc; ++#ifdef CONFIG_PM_SLEEP ++ unsigned char save[2]; ++#endif ++}; ++ ++static int m62332_set_value(struct iio_dev *indio_dev, ++ unsigned char val, int channel) ++{ ++ struct m62332_data *data = iio_priv(indio_dev); ++ struct i2c_client *client = data->client; ++ u8 outbuf[2]; ++ int res = 0; ++ ++ if (val == data->raw[channel]) ++ return 0; ++ ++ outbuf[0] = channel; ++ outbuf[1] = val; ++ ++ if (val || data->raw[!channel]) ++ res = regulator_enable(data->vcc); ++ if (res) ++ return res; ++ ++ res = i2c_master_send(client, outbuf, 2); ++ if (res < 0) ++ return res; ++ else if (res != 2) ++ return -EIO; ++ ++ data->raw[channel] = val; ++ ++ if (!data->raw[0] && !data->raw[1]) ++ regulator_disable(data->vcc); ++ ++ return 0; ++} ++ ++static int m62332_read_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, ++ int *val, ++ int *val2, ++ long m) ++{ ++ struct m62332_data *data = iio_priv(indio_dev); ++ ++ switch (m) { ++ case IIO_CHAN_INFO_SCALE: ++ /* Corresponds to Vref / 2^(bits) */ ++ *val = data->vref_mv; ++ *val2 = 8; ++ return IIO_VAL_FRACTIONAL_LOG2; ++ case IIO_CHAN_INFO_RAW: ++ *val = data->raw[chan->channel]; ++ return IIO_VAL_INT; ++ default: ++ break; ++ } ++ return -EINVAL; ++} ++ ++static int m62332_write_raw(struct iio_dev *indio_dev, ++ struct iio_chan_spec const *chan, int val, int val2, long mask) ++{ ++ int ret; ++ ++ switch (mask) { ++ case IIO_CHAN_INFO_RAW: ++ if (val < 0 || val > 255) ++ return -EINVAL; ++ ++ ret = m62332_set_value(indio_dev, val, chan->channel); ++ break; ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return ret; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int m62332_suspend(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ struct m62332_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ data->save[0] = data->raw[0]; ++ data->save[1] = data->raw[1]; ++ ++ ret = m62332_set_value(indio_dev, 0, 0); ++ if (ret < 0) ++ return ret; ++ ++ return m62332_set_value(indio_dev, 0, 1); ++} ++ ++static int m62332_resume(struct device *dev) ++{ ++ struct i2c_client *client = to_i2c_client(dev); ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ struct m62332_data *data = iio_priv(indio_dev); ++ int ret; ++ ++ ret = m62332_set_value(indio_dev, data->save[0], 0); ++ if (ret < 0) ++ return ret; ++ ++ return m62332_set_value(indio_dev, data->save[1], 1); ++} ++ ++static SIMPLE_DEV_PM_OPS(m62332_pm_ops, m62332_suspend, m62332_resume); ++#define M62332_PM_OPS (&m62332_pm_ops) ++#else ++#define M62332_PM_OPS NULL ++#endif ++ ++static const struct iio_info m62332_info = { ++ .read_raw = m62332_read_raw, ++ .write_raw = m62332_write_raw, ++ .driver_module = THIS_MODULE, ++}; ++ ++#define M62332_CHANNEL(chan) { \ ++ .type = IIO_VOLTAGE, \ ++ .indexed = 1, \ ++ .output = 1, \ ++ .channel = (chan), \ ++ .datasheet_name = "CH" #chan, \ ++ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ ++ BIT(IIO_CHAN_INFO_SCALE), \ ++} ++ ++static const struct iio_chan_spec m62332_channels[] = { ++ M62332_CHANNEL(0), ++ M62332_CHANNEL(1) ++}; ++ ++static int m62332_probe(struct i2c_client *client, ++ const struct i2c_device_id *id) ++{ ++ struct m62332_data *data; ++ struct iio_dev *indio_dev; ++ ++ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data)); ++ if (!indio_dev) ++ return -ENOMEM; ++ data = iio_priv(indio_dev); ++ i2c_set_clientdata(client, indio_dev); ++ data->client = client; ++ ++ data->vcc = devm_regulator_get(&client->dev, "VCC"); ++ if (IS_ERR(data->vcc)) ++ return PTR_ERR(data->vcc); ++ ++ /* establish that the iio_dev is a child of the i2c device */ ++ indio_dev->dev.parent = &client->dev; ++ ++ indio_dev->num_channels = 2; ++ indio_dev->channels = m62332_channels; ++ indio_dev->modes = INDIO_DIRECT_MODE; ++ indio_dev->info = &m62332_info; ++ ++ data->vref_mv = regulator_get_voltage(data->vcc) / 1000; /* mV */ ++ ++ iio_map_array_register(indio_dev, client->dev.platform_data); ++ ++ return iio_device_register(indio_dev); ++} ++ ++static int m62332_remove(struct i2c_client *client) ++{ ++ struct iio_dev *indio_dev = i2c_get_clientdata(client); ++ ++ iio_device_unregister(indio_dev); ++ iio_map_array_unregister(indio_dev); ++ return 0; ++} ++ ++static const struct i2c_device_id m62332_id[] = { ++ { "m62332", }, ++ { } ++}; ++MODULE_DEVICE_TABLE(i2c, m62332_id); ++ ++static struct i2c_driver m62332_driver = { ++ .driver = { ++ .name = "m62332", ++ .pm = M62332_PM_OPS, ++ }, ++ .probe = m62332_probe, ++ .remove = m62332_remove, ++ .id_table = m62332_id, ++}; ++module_i2c_driver(m62332_driver); ++ ++MODULE_AUTHOR("Dmitry Eremin-Solenikov"); ++MODULE_DESCRIPTION("M62332 8-bit DAC"); ++MODULE_LICENSE("GPL v2"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0002-mfd-add-new-driver-for-Sharp-LoCoMo.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0002-mfd-add-new-driver-for-Sharp-LoCoMo.patch new file mode 100644 index 0000000..4888b69 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0002-mfd-add-new-driver-for-Sharp-LoCoMo.patch @@ -0,0 +1,603 @@ +From 39201b5a779092078e865dd33db6d24e1e0a4c6f Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 02:56:08 +0400 +Subject: [PATCH 02/20] mfd: add new driver for Sharp LoCoMo + +LoCoMo is a GA used on Sharp Zaurus SL-5x00. Current driver does has +several design issues (special bus instead of platform bus, doesn't use +mfd-core, etc). + +Implement 'core' parts of locomo support as an mfd driver. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/mfd/Kconfig | 10 ++ + drivers/mfd/Makefile | 1 + + drivers/mfd/locomo.c | 361 +++++++++++++++++++++++++++++++++++++++++++++ + include/linux/mfd/locomo.h | 173 ++++++++++++++++++++++ + 4 files changed, 545 insertions(+) + create mode 100644 drivers/mfd/locomo.c + create mode 100644 include/linux/mfd/locomo.h + +diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig +index 38356e3..95fd73e 100644 +--- a/drivers/mfd/Kconfig ++++ b/drivers/mfd/Kconfig +@@ -1378,6 +1378,16 @@ config MFD_STW481X + in various ST Microelectronics and ST-Ericsson embedded + Nomadik series. + ++config MFD_LOCOMO ++ bool "Sharp LoCoMo support" ++ depends on ARM ++ select MFD_CORE ++ select IRQ_DOMAIN ++ select REGMAP_MMIO ++ help ++ Support for Sharp LoCoMo Grid Array found in Sharp SL-5x00 ++ PDA family. ++ + menu "Multimedia Capabilities Port drivers" + depends on ARCH_SA1100 + +diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile +index 19f3d74..8deda90 100644 +--- a/drivers/mfd/Makefile ++++ b/drivers/mfd/Makefile +@@ -178,6 +178,7 @@ obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o + obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o + obj-$(CONFIG_MFD_DLN2) += dln2.o + obj-$(CONFIG_MFD_RT5033) += rt5033.o ++obj-$(CONFIG_MFD_LOCOMO) += locomo.o + + intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o + obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o +diff --git a/drivers/mfd/locomo.c b/drivers/mfd/locomo.c +new file mode 100644 +index 0000000..bc7cc94 +--- /dev/null ++++ b/drivers/mfd/locomo.c +@@ -0,0 +1,361 @@ ++/* ++ * Sharp LoCoMo support ++ * ++ * Based on old driver at arch/arm/common/locomo.c ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 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. ++ */ ++#include <linux/delay.h> ++#include <linux/gpio.h> ++#include <linux/io.h> ++#include <linux/irq.h> ++#include <linux/irqdomain.h> ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/regmap.h> ++#include <linux/slab.h> ++#include <linux/platform_device.h> ++#include <linux/mfd/core.h> ++#include <linux/mfd/locomo.h> ++ ++/* LoCoMo Interrupts */ ++#define IRQ_LOCOMO_KEY (0) ++#define IRQ_LOCOMO_GPIO (1) ++#define IRQ_LOCOMO_LT (2) ++#define IRQ_LOCOMO_SPI (3) ++ ++#define LOCOMO_NR_IRQS (4) ++ ++/* the following is the overall data for the locomo chip */ ++struct locomo { ++ struct device *dev; ++ unsigned int irq; ++ spinlock_t lock; ++ struct irq_domain *domain; ++ struct regmap *regmap; ++}; ++ ++static struct resource locomo_kbd_resources[] = { ++ DEFINE_RES_IRQ(IRQ_LOCOMO_KEY), ++}; ++ ++static struct resource locomo_gpio_resources[] = { ++ DEFINE_RES_IRQ(IRQ_LOCOMO_GPIO), ++}; ++ ++static struct locomo_gpio_platform_data locomo_gpio_pdata = { ++}; ++ ++static struct resource locomo_lt_resources[] = { ++ DEFINE_RES_IRQ(IRQ_LOCOMO_LT), ++}; ++ ++static struct resource locomo_spi_resources[] = { ++ DEFINE_RES_IRQ(IRQ_LOCOMO_SPI), ++}; ++ ++static struct locomo_lcd_platform_data locomo_lcd_pdata = { ++}; ++ ++static struct mfd_cell locomo_cells[] = { ++ { ++ .name = "locomo-kbd", ++ .resources = locomo_kbd_resources, ++ .num_resources = ARRAY_SIZE(locomo_kbd_resources), ++ }, ++ { ++ .name = "locomo-gpio", ++ .resources = locomo_gpio_resources, ++ .num_resources = ARRAY_SIZE(locomo_gpio_resources), ++ .platform_data = &locomo_gpio_pdata, ++ .pdata_size = sizeof(locomo_gpio_pdata), ++ }, ++ { ++ .name = "locomo-lt", /* Long time timer */ ++ .resources = locomo_lt_resources, ++ .num_resources = ARRAY_SIZE(locomo_lt_resources), ++ }, ++ { ++ .name = "locomo-spi", ++ .resources = locomo_spi_resources, ++ .num_resources = ARRAY_SIZE(locomo_spi_resources), ++ }, ++ { ++ .name = "locomo-led", ++ }, ++ { ++ .name = "locomo-backlight", ++ }, ++ { ++ .name = "locomo-lcd", ++ .platform_data = &locomo_lcd_pdata, ++ .pdata_size = sizeof(locomo_lcd_pdata), ++ }, ++ { ++ .name = "locomo-i2c", ++ }, ++}; ++ ++/* IRQ support */ ++static void locomo_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ struct locomo *lchip = irq_get_handler_data(irq); ++ struct irq_chip *irqchip = irq_desc_get_chip(desc); ++ unsigned int req; ++ ++ chained_irq_enter(irqchip, desc); ++ ++ /* check why this interrupt was generated */ ++ while (1) { ++ regmap_read(lchip->regmap, LOCOMO_ICR, &req); ++ req &= 0x0f00; ++ ++ if (!req) ++ break; ++ ++ irq = ffs(req) - 9; ++ generic_handle_irq(irq_find_mapping(lchip->domain, irq)); ++ } ++ ++ chained_irq_exit(irqchip, desc); ++} ++ ++static void locomo_ack_irq(struct irq_data *d) ++{ ++} ++ ++static void locomo_mask_irq(struct irq_data *d) ++{ ++ struct locomo *lchip = irq_data_get_irq_chip_data(d); ++ ++ regmap_update_bits(lchip->regmap, LOCOMO_ICR, ++ 0x0010 << d->hwirq, ++ 0); ++} ++ ++static void locomo_unmask_irq(struct irq_data *d) ++{ ++ struct locomo *lchip = irq_data_get_irq_chip_data(d); ++ ++ regmap_update_bits(lchip->regmap, LOCOMO_ICR, ++ (0x0010 << d->hwirq), ++ (0x0010 << d->hwirq)); ++} ++ ++static struct irq_chip locomo_chip = { ++ .name = "LOCOMO", ++ .irq_ack = locomo_ack_irq, ++ .irq_mask = locomo_mask_irq, ++ .irq_unmask = locomo_unmask_irq, ++}; ++ ++static int locomo_irq_map(struct irq_domain *d, unsigned int virq, ++ irq_hw_number_t hwirq) ++{ ++ struct locomo *locomo = d->host_data; ++ ++ irq_set_chip_data(virq, locomo); ++ irq_set_chip_and_handler(virq, &locomo_chip, ++ handle_level_irq); ++ set_irq_flags(virq, IRQF_VALID); ++ ++ return 0; ++} ++ ++static void locomo_irq_unmap(struct irq_domain *d, unsigned int virq) ++{ ++ set_irq_flags(virq, 0); ++ irq_set_chip_and_handler(virq, NULL, NULL); ++ irq_set_chip_data(virq, NULL); ++} ++ ++static struct irq_domain_ops locomo_irq_ops = { ++ .map = locomo_irq_map, ++ .unmap = locomo_irq_unmap, ++ .xlate = irq_domain_xlate_onecell, ++}; ++ ++static int locomo_setup_irq(struct locomo *lchip) ++{ ++ lchip->domain = irq_domain_add_simple(NULL, LOCOMO_NR_IRQS, 0, ++ &locomo_irq_ops, lchip); ++ if (!lchip->domain) { ++ dev_err(lchip->dev, "Failed to register irqdomain\n"); ++ return -ENOSYS; ++ } ++ ++ /* ++ * Install handler for IRQ_LOCOMO_HW. ++ */ ++ irq_set_irq_type(lchip->irq, IRQ_TYPE_EDGE_FALLING); ++ irq_set_handler_data(lchip->irq, lchip); ++ irq_set_chained_handler(lchip->irq, locomo_handler); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomo_suspend(struct device *dev) ++{ ++ struct locomo *lchip = dev_get_drvdata(dev); ++ ++ /* AUDIO */ ++ regmap_write(lchip->regmap, LOCOMO_PAIF, 0x00); ++ regmap_write(lchip->regmap, LOCOMO_DAC, 0x00); ++ ++ /* ++ * Original code disabled the clock depending on leds settings ++ * However we disable leds before suspend, thus it's safe ++ * to just assume this setting. ++ */ ++ /* CLK32 off */ ++ regmap_write(lchip->regmap, LOCOMO_C32K, 0x00); ++ ++ /* 22MHz/24MHz clock off */ ++ regmap_write(lchip->regmap, LOCOMO_ACC, 0x00); ++ ++ return 0; ++} ++ ++static int locomo_resume(struct device *dev) ++{ ++ struct locomo *lchip = dev_get_drvdata(dev); ++ regmap_write(lchip->regmap, LOCOMO_C32K, 0x00); ++ ++ return 0; ++} ++static SIMPLE_DEV_PM_OPS(locomo_pm, locomo_suspend, locomo_resume); ++#define LOCOMO_PM (&locomo_pm) ++#else ++#define LOCOMO_PM NULL ++#endif ++ ++static const struct regmap_config locomo_regmap_config = { ++ .name = "LoCoMo", ++ .reg_bits = 8, ++ .reg_stride = 4, ++ .val_bits = 16, ++ .cache_type = REGCACHE_NONE, ++ .max_register = 0xec, ++}; ++ ++static int locomo_probe(struct platform_device *dev) ++{ ++ struct locomo_platform_data *pdata = dev_get_platdata(&dev->dev); ++ struct resource *mem; ++ void __iomem *base; ++ struct locomo *lchip; ++ unsigned int r; ++ int ret = -ENODEV; ++ ++ lchip = devm_kzalloc(&dev->dev, sizeof(struct locomo), GFP_KERNEL); ++ if (!lchip) ++ return -ENOMEM; ++ ++ spin_lock_init(&lchip->lock); ++ lchip->dev = &dev->dev; ++ ++ lchip->irq = platform_get_irq(dev, 0); ++ if (lchip->irq < 0) ++ return -ENXIO; ++ ++ mem = platform_get_resource(dev, IORESOURCE_MEM, 0); ++ base = devm_ioremap_resource(&dev->dev, mem); ++ if (IS_ERR(base)) ++ return PTR_ERR(base); ++ ++ lchip->regmap = devm_regmap_init_mmio(&dev->dev, base, ++ &locomo_regmap_config); ++ if (IS_ERR(lchip->regmap)) ++ return PTR_ERR(lchip->regmap); ++ ++ if (pdata) { ++ locomo_gpio_pdata.gpio_base = pdata->gpio_base; ++ locomo_lcd_pdata.comadj = pdata->comadj; ++ } else { ++ locomo_gpio_pdata.gpio_base = -1; ++ locomo_lcd_pdata.comadj = 128; ++ } ++ ++ platform_set_drvdata(dev, lchip); ++ ++ regmap_read(lchip->regmap, LOCOMO_VER, &r); ++ dev_info(&dev->dev, "LoCoMo Chip: %04x\n", r); ++ ++ /* locomo initialize */ ++ regmap_write(lchip->regmap, LOCOMO_ICR, 0); ++ ++ /* Longtime timer */ ++ regmap_write(lchip->regmap, LOCOMO_LTINT, 0); ++ /* SPI */ ++ regmap_write(lchip->regmap, LOCOMO_SPIIE, 0); ++ ++ /* init DAC */ ++ regmap_update_bits(lchip->regmap, LOCOMO_DAC, ++ LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB, ++ LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB); ++ ++ /* ++ * The interrupt controller must be initialised before any ++ * other device to ensure that the interrupts are available. ++ */ ++ ret = locomo_setup_irq(lchip); ++ if (ret < 0) ++ goto err_add; ++ ++ ret = mfd_add_devices(&dev->dev, dev->id, ++ locomo_cells, ARRAY_SIZE(locomo_cells), ++ mem, -1, lchip->domain); ++ if (ret) ++ goto err_add; ++ ++ return 0; ++ ++err_add: ++ irq_set_chained_handler(lchip->irq, NULL); ++ irq_set_handler_data(lchip->irq, NULL); ++ if (lchip->domain) ++ irq_domain_remove(lchip->domain); ++ ++ return ret; ++} ++ ++static int locomo_remove(struct platform_device *dev) ++{ ++ struct locomo *lchip = platform_get_drvdata(dev); ++ ++ if (!lchip) ++ return 0; ++ ++ mfd_remove_devices(&dev->dev); ++ ++ irq_set_chained_handler(lchip->irq, NULL); ++ irq_set_handler_data(lchip->irq, NULL); ++ if (lchip->domain) ++ irq_domain_remove(lchip->domain); ++ ++ return 0; ++} ++ ++static struct platform_driver locomo_device_driver = { ++ .probe = locomo_probe, ++ .remove = locomo_remove, ++ .driver = { ++ .name = "locomo", ++ .pm = LOCOMO_PM, ++ }, ++}; ++ ++module_platform_driver(locomo_device_driver); ++ ++MODULE_DESCRIPTION("Sharp LoCoMo core driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_ALIAS("platform:locomo"); +diff --git a/include/linux/mfd/locomo.h b/include/linux/mfd/locomo.h +new file mode 100644 +index 0000000..6729767 +--- /dev/null ++++ b/include/linux/mfd/locomo.h +@@ -0,0 +1,173 @@ ++/* ++ * include/linux/mfd/locomo.h ++ * ++ * This file contains the definitions for the LoCoMo G/A Chip ++ * ++ * (C) Copyright 2004 John Lenz ++ * ++ * May be copied or modified under the terms of the GNU General Public ++ * License. See linux/COPYING for more information. ++ * ++ * Based on sa1111.h ++ */ ++#ifndef _ASM_ARCH_LOCOMO ++#define _ASM_ARCH_LOCOMO ++ ++/* LOCOMO version */ ++#define LOCOMO_VER 0x00 ++ ++/* Pin status */ ++#define LOCOMO_ST 0x04 ++ ++/* Pin status */ ++#define LOCOMO_C32K 0x08 ++ ++/* Interrupt controller */ ++#define LOCOMO_ICR 0x0C ++ ++/* MCS decoder for boot selecting */ ++#define LOCOMO_MCSX0 0x10 ++#define LOCOMO_MCSX1 0x14 ++#define LOCOMO_MCSX2 0x18 ++#define LOCOMO_MCSX3 0x1c ++ ++/* Touch panel controller */ ++#define LOCOMO_ASD 0x20 /* AD start delay */ ++#define LOCOMO_HSD 0x28 /* HSYS delay */ ++#define LOCOMO_HSC 0x2c /* HSYS period */ ++#define LOCOMO_TADC 0x30 /* tablet ADC clock */ ++ ++/* Backlight controller: TFT signal */ ++#define LOCOMO_TC 0x38 /* TFT control signal */ ++#define LOCOMO_CPSD 0x3c /* CPS delay */ ++ ++/* Keyboard controller */ ++#define LOCOMO_KIB 0x40 /* KIB level */ ++#define LOCOMO_KSC 0x44 /* KSTRB control */ ++#define LOCOMO_KCMD 0x48 /* KSTRB command */ ++#define LOCOMO_KIC 0x4c /* Key interrupt */ ++ ++/* Audio clock */ ++#define LOCOMO_ACC 0x54 /* Audio clock */ ++#define LOCOMO_ACC_XON 0x80 ++#define LOCOMO_ACC_XEN 0x40 ++#define LOCOMO_ACC_XSEL0 0x00 ++#define LOCOMO_ACC_XSEL1 0x20 ++#define LOCOMO_ACC_MCLKEN 0x10 ++#define LOCOMO_ACC_64FSEN 0x08 ++#define LOCOMO_ACC_CLKSEL000 0x00 /* mclk 2 */ ++#define LOCOMO_ACC_CLKSEL001 0x01 /* mclk 3 */ ++#define LOCOMO_ACC_CLKSEL010 0x02 /* mclk 4 */ ++#define LOCOMO_ACC_CLKSEL011 0x03 /* mclk 6 */ ++#define LOCOMO_ACC_CLKSEL100 0x04 /* mclk 8 */ ++#define LOCOMO_ACC_CLKSEL101 0x05 /* mclk 12 */ ++ ++/* SPI interface */ ++#define LOCOMO_SPIMD 0x60 /* SPI mode setting */ ++#define LOCOMO_SPIMD_LOOPBACK (1 << 15) /* loopback tx to rx */ ++#define LOCOMO_SPIMD_MSB1ST (1 << 14) /* send MSB first */ ++#define LOCOMO_SPIMD_DOSTAT (1 << 13) /* transmit line is idle high */ ++#define LOCOMO_SPIMD_TCPOL (1 << 11) /* transmit CPOL (maybe affects CPHA) */ ++#define LOCOMO_SPIMD_RCPOL (1 << 10) /* receive CPOL (maybe affects CPHA) */ ++#define LOCOMO_SPIMD_TDINV (1 << 9) /* invert transmit line */ ++#define LOCOMO_SPIMD_RDINV (1 << 8) /* invert receive line */ ++#define LOCOMO_SPIMD_XON (1 << 7) /* enable spi controller clock */ ++#define LOCOMO_SPIMD_XEN (1 << 6) /* clock bit write enable */ ++#define LOCOMO_SPIMD_XSEL 0x0018 /* clock select */ ++/* xon must be off when enabling xen, wait 300 us before xon -> 1 */ ++#define CLOCK_18MHZ 0 /* 18,432 MHz clock */ ++#define CLOCK_22MHZ 1 /* 22,5792 MHz clock */ ++#define CLOCK_25MHZ 2 /* 24,576 MHz clock */ ++#define LOCOMO_SPIMD_CLKSEL 0x7 ++#define DIV_1 0 /* don't divide clock */ ++#define DIV_2 1 /* divide clock by two */ ++#define DIV_4 2 /* divide clock by four */ ++#define DIV_8 3 /* divide clock by eight*/ ++#define DIV_64 4 /* divide clock by 64 */ ++ ++#define LOCOMO_SPICT 0x64 /* SPI mode control */ ++#define LOCOMO_SPICT_CRC16_7_B (1 << 15) /* 0: crc16 1: crc7 */ ++#define LOCOMO_SPICT_CRCRX_TX_B (1 << 14) ++#define LOCOMO_SPICT_CRCRESET_B (1 << 13) ++#define LOCOMO_SPICT_CEN (1 << 7) /* ?? enable */ ++#define LOCOMO_SPICT_CS (1 << 6) /* chip select */ ++#define LOCOMO_SPICT_UNIT16 (1 << 5) /* 0: 8 bit, 1: 16 bit*/ ++#define LOCOMO_SPICT_ALIGNEN (1 << 2) /* align transfer enable */ ++#define LOCOMO_SPICT_RXWEN (1 << 1) /* continuous receive */ ++#define LOCOMO_SPICT_RXUEN (1 << 0) /* aligned receive */ ++ ++#define LOCOMO_SPIST 0x68 /* SPI status */ ++#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */ ++#define LOCOMO_SPI_REND (1 << 2) /* Receive end bit */ ++#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */ ++#define LOCOMO_SPI_RFR (1) /* read buffer bit */ ++ ++#define LOCOMO_SPIIS 0x70 /* SPI interrupt status */ ++#define LOCOMO_SPIWE 0x74 /* SPI interrupt status write enable */ ++#define LOCOMO_SPIIE 0x78 /* SPI interrupt enable */ ++#define LOCOMO_SPIIR 0x7c /* SPI interrupt request */ ++#define LOCOMO_SPITD 0x80 /* SPI transfer data write */ ++#define LOCOMO_SPIRD 0x84 /* SPI receive data read */ ++#define LOCOMO_SPITS 0x88 /* SPI transfer data shift */ ++#define LOCOMO_SPIRS 0x8C /* SPI receive data shift */ ++ ++/* GPIO */ ++#define LOCOMO_GPD 0x90 /* GPIO direction */ ++#define LOCOMO_GPE 0x94 /* GPIO input enable */ ++#define LOCOMO_GPL 0x98 /* GPIO level */ ++#define LOCOMO_GPO 0x9c /* GPIO out data setting */ ++#define LOCOMO_GRIE 0xa0 /* GPIO rise detection */ ++#define LOCOMO_GFIE 0xa4 /* GPIO fall detection */ ++#define LOCOMO_GIS 0xa8 /* GPIO edge detection status */ ++#define LOCOMO_GWE 0xac /* GPIO status write enable */ ++#define LOCOMO_GIE 0xb0 /* GPIO interrupt enable */ ++#define LOCOMO_GIR 0xb4 /* GPIO interrupt request */ ++ ++/* Front light adjustment controller */ ++#define LOCOMO_ALS 0xc8 /* Adjust light cycle */ ++#define LOCOMO_ALS_EN 0x8000 ++#define LOCOMO_ALD 0xcc /* Adjust light duty */ ++ ++/* PCM audio interface */ ++#define LOCOMO_PAIF 0xd0 /* PCM audio interface */ ++#define LOCOMO_PAIF_SCINV 0x20 ++#define LOCOMO_PAIF_SCEN 0x10 ++#define LOCOMO_PAIF_LRCRST 0x08 ++#define LOCOMO_PAIF_LRCEVE 0x04 ++#define LOCOMO_PAIF_LRCINV 0x02 ++#define LOCOMO_PAIF_LRCEN 0x01 ++ ++/* Long time timer */ ++#define LOCOMO_LTC 0xd8 /* LTC interrupt setting */ ++#define LOCOMO_LTINT 0xdc /* LTC interrupt */ ++ ++/* DAC control signal for LCD (COMADJ ) */ ++#define LOCOMO_DAC 0xe0 ++/* DAC control */ ++#define LOCOMO_DAC_SCLOEB 0x08 /* SCL pin output data */ ++#define LOCOMO_DAC_TEST 0x04 /* Test bit */ ++#define LOCOMO_DAC_SDA 0x02 /* SDA pin level (read-only) */ ++#define LOCOMO_DAC_SDAOEB 0x01 /* SDA pin output data */ ++ ++/* LED controller */ ++#define LOCOMO_LPT0 0xe8 ++#define LOCOMO_LPT1 0xec ++#define LOCOMO_LPT_TOFH 0x80 ++#define LOCOMO_LPT_TOFL 0x08 ++#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4) ++#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7)) ++ ++struct locomo_gpio_platform_data { ++ unsigned int gpio_base; ++}; ++ ++struct locomo_lcd_platform_data { ++ u8 comadj; ++}; ++ ++struct locomo_platform_data { ++ unsigned int gpio_base; ++ u8 comadj; ++}; ++ ++#endif +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0003-leds-port-locomo-leds-driver-to-new-locomo-core.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0003-leds-port-locomo-leds-driver-to-new-locomo-core.patch new file mode 100644 index 0000000..127129c --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0003-leds-port-locomo-leds-driver-to-new-locomo-core.patch @@ -0,0 +1,187 @@ +From 9ce7fe614b1251e1eb04b714bcb07d48d664e9ca Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:04:12 +0400 +Subject: [PATCH 03/20] leds: port locomo leds driver to new locomo core + +Adapt locomo leds driver to new locomo core setup. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/leds/Kconfig | 1 - + drivers/leds/leds-locomo.c | 116 +++++++++++++++++++++++++-------------------- + 2 files changed, 65 insertions(+), 52 deletions(-) + +diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig +index 25b320d..aec42ae 100644 +--- a/drivers/leds/Kconfig ++++ b/drivers/leds/Kconfig +@@ -79,7 +79,6 @@ config LEDS_LM3642 + config LEDS_LOCOMO + tristate "LED Support for Locomo device" + depends on LEDS_CLASS +- depends on SHARP_LOCOMO + help + This option enables support for the LEDs on Sharp Locomo. + Zaurus models SL-5500 and SL-5600. +diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c +index 80ba048..cecc585 100644 +--- a/drivers/leds/leds-locomo.c ++++ b/drivers/leds/leds-locomo.c +@@ -9,89 +9,103 @@ + */ + + #include <linux/kernel.h> +-#include <linux/init.h> +-#include <linux/module.h> +-#include <linux/device.h> + #include <linux/leds.h> +- +-#include <mach/hardware.h> +-#include <asm/hardware/locomo.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/mfd/locomo.h> ++ ++struct locomo_led { ++ struct led_classdev led; ++ struct regmap *regmap; ++ unsigned int reg; ++}; + + static void locomoled_brightness_set(struct led_classdev *led_cdev, +- enum led_brightness value, int offset) ++ enum led_brightness value) + { +- struct locomo_dev *locomo_dev = LOCOMO_DEV(led_cdev->dev->parent); +- unsigned long flags; +- +- local_irq_save(flags); +- if (value) +- locomo_writel(LOCOMO_LPT_TOFH, locomo_dev->mapbase + offset); +- else +- locomo_writel(LOCOMO_LPT_TOFL, locomo_dev->mapbase + offset); +- local_irq_restore(flags); ++ struct locomo_led *led = container_of(led_cdev, struct locomo_led, led); ++ ++ regmap_write(led->regmap, led->reg, ++ value ? LOCOMO_LPT_TOFH : LOCOMO_LPT_TOFL); + } + +-static void locomoled_brightness_set0(struct led_classdev *led_cdev, +- enum led_brightness value) ++static int locomo_led_register( ++ struct locomo_led *led, ++ struct device *dev, ++ const char *name, ++ const char *trigger, ++ struct regmap *regmap, ++ unsigned int reg) + { +- locomoled_brightness_set(led_cdev, value, LOCOMO_LPT0); ++ led->led.name = name; ++ led->led.flags = LED_CORE_SUSPENDRESUME; ++ led->led.default_trigger = trigger; ++ led->led.brightness_set = locomoled_brightness_set; ++ led->regmap = regmap; ++ led->reg = reg; ++ ++ return led_classdev_register(dev, &led->led); + } + +-static void locomoled_brightness_set1(struct led_classdev *led_cdev, +- enum led_brightness value) ++static int locomoled_probe(struct platform_device *pdev) + { +- locomoled_brightness_set(led_cdev, value, LOCOMO_LPT1); +-} ++ int ret; ++ struct locomo_led *leds; ++ struct regmap *regmap; + +-static struct led_classdev locomo_led0 = { +- .name = "locomo:amber:charge", +- .default_trigger = "main-battery-charging", +- .brightness_set = locomoled_brightness_set0, +-}; ++ leds = devm_kzalloc(&pdev->dev, 2 * sizeof(*leds), GFP_KERNEL); ++ if (!leds) ++ return -ENOMEM; + +-static struct led_classdev locomo_led1 = { +- .name = "locomo:green:mail", +- .default_trigger = "nand-disk", +- .brightness_set = locomoled_brightness_set1, +-}; ++ regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!regmap) ++ return -ENODEV; + +-static int locomoled_probe(struct locomo_dev *ldev) +-{ +- int ret; ++ platform_set_drvdata(pdev, leds); + +- ret = led_classdev_register(&ldev->dev, &locomo_led0); ++ ret = locomo_led_register(leds, ++ &pdev->dev, ++ "locomo:amber:charge", ++ "main-battery-charging", ++ regmap, ++ LOCOMO_LPT0); + if (ret < 0) + return ret; + +- ret = led_classdev_register(&ldev->dev, &locomo_led1); ++ ret = locomo_led_register(leds + 1, ++ &pdev->dev, ++ "locomo:green:mail", ++ "mmc0", ++ regmap, ++ LOCOMO_LPT1); + if (ret < 0) +- led_classdev_unregister(&locomo_led0); ++ led_classdev_unregister(&leds[0].led); + + return ret; + } + +-static int locomoled_remove(struct locomo_dev *dev) ++static int locomoled_remove(struct platform_device *pdev) + { +- led_classdev_unregister(&locomo_led0); +- led_classdev_unregister(&locomo_led1); ++ struct locomo_led *leds = platform_get_drvdata(pdev); ++ ++ led_classdev_unregister(&leds[0].led); ++ led_classdev_unregister(&leds[1].led); ++ + return 0; + } + +-static struct locomo_driver locomoled_driver = { +- .drv = { +- .name = "locomoled" ++static struct platform_driver locomoled_driver = { ++ .driver = { ++ .name = "locomo-led" + }, +- .devid = LOCOMO_DEVID_LED, + .probe = locomoled_probe, + .remove = locomoled_remove, + }; + +-static int __init locomoled_init(void) +-{ +- return locomo_driver_register(&locomoled_driver); +-} +-module_init(locomoled_init); ++module_platform_driver(locomoled_driver); + + MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); + MODULE_DESCRIPTION("Locomo LED driver"); + MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:locomo-led"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch new file mode 100644 index 0000000..03a2023 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0004-input-convert-LoCoMo-keyboard-driver-to-use-new-loco.patch @@ -0,0 +1,480 @@ +From c546d0c1ae4e7134cfc2668bf4e01753dfb9a98d Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:06:46 +0400 +Subject: [PATCH 04/20] input: convert LoCoMo keyboard driver to use new locomo + core + +As LoCoMo is switching to new device model, adapt keyboard driver to +support new locomo core driver. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/input/keyboard/Kconfig | 1 - + drivers/input/keyboard/locomokbd.c | 271 +++++++++++++++++++------------------ + 2 files changed, 143 insertions(+), 129 deletions(-) + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index a89ba7c..4e20538 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -337,7 +337,6 @@ config KEYBOARD_LM8333 + + config KEYBOARD_LOCOMO + tristate "LoCoMo Keyboard Support" +- depends on SHARP_LOCOMO + help + Say Y here if you are running Linux on a Sharp Zaurus Collie or Poodle based PDA + +diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c +index c94d610..eed0a94 100644 +--- a/drivers/input/keyboard/locomokbd.c ++++ b/drivers/input/keyboard/locomokbd.c +@@ -23,37 +23,37 @@ + * + */ + +-#include <linux/slab.h> +-#include <linux/module.h> ++#include <linux/delay.h> + #include <linux/init.h> + #include <linux/input.h> +-#include <linux/delay.h> +-#include <linux/device.h> + #include <linux/interrupt.h> +-#include <linux/ioport.h> +- +-#include <asm/hardware/locomo.h> +-#include <asm/irq.h> +- +-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); +-MODULE_DESCRIPTION("LoCoMo keyboard driver"); +-MODULE_LICENSE("GPL"); ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/slab.h> ++#include <linux/mfd/locomo.h> + +-#define LOCOMOKBD_NUMKEYS 128 ++/* There is one minor difference between mappings on poodle and collie */ ++#include <asm/mach-types.h> + + #define KEY_ACTIVITY KEY_F16 + #define KEY_CONTACT KEY_F18 + #define KEY_CENTER KEY_F15 + ++#define KB_ROWS 16 ++#define KB_COLS 8 ++#define LOCOMOKBD_NUMKEYS (KB_ROWS * KB_COLS) ++#define SCANCODE(c, r) (((c)<<4) + (r) + 1) ++ + static const unsigned char + locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { + 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ +- 0, 0, 0, 0, 0, 0, 0, KEY_MENU, KEY_HOME, KEY_CONTACT, /* 10 - 19 */ ++ 0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, KEY_CONTACT, /* 10 - 19 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ + 0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0, /* 30 - 39 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT, /* 40 - 49 */ + KEY_UP, KEY_LEFT, 0, 0, KEY_P, 0, KEY_O, KEY_I, KEY_Y, KEY_T, /* 50 - 59 */ +- KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_ENTER, 0, 0, /* 60 - 69 */ ++ KEY_E, KEY_W, 0, 0, 0, 0, KEY_DOWN, KEY_KPENTER, 0, 0, /* 60 - 69 */ + KEY_BACKSPACE, 0, KEY_L, KEY_U, KEY_H, KEY_R, KEY_D, KEY_Q, 0, 0, /* 70 - 79 */ + 0, 0, 0, 0, 0, 0, KEY_ENTER, KEY_RIGHTSHIFT, KEY_K, KEY_J, /* 80 - 89 */ + KEY_G, KEY_F, KEY_X, KEY_S, 0, 0, 0, 0, 0, 0, /* 90 - 99 */ +@@ -62,20 +62,14 @@ locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { + KEY_M, KEY_SPACE, KEY_V, KEY_APOSTROPHE, KEY_SLASH, 0, 0, 0 /* 120 - 128 */ + }; + +-#define KB_ROWS 16 +-#define KB_COLS 8 +-#define KB_ROWMASK(r) (1 << (r)) +-#define SCANCODE(c,r) ( ((c)<<4) + (r) + 1 ) +- + #define KB_DELAY 8 +-#define SCAN_INTERVAL (HZ/10) + + struct locomokbd { + unsigned char keycode[LOCOMOKBD_NUMKEYS]; + struct input_dev *input; +- char phys[32]; + +- unsigned long base; ++ struct regmap *regmap; ++ int irq; + spinlock_t lock; + + struct timer_list timer; +@@ -84,37 +78,33 @@ struct locomokbd { + }; + + /* helper functions for reading the keyboard matrix */ +-static inline void locomokbd_charge_all(unsigned long membase) ++static inline void locomokbd_charge_all(struct locomokbd *locomokbd) + { +- locomo_writel(0x00FF, membase + LOCOMO_KSC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x00ff); + } + +-static inline void locomokbd_activate_all(unsigned long membase) ++static inline void locomokbd_activate_all(struct locomokbd *locomokbd) + { +- unsigned long r; +- +- locomo_writel(0, membase + LOCOMO_KSC); +- r = locomo_readl(membase + LOCOMO_KIC); +- r &= 0xFEFF; +- locomo_writel(r, membase + LOCOMO_KIC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0); + } + +-static inline void locomokbd_activate_col(unsigned long membase, int col) ++static inline void locomokbd_activate_col(struct locomokbd *locomokbd, int col) + { + unsigned short nset; + unsigned short nbset; + +- nset = 0xFF & ~(1 << col); ++ nset = 0xFF & ~BIT(col); + nbset = (nset << 8) + nset; +- locomo_writel(nbset, membase + LOCOMO_KSC); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset); + } + +-static inline void locomokbd_reset_col(unsigned long membase, int col) ++static inline void locomokbd_reset_col(struct locomokbd *locomokbd, int col) + { + unsigned short nbset; + +- nbset = ((0xFF & ~(1 << col)) << 8) + 0xFF; +- locomo_writel(nbset, membase + LOCOMO_KSC); ++ nbset = ((0xFF & ~BIT(col)) << 8) + 0xFF; ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, nbset); + } + + /* +@@ -129,24 +119,25 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + unsigned int row, col, rowd; + unsigned long flags; + unsigned int num_pressed; +- unsigned long membase = locomokbd->base; ++ bool esc_pressed = false; + + spin_lock_irqsave(&locomokbd->lock, flags); + +- locomokbd_charge_all(membase); ++ locomokbd_charge_all(locomokbd); + + num_pressed = 0; + for (col = 0; col < KB_COLS; col++) { +- +- locomokbd_activate_col(membase, col); ++ udelay(KB_DELAY); ++ locomokbd_activate_col(locomokbd, col); + udelay(KB_DELAY); + +- rowd = ~locomo_readl(membase + LOCOMO_KIB); ++ regmap_read(locomokbd->regmap, LOCOMO_KIB, &rowd); ++ rowd = ~rowd; + for (row = 0; row < KB_ROWS; row++) { + unsigned int scancode, pressed, key; + + scancode = SCANCODE(col, row); +- pressed = rowd & KB_ROWMASK(row); ++ pressed = rowd & BIT(row); + key = locomokbd->keycode[scancode]; + + input_report_key(locomokbd->input, key, pressed); +@@ -158,29 +149,30 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + /* The "Cancel/ESC" key is labeled "On/Off" on + * Collie and Poodle and should suspend the device + * if it was pressed for more than a second. */ +- if (unlikely(key == KEY_ESC)) { +- if (!time_after(jiffies, +- locomokbd->suspend_jiffies + HZ)) +- continue; +- if (locomokbd->count_cancel++ +- != (HZ/SCAN_INTERVAL + 1)) +- continue; +- input_event(locomokbd->input, EV_PWR, +- KEY_SUSPEND, 1); +- locomokbd->suspend_jiffies = jiffies; +- } else +- locomokbd->count_cancel = 0; ++ if (unlikely(key == KEY_ESC)) ++ esc_pressed = true; + } +- locomokbd_reset_col(membase, col); ++ locomokbd_reset_col(locomokbd, col); + } +- locomokbd_activate_all(membase); ++ locomokbd_activate_all(locomokbd); + + input_sync(locomokbd->input); + + /* if any keys are pressed, enable the timer */ + if (num_pressed) +- mod_timer(&locomokbd->timer, jiffies + SCAN_INTERVAL); ++ mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(100)); + else ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); ++ ++ ++ if (esc_pressed && time_after(jiffies, ++ locomokbd->suspend_jiffies + msecs_to_jiffies(1000))) { ++ if (locomokbd->count_cancel++ > (20)) { ++ input_event(locomokbd->input, EV_PWR, ++ KEY_SUSPEND, 1); ++ locomokbd->suspend_jiffies = jiffies; ++ } ++ } else + locomokbd->count_cancel = 0; + + spin_unlock_irqrestore(&locomokbd->lock, flags); +@@ -192,18 +184,18 @@ static void locomokbd_scankeyboard(struct locomokbd *locomokbd) + static irqreturn_t locomokbd_interrupt(int irq, void *dev_id) + { + struct locomokbd *locomokbd = dev_id; +- u16 r; ++ unsigned int r; + +- r = locomo_readl(locomokbd->base + LOCOMO_KIC); ++ ++ regmap_read(locomokbd->regmap, LOCOMO_KIC, &r); + if ((r & 0x0001) == 0) + return IRQ_HANDLED; + +- locomo_writel(r & ~0x0100, locomokbd->base + LOCOMO_KIC); /* Ack */ ++ /* Mask and Ack */ ++ regmap_write(locomokbd->regmap, LOCOMO_KIC, r & ~0x110); + +- /** wait chattering delay **/ +- udelay(100); ++ mod_timer(&locomokbd->timer, jiffies + msecs_to_jiffies(1)); + +- locomokbd_scankeyboard(locomokbd); + return IRQ_HANDLED; + } + +@@ -220,47 +212,37 @@ static void locomokbd_timer_callback(unsigned long data) + static int locomokbd_open(struct input_dev *dev) + { + struct locomokbd *locomokbd = input_get_drvdata(dev); +- u16 r; +- +- r = locomo_readl(locomokbd->base + LOCOMO_KIC) | 0x0010; +- locomo_writel(r, locomokbd->base + LOCOMO_KIC); +- return 0; ++ ++ return regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); + } + + static void locomokbd_close(struct input_dev *dev) + { + struct locomokbd *locomokbd = input_get_drvdata(dev); +- u16 r; +- +- r = locomo_readl(locomokbd->base + LOCOMO_KIC) & ~0x0010; +- locomo_writel(r, locomokbd->base + LOCOMO_KIC); ++ ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0); + } + +-static int locomokbd_probe(struct locomo_dev *dev) ++static int locomokbd_probe(struct platform_device *dev) + { + struct locomokbd *locomokbd; + struct input_dev *input_dev; + int i, err; + +- locomokbd = kzalloc(sizeof(struct locomokbd), GFP_KERNEL); +- input_dev = input_allocate_device(); +- if (!locomokbd || !input_dev) { +- err = -ENOMEM; +- goto err_free_mem; +- } ++ locomokbd = devm_kzalloc(&dev->dev, sizeof(struct locomokbd), ++ GFP_KERNEL); ++ if (!locomokbd) ++ return -ENOMEM; + +- /* try and claim memory region */ +- if (!request_mem_region((unsigned long) dev->mapbase, +- dev->length, +- LOCOMO_DRIVER_NAME(dev))) { +- err = -EBUSY; +- printk(KERN_ERR "locomokbd: Can't acquire access to io memory for keyboard\n"); +- goto err_free_mem; +- } ++ locomokbd->regmap = dev_get_regmap(dev->dev.parent, NULL); ++ if (!locomokbd->regmap) ++ return -EINVAL; + +- locomo_set_drvdata(dev, locomokbd); ++ locomokbd->irq = platform_get_irq(dev, 0); ++ if (locomokbd->irq < 0) ++ return -ENXIO; + +- locomokbd->base = (unsigned long) dev->mapbase; ++ platform_set_drvdata(dev, locomokbd); + + spin_lock_init(&locomokbd->lock); + +@@ -270,11 +252,13 @@ static int locomokbd_probe(struct locomo_dev *dev) + + locomokbd->suspend_jiffies = jiffies; + +- locomokbd->input = input_dev; +- strcpy(locomokbd->phys, "locomokbd/input0"); ++ input_dev = input_allocate_device(); ++ if (!input_dev) ++ return -ENOMEM; + ++ locomokbd->input = input_dev; + input_dev->name = "LoCoMo keyboard"; +- input_dev->phys = locomokbd->phys; ++ input_dev->phys = "locomokbd/input0"; + input_dev->id.bustype = BUS_HOST; + input_dev->id.vendor = 0x0001; + input_dev->id.product = 0x0001; +@@ -291,16 +275,30 @@ static int locomokbd_probe(struct locomo_dev *dev) + + input_set_drvdata(input_dev, locomokbd); + +- memcpy(locomokbd->keycode, locomokbd_keycode, sizeof(locomokbd->keycode)); ++ memcpy(locomokbd->keycode, ++ locomokbd_keycode, ++ sizeof(locomokbd->keycode)); ++ ++ if (machine_is_collie()) ++ locomokbd->keycode[18] = KEY_HOME; ++ else ++ locomokbd->keycode[3] = KEY_HOME; ++ + for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) +- set_bit(locomokbd->keycode[i], input_dev->keybit); +- clear_bit(0, input_dev->keybit); ++ input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]); ++ input_set_capability(input_dev, EV_PWR, KEY_SUSPEND); ++ __set_bit(EV_REP, input_dev->evbit); ++ ++ regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0x0); ++ regmap_write(locomokbd->regmap, LOCOMO_KIC, 0x0); + + /* attempt to get the interrupt */ +- err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd); ++ err = request_irq(locomokbd->irq, locomokbd_interrupt, 0, ++ "locomokbd", locomokbd); + if (err) { +- printk(KERN_ERR "locomokbd: Can't get irq for keyboard\n"); +- goto err_release_region; ++ dev_err(&dev->dev, "locomokbd: Can't get irq for keyboard\n"); ++ goto err_free_mem; + } + + err = input_register_device(locomokbd->input); +@@ -309,54 +307,71 @@ static int locomokbd_probe(struct locomo_dev *dev) + + return 0; + +- err_free_irq: +- free_irq(dev->irq[0], locomokbd); +- err_release_region: +- release_mem_region((unsigned long) dev->mapbase, dev->length); +- locomo_set_drvdata(dev, NULL); +- err_free_mem: ++err_free_irq: ++ free_irq(locomokbd->irq, locomokbd); ++err_free_mem: + input_free_device(input_dev); +- kfree(locomokbd); + + return err; + } + +-static int locomokbd_remove(struct locomo_dev *dev) ++static int locomokbd_remove(struct platform_device *dev) + { +- struct locomokbd *locomokbd = locomo_get_drvdata(dev); ++ struct locomokbd *locomokbd = platform_get_drvdata(dev); + +- free_irq(dev->irq[0], locomokbd); ++ free_irq(locomokbd->irq, locomokbd); + + del_timer_sync(&locomokbd->timer); + + input_unregister_device(locomokbd->input); +- locomo_set_drvdata(dev, NULL); + +- release_mem_region((unsigned long) dev->mapbase, dev->length); ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomokbd_suspend(struct device *dev) ++{ ++ struct locomokbd *locomokbd = dev_get_drvdata(dev); ++ ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x0); + +- kfree(locomokbd); ++ del_timer_sync(&locomokbd->timer); + + return 0; + } + +-static struct locomo_driver keyboard_driver = { +- .drv = { +- .name = "locomokbd" ++static int locomokbd_resume(struct device *dev) ++{ ++ struct locomokbd *locomokbd = dev_get_drvdata(dev); ++ ++ regmap_write(locomokbd->regmap, LOCOMO_KCMD, 1); ++ regmap_write(locomokbd->regmap, LOCOMO_KSC, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x100, 0); ++ regmap_update_bits(locomokbd->regmap, LOCOMO_KIC, 0x10, 0x10); ++ ++ locomokbd_scankeyboard(locomokbd); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(locomo_kbd_pm, locomokbd_suspend, locomokbd_resume); ++#define LOCOMO_KBD_PM (&locomo_kbd_pm) ++#else ++#define LOCOMO_KBD_PM NULL ++#endif ++ ++static struct platform_driver locomokbd_driver = { ++ .driver = { ++ .name = "locomo-kbd", ++ .pm = LOCOMO_KBD_PM, + }, +- .devid = LOCOMO_DEVID_KEYBOARD, + .probe = locomokbd_probe, + .remove = locomokbd_remove, + }; + +-static int __init locomokbd_init(void) +-{ +- return locomo_driver_register(&keyboard_driver); +-} +- +-static void __exit locomokbd_exit(void) +-{ +- locomo_driver_unregister(&keyboard_driver); +-} ++module_platform_driver(locomokbd_driver); + +-module_init(locomokbd_init); +-module_exit(locomokbd_exit); ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_DESCRIPTION("LoCoMo keyboard driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:locomo-kbd"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0005-input-locomokbd-provide-an-Alt-SysRQ-combination.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0005-input-locomokbd-provide-an-Alt-SysRQ-combination.patch new file mode 100644 index 0000000..6ccda75 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0005-input-locomokbd-provide-an-Alt-SysRQ-combination.patch @@ -0,0 +1,75 @@ +From d947e63ae4890ac4ecd6f408f68dbcafdcc34482 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Wed, 3 Dec 2014 20:26:56 +0300 +Subject: [PATCH 05/20] input: locomokbd: provide an Alt-SysRQ combination + +It is usefull sometimes to have an Alt-SysRQ combo on the keyboard to be +able to trigger sysrq functions directly. Add an option providing sysrq +mapping for Contact-Home keys. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/input/keyboard/Kconfig | 6 ++++++ + drivers/input/keyboard/locomokbd.c | 14 +++++++++++--- + 2 files changed, 17 insertions(+), 3 deletions(-) + +diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig +index 4e20538..8d6d4a8 100644 +--- a/drivers/input/keyboard/Kconfig ++++ b/drivers/input/keyboard/Kconfig +@@ -343,6 +343,12 @@ config KEYBOARD_LOCOMO + To compile this driver as a module, choose M here: the + module will be called locomokbd. + ++config KEYBOARD_LOCOMOKBD_SYSRQ ++ bool "Provide SysRQ key on LoCoMo keyboard" ++ help ++ Say Y here to be able to use Contact-Home as Alt-Sysrq combo. ++ Say N if you want to use them as usual keys. ++ + config KEYBOARD_LPC32XX + tristate "LPC32XX matrix key scanner support" + depends on ARCH_LPC32XX && OF +diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c +index eed0a94..eb8dbe2 100644 +--- a/drivers/input/keyboard/locomokbd.c ++++ b/drivers/input/keyboard/locomokbd.c +@@ -40,6 +40,14 @@ + #define KEY_CONTACT KEY_F18 + #define KEY_CENTER KEY_F15 + ++#ifdef CONFIG_KEYBOARD_LOCOMOKBD_SYSRQ ++#define LOCOMO_KEY_CONTACT KEY_LEFTALT ++#define LOCOMO_KEY_HOME KEY_SYSRQ ++#else ++#define LOCOMO_KEY_CONTACT KEY_CONTACT ++#define LOCOMO_KEY_HOME KEY_HOME ++#endif ++ + #define KB_ROWS 16 + #define KB_COLS 8 + #define LOCOMOKBD_NUMKEYS (KB_ROWS * KB_COLS) +@@ -48,7 +56,7 @@ + static const unsigned char + locomokbd_keycode[LOCOMOKBD_NUMKEYS] = { + 0, KEY_ESC, KEY_ACTIVITY, 0, 0, 0, 0, 0, 0, 0, /* 0 - 9 */ +- 0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, KEY_CONTACT, /* 10 - 19 */ ++ 0, 0, 0, 0, 0, 0, 0, KEY_MENU, 0, LOCOMO_KEY_CONTACT, /* 10 - 19 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 29 */ + 0, 0, 0, KEY_CENTER, 0, KEY_MAIL, 0, 0, 0, 0, /* 30 - 39 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, KEY_RIGHT, /* 40 - 49 */ +@@ -280,9 +288,9 @@ static int locomokbd_probe(struct platform_device *dev) + sizeof(locomokbd->keycode)); + + if (machine_is_collie()) +- locomokbd->keycode[18] = KEY_HOME; ++ locomokbd->keycode[18] = LOCOMO_KEY_HOME; + else +- locomokbd->keycode[3] = KEY_HOME; ++ locomokbd->keycode[3] = LOCOMO_KEY_HOME; + + for (i = 0; i < LOCOMOKBD_NUMKEYS; i++) + input_set_capability(input_dev, EV_KEY, locomokbd->keycode[i]); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0006-video-backlight-add-new-locomo-backlight-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0006-video-backlight-add-new-locomo-backlight-driver.patch new file mode 100644 index 0000000..cf2ebe7 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0006-video-backlight-add-new-locomo-backlight-driver.patch @@ -0,0 +1,212 @@ +From 3be6ca10a2c5275f6c89818b7478b21567dc3cf3 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:10:17 +0400 +Subject: [PATCH 06/20] video: backlight: add new locomo backlight driver + +Add new simple backlight driver - it cares only about PWM/frontlight +part of LoCoMo, it does not touch TFT settings and does not export TFT +power control. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/video/backlight/Kconfig | 6 +- + drivers/video/backlight/Makefile | 2 +- + drivers/video/backlight/locomo_bl.c | 153 ++++++++++++++++++++++++++++++++++++ + 3 files changed, 157 insertions(+), 4 deletions(-) + create mode 100644 drivers/video/backlight/locomo_bl.c + +diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig +index efb0904..540ab64 100644 +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -217,12 +217,12 @@ config BACKLIGHT_LM3533 + levels. + + config BACKLIGHT_LOCOMO +- tristate "Sharp LOCOMO LCD/Backlight Driver" +- depends on SHARP_LOCOMO ++ tristate "Sharp LOCOMO Backlight Driver" ++ depends on MFD_LOCOMO + default y + help + If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to +- enable the LCD/backlight driver. ++ enable the backlight driver. + + config BACKLIGHT_OMAP1 + tristate "OMAP1 PWL-based LCD Backlight" +diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile +index fcd50b73..2a61b7e 100644 +--- a/drivers/video/backlight/Makefile ++++ b/drivers/video/backlight/Makefile +@@ -39,7 +39,7 @@ obj-$(CONFIG_BACKLIGHT_IPAQ_MICRO) += ipaq_micro_bl.o + obj-$(CONFIG_BACKLIGHT_LM3533) += lm3533_bl.o + obj-$(CONFIG_BACKLIGHT_LM3630A) += lm3630a_bl.o + obj-$(CONFIG_BACKLIGHT_LM3639) += lm3639_bl.o +-obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomolcd.o ++obj-$(CONFIG_BACKLIGHT_LOCOMO) += locomo_bl.o + obj-$(CONFIG_BACKLIGHT_LP855X) += lp855x_bl.o + obj-$(CONFIG_BACKLIGHT_LP8788) += lp8788_bl.o + obj-$(CONFIG_BACKLIGHT_LV5207LP) += lv5207lp.o +diff --git a/drivers/video/backlight/locomo_bl.c b/drivers/video/backlight/locomo_bl.c +new file mode 100644 +index 0000000..cc60022 +--- /dev/null ++++ b/drivers/video/backlight/locomo_bl.c +@@ -0,0 +1,153 @@ ++/* ++ * Backlight control code for Sharp Zaurus SL-5500 ++ * ++ * Copyright 2005 John Lenz <lenz@cs.wisc.edu> ++ * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) ++ * GPL v2 ++ * ++ * This driver assumes single CPU. That's okay, because collie is ++ * slightly old hardware, and no one is going to retrofit second CPU to ++ * old PDA. ++ */ ++ ++#include <linux/backlight.h> ++#include <linux/delay.h> ++#include <linux/fb.h> ++#include <linux/gpio/consumer.h> ++#include <linux/mfd/locomo.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++ ++struct locomo_bl { ++ struct regmap *regmap; ++ int current_intensity; ++ struct gpio_desc *fl_vr; ++}; ++ ++static const struct { ++ u16 duty, bpwf; ++ bool vr; ++} locomo_bl_pwm[] = { ++ { 0, 161, false }, ++ { 117, 161, false }, ++ { 163, 148, false }, ++ { 194, 161, false }, ++ { 194, 161, true }, ++}; ++ ++static int locomo_bl_set_intensity(struct backlight_device *bd) ++{ ++ int intensity = bd->props.brightness; ++ struct locomo_bl *bl = dev_get_drvdata(&bd->dev); ++ ++ if (bd->props.power != FB_BLANK_UNBLANK) ++ intensity = 0; ++ if (bd->props.fb_blank != FB_BLANK_UNBLANK) ++ intensity = 0; ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ intensity = 0; ++ ++ gpiod_set_value(bl->fl_vr, locomo_bl_pwm[intensity].vr); ++ ++ regmap_write(bl->regmap, LOCOMO_ALS, locomo_bl_pwm[intensity].bpwf); ++ usleep_range(100, 200); ++ regmap_write(bl->regmap, LOCOMO_ALD, locomo_bl_pwm[intensity].duty); ++ usleep_range(100, 200); ++ regmap_write(bl->regmap, LOCOMO_ALS, locomo_bl_pwm[intensity].bpwf | ++ LOCOMO_ALS_EN); ++ ++ bl->current_intensity = intensity; ++ if (bd->props.state & BL_CORE_SUSPENDED) ++ regmap_write(bl->regmap, LOCOMO_ALS, 0x00); ++ ++ return 0; ++} ++ ++static int locomo_bl_get_intensity(struct backlight_device *bd) ++{ ++ struct locomo_bl *bl = dev_get_drvdata(&bd->dev); ++ ++ return bl->current_intensity; ++} ++ ++static const struct backlight_ops locomo_bl_ops = { ++ .options = BL_CORE_SUSPENDRESUME, ++ .get_brightness = locomo_bl_get_intensity, ++ .update_status = locomo_bl_set_intensity, ++}; ++ ++static int locomo_bl_probe(struct platform_device *dev) ++{ ++ struct backlight_properties props; ++ struct locomo_bl *bl; ++ struct backlight_device *locomo_bl_device; ++ ++ bl = devm_kmalloc(&dev->dev, sizeof(struct locomo_bl), GFP_KERNEL); ++ if (!bl) ++ return -ENOMEM; ++ ++ bl->regmap = dev_get_regmap(dev->dev.parent, NULL); ++ if (!bl->regmap) ++ return -ENODEV; ++ ++ bl->fl_vr = devm_gpiod_get(&dev->dev, "flvr", GPIOD_OUT_LOW); ++ if (IS_ERR(bl->fl_vr)) ++ return PTR_ERR(bl->fl_vr); ++ ++ regmap_write(bl->regmap, LOCOMO_ALS, 0); ++ regmap_write(bl->regmap, LOCOMO_ALD, 0); ++ ++ memset(&props, 0, sizeof(struct backlight_properties)); ++ props.type = BACKLIGHT_RAW; ++ props.max_brightness = ARRAY_SIZE(locomo_bl_pwm) - 1; ++ props.brightness = props.max_brightness / 2; ++ locomo_bl_device = devm_backlight_device_register(&dev->dev, ++ "locomo-bl", ++ &dev->dev, bl, ++ &locomo_bl_ops, &props); ++ ++ if (IS_ERR(locomo_bl_device)) ++ return PTR_ERR(locomo_bl_device); ++ ++ platform_set_drvdata(dev, locomo_bl_device); ++ ++ /* Set up frontlight so that screen is readable */ ++ backlight_update_status(locomo_bl_device); ++ ++ return 0; ++} ++ ++static void locomo_bl_shutdown(struct platform_device *dev) ++{ ++ struct backlight_device *locomo_bl_device = platform_get_drvdata(dev); ++ ++ locomo_bl_device->props.brightness = 0; ++ locomo_bl_device->props.power = 0; ++ locomo_bl_set_intensity(locomo_bl_device); ++} ++ ++static int locomo_bl_remove(struct platform_device *dev) ++{ ++ locomo_bl_shutdown(dev); ++ ++ return 0; ++} ++ ++static struct platform_driver locomo_bl_driver = { ++ .driver = { ++ .name = "locomo-backlight", ++ }, ++ .probe = locomo_bl_probe, ++ .remove = locomo_bl_remove, ++ /* Turn off bl on power off/reboot */ ++ .shutdown = locomo_bl_shutdown, ++}; ++ ++module_platform_driver(locomo_bl_driver); ++ ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_AUTHOR("Pavel Machek <pavel@ucw.cz>"); ++MODULE_DESCRIPTION("LoCoMo Backlight driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:locomo-backlight"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0007-video-lcd-add-LoCoMo-LCD-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0007-video-lcd-add-LoCoMo-LCD-driver.patch new file mode 100644 index 0000000..f9ea7eb --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0007-video-lcd-add-LoCoMo-LCD-driver.patch @@ -0,0 +1,343 @@ +From b85af3e957277b30a2ef51d605478a292a4be817 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Wed, 4 Dec 2013 23:58:34 +0400 +Subject: [PATCH 07/20] video: lcd: add LoCoMo LCD driver + +LoCoMo has some special handling for TFT screens attached to Collie and +Poodle. Implement that as a separate driver. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/video/backlight/Kconfig | 10 ++ + drivers/video/backlight/Makefile | 1 + + drivers/video/backlight/locomo_lcd.c | 285 +++++++++++++++++++++++++++++++++++ + 3 files changed, 296 insertions(+) + create mode 100644 drivers/video/backlight/locomo_lcd.c + +diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig +index 540ab64..ba0f43c 100644 +--- a/drivers/video/backlight/Kconfig ++++ b/drivers/video/backlight/Kconfig +@@ -48,6 +48,16 @@ config LCD_LMS283GF05 + SPI driver for Samsung LMS283GF05. This provides basic support + for powering the LCD up/down through a sysfs interface. + ++config LCD_LOCOMO ++ tristate "Sharp LOCOMO LCD Driver" ++ depends on MFD_LOCOMO ++ select IIO ++ help ++ If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to ++ enable the LCD driver. The panel starts up in power ++ off state, so you need this driver in order to see any ++ output. ++ + config LCD_LTV350QV + tristate "Samsung LTV350QV LCD Panel" + depends on SPI_MASTER +diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile +index 2a61b7e..bb360a2 100644 +--- a/drivers/video/backlight/Makefile ++++ b/drivers/video/backlight/Makefile +@@ -11,6 +11,7 @@ obj-$(CONFIG_LCD_L4F00242T03) += l4f00242t03.o + obj-$(CONFIG_LCD_LD9040) += ld9040.o + obj-$(CONFIG_LCD_LMS283GF05) += lms283gf05.o + obj-$(CONFIG_LCD_LMS501KF03) += lms501kf03.o ++obj-$(CONFIG_LCD_LOCOMO) += locomo_lcd.o + obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o + obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o + obj-$(CONFIG_LCD_S6E63M0) += s6e63m0.o +diff --git a/drivers/video/backlight/locomo_lcd.c b/drivers/video/backlight/locomo_lcd.c +new file mode 100644 +index 0000000..dc316cb +--- /dev/null ++++ b/drivers/video/backlight/locomo_lcd.c +@@ -0,0 +1,285 @@ ++/* ++ * Backlight control code for Sharp Zaurus SL-5500 ++ * ++ * Copyright 2005 John Lenz <lenz@cs.wisc.edu> ++ * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) ++ * GPL v2 ++ * ++ * This driver assumes single CPU. That's okay, because collie is ++ * slightly old hardware, and no one is going to retrofit second CPU to ++ * old PDA. ++ */ ++ ++#include <linux/delay.h> ++#include <linux/fb.h> ++#include <linux/gpio/consumer.h> ++#include <linux/iio/consumer.h> ++#include <linux/lcd.h> ++#include <linux/mfd/locomo.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++ ++struct locomo_lcd { ++ struct regmap *regmap; ++ struct platform_device *dev; ++ struct locomo_lcd_platform_data *data; ++ int power; ++ struct iio_channel *comadj; ++ struct gpio_desc *vsha, *vshd, *vee, *mod; ++}; ++ ++static void locomo_lcd_on(struct locomo_lcd *lcd) ++{ ++ gpiod_set_value(lcd->vsha, 1); ++ usleep_range(2000, 3000); ++ ++ gpiod_set_value(lcd->vshd, 1); ++ usleep_range(2000, 3000); ++ ++ iio_write_channel_raw(lcd->comadj, lcd->data->comadj); ++ usleep_range(5000, 6000); ++ ++ gpiod_set_value(lcd->vee, 1); ++ usleep_range(10000, 11000); ++ ++ /* TFTCRST | CPSOUT=0 | CPSEN */ ++ regmap_write(lcd->regmap, LOCOMO_TC, 0x01); ++ ++ /* Set CPSD */ ++ regmap_write(lcd->regmap, LOCOMO_CPSD, 6); ++ ++ /* TFTCRST | CPSOUT=0 | CPSEN */ ++ regmap_write(lcd->regmap, LOCOMO_TC, 0x04 | 0x01); ++ usleep_range(10000, 11000); ++ ++ gpiod_set_value(lcd->mod, 1); ++} ++ ++static void locomo_lcd_off(struct locomo_lcd *lcd) ++{ ++ /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */ ++ regmap_write(lcd->regmap, LOCOMO_TC, 0x06); ++ usleep_range(1000, 2000); ++ ++ gpiod_set_value(lcd->vsha, 0); ++ msleep(110); ++ ++ gpiod_set_value(lcd->vee, 0); ++ msleep(700); ++ ++ iio_write_channel_raw(lcd->comadj, 0); ++ usleep_range(5000, 6000); ++ ++ /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */ ++ regmap_write(lcd->regmap, LOCOMO_TC, 0); ++ gpiod_set_value(lcd->mod, 0); ++ gpiod_set_value(lcd->vshd, 0); ++} ++ ++static void locomo_lcd_program_adsync(struct locomo_lcd *lcd) ++{ ++ regmap_write(lcd->regmap, LOCOMO_ASD, ++ 6 + 8 + 320 + 30 - 10); ++ regmap_update_bits(lcd->regmap, LOCOMO_ASD, ++ 0x8000, ++ 0x8000); ++ ++ regmap_write(lcd->regmap, LOCOMO_HSD, ++ 6 + 8 + 320 + 30 - 10 - 128 + 4); ++ regmap_update_bits(lcd->regmap, LOCOMO_HSD, ++ 0x8000, ++ 0x8000); ++ ++ regmap_write(lcd->regmap, LOCOMO_HSC, 128 / 8); ++ ++ /* XON */ ++ regmap_write(lcd->regmap, LOCOMO_TADC, 0x80); ++ usleep_range(1000, 1100); ++ ++ /* CLK9MEN */ ++ regmap_update_bits(lcd->regmap, LOCOMO_TADC, ++ 0x10, ++ 0x10); ++ usleep_range(100, 200); ++} ++ ++static void locomo_lcd_disable_adsync(struct locomo_lcd *lcd) ++{ ++ /* ADSTART */ ++ regmap_write(lcd->regmap, LOCOMO_ASD, 0x00); ++ ++ /* 18MHz clock off*/ ++ regmap_write(lcd->regmap, LOCOMO_TADC, 0x00); ++} ++ ++int locomo_lcd_set_power(struct lcd_device *ldev, int power) ++{ ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ dev_dbg(&ldev->dev, "LCD power %d (is %d)\n", power, lcd->power); ++ ++ if (!power && lcd->power) ++ locomo_lcd_on(lcd); ++ ++ if (power && !lcd->power) ++ locomo_lcd_off(lcd); ++ ++ lcd->power = power; ++ ++ return 0; ++} ++ ++static int locomo_lcd_get_power(struct lcd_device *ldev) ++{ ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ return lcd->power; ++} ++ ++static struct lcd_ops locomo_lcd_ops = { ++ .set_power = locomo_lcd_set_power, ++ .get_power = locomo_lcd_get_power, ++}; ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomo_lcd_suspend(struct device *dev) ++{ ++ struct lcd_device *ldev = dev_get_drvdata(dev); ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ locomo_lcd_off(lcd); ++ ++ locomo_lcd_disable_adsync(lcd); ++ ++ return 0; ++} ++ ++static int locomo_lcd_resume(struct device *dev) ++{ ++ struct lcd_device *ldev = dev_get_drvdata(dev); ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ locomo_lcd_program_adsync(lcd); ++ ++ if (!lcd->power) ++ locomo_lcd_on(lcd); ++ ++ return 0; ++} ++ ++static SIMPLE_DEV_PM_OPS(locomo_lcd_pm, locomo_lcd_suspend, locomo_lcd_resume); ++#define LOCOMOLCD_PM (&locomo_lcd_pm) ++#else ++#define LOCOMOLCD_PM NULL ++#endif ++ ++static int locomo_lcd_probe(struct platform_device *dev) ++{ ++ struct lcd_device *lcd_dev; ++ struct locomo_lcd *lcd; ++ int rc; ++ ++ lcd = devm_kmalloc(&dev->dev, sizeof(struct locomo_lcd), GFP_KERNEL); ++ if (!lcd) ++ return -ENOMEM; ++ ++ lcd->dev = dev; ++ lcd->power = FB_BLANK_NORMAL; ++ ++ lcd->regmap = dev_get_regmap(dev->dev.parent, NULL); ++ if (!lcd->regmap) ++ return -ENODEV; ++ ++ lcd->data = dev_get_platdata(&dev->dev); ++ if (!lcd->data) ++ return -EINVAL; ++ ++ lcd->vsha = devm_gpiod_get(&dev->dev, "VSHA", GPIOD_OUT_LOW); ++ if (IS_ERR(lcd->vsha)) ++ return PTR_ERR(lcd->vsha); ++ ++ lcd->vshd = devm_gpiod_get(&dev->dev, "VSHD", GPIOD_OUT_LOW); ++ if (IS_ERR(lcd->vshd)) ++ return PTR_ERR(lcd->vshd); ++ ++ lcd->vee = devm_gpiod_get(&dev->dev, "Vee", GPIOD_OUT_LOW); ++ if (IS_ERR(lcd->vee)) ++ return PTR_ERR(lcd->vee); ++ ++ lcd->mod = devm_gpiod_get(&dev->dev, "MOD", GPIOD_OUT_LOW); ++ if (IS_ERR(lcd->mod)) ++ return PTR_ERR(lcd->mod); ++ ++ lcd->comadj = iio_channel_get(&dev->dev, "comadj"); ++ if (IS_ERR(lcd->comadj)) { ++ rc = PTR_ERR(lcd->comadj); ++ if (rc == -ENODEV) ++ rc = -EPROBE_DEFER; ++ ++ return rc; ++ } ++ ++ locomo_lcd_program_adsync(lcd); ++ ++ lcd_dev = devm_lcd_device_register(&dev->dev, "locomo", &dev->dev, lcd, ++ &locomo_lcd_ops); ++ if (IS_ERR(lcd_dev)) { ++ rc = PTR_ERR(lcd_dev); ++ goto err; ++ } ++ ++ platform_set_drvdata(dev, lcd_dev); ++ ++ lcd_set_power(lcd_dev, FB_BLANK_UNBLANK); ++ ++ return 0; ++ ++err: ++ locomo_lcd_disable_adsync(lcd); ++ iio_channel_release(lcd->comadj); ++ ++ return rc; ++} ++ ++static int locomo_lcd_remove(struct platform_device *dev) ++{ ++ struct lcd_device *ldev = platform_get_drvdata(dev); ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ locomo_lcd_off(lcd); ++ ++ locomo_lcd_disable_adsync(lcd); ++ ++ iio_channel_release(lcd->comadj); ++ ++ return 0; ++} ++ ++static void locomo_lcd_shutdown(struct platform_device *dev) ++{ ++ struct lcd_device *ldev = platform_get_drvdata(dev); ++ struct locomo_lcd *lcd = lcd_get_data(ldev); ++ ++ locomo_lcd_off(lcd); ++ ++ locomo_lcd_disable_adsync(lcd); ++} ++ ++static struct platform_driver locomo_lcd_driver = { ++ .driver = { ++ .name = "locomo-lcd", ++ .pm = LOCOMOLCD_PM, ++ }, ++ .probe = locomo_lcd_probe, ++ .remove = locomo_lcd_remove, ++ .shutdown = locomo_lcd_shutdown, ++}; ++ ++module_platform_driver(locomo_lcd_driver); ++ ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_AUTHOR("Pavel Machek <pavel@ucw.cz>"); ++MODULE_DESCRIPTION("LoCoMo LCD driver"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:locomo-lcd"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0008-GPIO-port-LoCoMo-gpio-support-from-old-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0008-GPIO-port-LoCoMo-gpio-support-from-old-driver.patch new file mode 100644 index 0000000..3f72520 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0008-GPIO-port-LoCoMo-gpio-support-from-old-driver.patch @@ -0,0 +1,226 @@ +From d9847bd340045c31bfdde1fa91f319b3cfb196c0 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:03:21 +0400 +Subject: [PATCH 08/20] GPIO: port LoCoMo gpio support from old driver + +Add gpiolib driver for gpio pins placed on the LoCoMo GA. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/gpio/Kconfig | 9 +++ + drivers/gpio/Makefile | 1 + + drivers/gpio/gpio-locomo.c | 170 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 180 insertions(+) + create mode 100644 drivers/gpio/gpio-locomo.c + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index c1e2ca3..9b1c2e6 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -504,6 +504,15 @@ config GPIO_TB10X + select GENERIC_IRQ_CHIP + select OF_GPIO + ++config GPIO_LOCOMO ++ bool "Sharp LoCoMo GPIO support" ++ depends on MFD_LOCOMO ++ help ++ Select this to support GPIO pins on Sharp LoCoMo Grid Array found ++ in Sharp Zaurus collie and poodle models. ++ ++ Sat Yes if you have such PDA, say No otherwise. ++ + comment "I2C GPIO expanders:" + + config GPIO_ARIZONA +diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile +index bdda6a9..0a97e98 100644 +--- a/drivers/gpio/Makefile ++++ b/drivers/gpio/Makefile +@@ -41,6 +41,7 @@ obj-$(CONFIG_GPIO_JANZ_TTL) += gpio-janz-ttl.o + obj-$(CONFIG_GPIO_KEMPLD) += gpio-kempld.o + obj-$(CONFIG_ARCH_KS8695) += gpio-ks8695.o + obj-$(CONFIG_GPIO_INTEL_MID) += gpio-intel-mid.o ++obj-$(CONFIG_GPIO_LOCOMO) += gpio-locomo.o + obj-$(CONFIG_GPIO_LP3943) += gpio-lp3943.o + obj-$(CONFIG_ARCH_LPC32XX) += gpio-lpc32xx.o + obj-$(CONFIG_GPIO_LYNXPOINT) += gpio-lynxpoint.o +diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c +new file mode 100644 +index 0000000..dd9a1ca +--- /dev/null ++++ b/drivers/gpio/gpio-locomo.c +@@ -0,0 +1,170 @@ ++/* ++ * Sharp LoCoMo support for GPIO ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ * ++ * 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. ++ */ ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/slab.h> ++#include <linux/bitops.h> ++#include <linux/err.h> ++#include <linux/gpio.h> ++#include <linux/io.h> ++#include <linux/regmap.h> ++#include <linux/mfd/locomo.h> ++ ++struct locomo_gpio { ++ struct regmap *regmap; ++ ++ struct gpio_chip gpio; ++ ++ u16 rising_edge; ++ u16 falling_edge; ++ ++ unsigned int save_gpo; ++ unsigned int save_gpe; ++}; ++ ++static int locomo_gpio_get(struct gpio_chip *chip, ++ unsigned offset) ++{ ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int gpl; ++ ++ regmap_read(lg->regmap, LOCOMO_GPL, &gpl); ++ ++ return gpl & BIT(offset); ++} ++ ++static void locomo_gpio_set(struct gpio_chip *chip, ++ unsigned offset, int value) ++{ ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GPO, ++ BIT(offset), ++ value ? BIT(offset) : 0); ++} ++ ++static int locomo_gpio_direction_input(struct gpio_chip *chip, ++ unsigned offset) ++{ ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GPD, BIT(offset), BIT(offset)); ++ regmap_update_bits(lg->regmap, LOCOMO_GPE, BIT(offset), BIT(offset)); ++ ++ return 0; ++} ++ ++static int locomo_gpio_direction_output(struct gpio_chip *chip, ++ unsigned offset, int value) ++{ ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GPO, ++ BIT(offset), ++ value ? BIT(offset) : 0); ++ regmap_update_bits(lg->regmap, LOCOMO_GPD, BIT(offset), 0); ++ regmap_update_bits(lg->regmap, LOCOMO_GPE, BIT(offset), 0); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomo_gpio_suspend(struct device *dev) ++{ ++ struct locomo_gpio *lg = dev_get_drvdata(dev); ++ ++ regmap_read(lg->regmap, LOCOMO_GPO, &lg->save_gpo); ++ regmap_write(lg->regmap, LOCOMO_GPO, 0x00); ++ regmap_read(lg->regmap, LOCOMO_GPE, &lg->save_gpe); ++ regmap_write(lg->regmap, LOCOMO_GPE, 0x00); ++ ++ return 0; ++} ++ ++static int locomo_gpio_resume(struct device *dev) ++{ ++ struct locomo_gpio *lg = dev_get_drvdata(dev); ++ ++ regmap_write(lg->regmap, LOCOMO_GPO, lg->save_gpo); ++ regmap_write(lg->regmap, LOCOMO_GPE, lg->save_gpe); ++ ++ return 0; ++} ++static SIMPLE_DEV_PM_OPS(locomo_gpio_pm, ++ locomo_gpio_suspend, locomo_gpio_resume); ++#define LOCOMO_GPIO_PM (&locomo_gpio_pm) ++#else ++#define LOCOMO_GPIO_PM NULL ++#endif ++ ++static int locomo_gpio_probe(struct platform_device *pdev) ++{ ++ struct locomo_gpio *lg; ++ int ret; ++ struct locomo_gpio_platform_data *pdata = dev_get_platdata(&pdev->dev); ++ ++ lg = devm_kzalloc(&pdev->dev, sizeof(struct locomo_gpio), ++ GFP_KERNEL); ++ if (!lg) ++ return -ENOMEM; ++ ++ lg->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!lg->regmap) ++ return -EINVAL; ++ ++ platform_set_drvdata(pdev, lg); ++ ++ regmap_write(lg->regmap, LOCOMO_GPO, 0x00); ++ regmap_write(lg->regmap, LOCOMO_GPE, 0x00); ++ regmap_write(lg->regmap, LOCOMO_GPD, 0x00); ++ regmap_write(lg->regmap, LOCOMO_GIE, 0x00); ++ ++ lg->gpio.base = pdata ? pdata->gpio_base : -1; ++ lg->gpio.label = "locomo-gpio"; ++ lg->gpio.ngpio = 16; ++ lg->gpio.set = locomo_gpio_set; ++ lg->gpio.get = locomo_gpio_get; ++ lg->gpio.direction_input = locomo_gpio_direction_input; ++ lg->gpio.direction_output = locomo_gpio_direction_output; ++ ++ ret = gpiochip_add(&lg->gpio); ++ if (ret) ++ return ret; ++ ++ return 0; ++} ++ ++static int locomo_gpio_remove(struct platform_device *pdev) ++{ ++ struct locomo_gpio *lg = platform_get_drvdata(pdev); ++ ++ gpiochip_remove(&lg->gpio); ++ ++ return 0; ++} ++ ++static struct platform_driver locomo_gpio_driver = { ++ .probe = locomo_gpio_probe, ++ .remove = locomo_gpio_remove, ++ .driver = { ++ .name = "locomo-gpio", ++ .pm = LOCOMO_GPIO_PM, ++ }, ++}; ++module_platform_driver(locomo_gpio_driver); ++ ++MODULE_DESCRIPTION("Sharp LoCoMo GPIO driver"); ++MODULE_LICENSE("GPL"); ++MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); ++MODULE_ALIAS("platform:locomo-gpio"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch new file mode 100644 index 0000000..7d07659 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0009-gpio-locomo-implement-per-pin-irq-handling.patch @@ -0,0 +1,204 @@ +From ec2485ae9fd5238d1def04e6377d213285ab3315 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 04:27:27 +0400 +Subject: [PATCH 09/20] gpio: locomo: implement per-pin irq handling + +LoCoMo has a possibility to generate per-GPIO edge irqs. Support for +that was there in old locomo driver, got 'cleaned up' during old driver +IRQ cascading cleanup and is now reimplemented. It is expected that +SL-5500 (collie) will use locomo gpio irqs for mmc detection irq. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/gpio/Kconfig | 1 + + drivers/gpio/gpio-locomo.c | 120 ++++++++++++++++++++++++++++++++++++++++++++- + 2 files changed, 120 insertions(+), 1 deletion(-) + +diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig +index 9b1c2e6..b6ebcb6 100644 +--- a/drivers/gpio/Kconfig ++++ b/drivers/gpio/Kconfig +@@ -507,6 +507,7 @@ config GPIO_TB10X + config GPIO_LOCOMO + bool "Sharp LoCoMo GPIO support" + depends on MFD_LOCOMO ++ select GPIOLIB_IRQCHIP + help + Select this to support GPIO pins on Sharp LoCoMo Grid Array found + in Sharp Zaurus collie and poodle models. +diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c +index dd9a1ca..d8e5880 100644 +--- a/drivers/gpio/gpio-locomo.c ++++ b/drivers/gpio/gpio-locomo.c +@@ -16,13 +16,15 @@ + #include <linux/slab.h> + #include <linux/bitops.h> + #include <linux/err.h> +-#include <linux/gpio.h> ++#include <linux/gpio/driver.h> + #include <linux/io.h> ++#include <linux/irq.h> + #include <linux/regmap.h> + #include <linux/mfd/locomo.h> + + struct locomo_gpio { + struct regmap *regmap; ++ int irq; + + struct gpio_chip gpio; + +@@ -79,6 +81,99 @@ static int locomo_gpio_direction_output(struct gpio_chip *chip, + return 0; + } + ++static void ++locomo_gpio_irq_handler(unsigned int irq, struct irq_desc *desc) ++{ ++ struct gpio_chip *chip = irq_get_handler_data(irq); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ struct irq_chip *irqchip = irq_desc_get_chip(desc); ++ unsigned int gir; ++ unsigned int gpd; ++ unsigned int req; ++ ++ chained_irq_enter(irqchip, desc); ++ ++ while (1) { ++ regmap_read(lg->regmap, LOCOMO_GIR, &gir); ++ regmap_read(lg->regmap, LOCOMO_GPD, &gpd); ++ req = gir & gpd; ++ ++ if (!req) ++ break; ++ ++ generic_handle_irq(irq_find_mapping(lg->gpio.irqdomain, ++ ffs(req) - 1)); ++ } ++ ++ chained_irq_exit(irqchip, desc); ++} ++ ++static void locomo_gpio_ack_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, mask); ++ regmap_update_bits(lg->regmap, LOCOMO_GIS, mask, 0); ++ regmap_update_bits(lg->regmap, LOCOMO_GWE, mask, 0); ++} ++ ++static void locomo_gpio_mask_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, 0); ++} ++ ++static void locomo_gpio_unmask_irq(struct irq_data *d) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask = BIT(d->hwirq); ++ ++ regmap_update_bits(lg->regmap, LOCOMO_GIE, mask, mask); ++} ++ ++static int locomo_gpio_type_irq(struct irq_data *d, unsigned int type) ++{ ++ struct gpio_chip *chip = irq_data_get_irq_chip_data(d); ++ struct locomo_gpio *lg = container_of(chip, struct locomo_gpio, gpio); ++ unsigned int mask; ++ ++ mask = BIT(d->hwirq); ++ ++ if (type == IRQ_TYPE_PROBE) { ++ if ((lg->rising_edge | lg->falling_edge) & mask) ++ return 0; ++ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; ++ } ++ ++ if (type & IRQ_TYPE_EDGE_RISING) ++ lg->rising_edge |= mask; ++ else ++ lg->rising_edge &= ~mask; ++ if (type & IRQ_TYPE_EDGE_FALLING) ++ lg->falling_edge |= mask; ++ else ++ lg->falling_edge &= ~mask; ++ ++ regmap_write(lg->regmap, LOCOMO_GRIE, lg->rising_edge); ++ regmap_write(lg->regmap, LOCOMO_GFIE, lg->falling_edge); ++ ++ return 0; ++} ++ ++static struct irq_chip locomo_gpio_irq_chip = { ++ .name = "LOCOMO-g", ++ .irq_ack = locomo_gpio_ack_irq, ++ .irq_mask = locomo_gpio_mask_irq, ++ .irq_unmask = locomo_gpio_unmask_irq, ++ .irq_set_type = locomo_gpio_type_irq, ++}; ++ + #ifdef CONFIG_PM_SLEEP + static int locomo_gpio_suspend(struct device *dev) + { +@@ -119,6 +214,10 @@ static int locomo_gpio_probe(struct platform_device *pdev) + if (!lg) + return -ENOMEM; + ++ lg->irq = platform_get_irq(pdev, 0); ++ if (lg->irq < 0) ++ return -ENXIO; ++ + lg->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!lg->regmap) + return -EINVAL; +@@ -130,6 +229,7 @@ static int locomo_gpio_probe(struct platform_device *pdev) + regmap_write(lg->regmap, LOCOMO_GPD, 0x00); + regmap_write(lg->regmap, LOCOMO_GIE, 0x00); + ++ lg->gpio.dev = &pdev->dev; + lg->gpio.base = pdata ? pdata->gpio_base : -1; + lg->gpio.label = "locomo-gpio"; + lg->gpio.ngpio = 16; +@@ -142,7 +242,22 @@ static int locomo_gpio_probe(struct platform_device *pdev) + if (ret) + return ret; + ++ ret = gpiochip_irqchip_add(&lg->gpio, &locomo_gpio_irq_chip, 0, ++ handle_level_irq, IRQ_TYPE_NONE); ++ if (ret) { ++ dev_err(&pdev->dev, "Failed to add irq chip\n"); ++ goto err_rm_gpiochip; ++ } ++ ++ gpiochip_set_chained_irqchip(&lg->gpio, &locomo_gpio_irq_chip, lg->irq, ++ locomo_gpio_irq_handler); ++ + return 0; ++ ++err_rm_gpiochip: ++ gpiochip_remove(&lg->gpio); ++ ++ return ret; + } + + static int locomo_gpio_remove(struct platform_device *pdev) +@@ -151,6 +266,9 @@ static int locomo_gpio_remove(struct platform_device *pdev) + + gpiochip_remove(&lg->gpio); + ++ irq_set_chained_handler(lg->irq, NULL); ++ irq_set_handler_data(lg->irq, NULL); ++ + return 0; + } + +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0010-spi-add-locomo-SPI-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0010-spi-add-locomo-SPI-driver.patch new file mode 100644 index 0000000..94a91a4 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0010-spi-add-locomo-SPI-driver.patch @@ -0,0 +1,421 @@ +From a6c75627194e087467ed57a9e50168375e8a5908 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Thu, 28 Nov 2013 15:47:18 +0400 +Subject: [PATCH 10/20] spi: add locomo SPI driver + +LoCoMo chip has a built-in simple SPI controller. On Sharp SL-5500 PDDAs +it is connected to external MMC slot. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/spi/Kconfig | 10 ++ + drivers/spi/Makefile | 1 + + drivers/spi/spi-locomo.c | 363 +++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 374 insertions(+) + create mode 100644 drivers/spi/spi-locomo.c + +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index ab8dfbe..96312d6 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -259,6 +259,16 @@ config SPI_LM70_LLP + which interfaces to an LM70 temperature sensor using + a parallel port. + ++config SPI_LOCOMO ++ tristate "Locomo SPI master" ++ depends on MFD_LOCOMO ++ help ++ This enables using the SPI controller as present in the LoCoMo ++ chips. It is probably only useful on the Sharp SL-5x00 PDA family. ++ ++ On SL-5500 and SL-5000 devices this controller is used for ++ MMC/SD cards. ++ + config SPI_MPC52xx + tristate "Freescale MPC52xx SPI (non-PSC) controller support" + depends on PPC_MPC52xx +diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile +index d8cbf65..623c463 100644 +--- a/drivers/spi/Makefile ++++ b/drivers/spi/Makefile +@@ -44,6 +44,7 @@ obj-$(CONFIG_SPI_GPIO) += spi-gpio.o + obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o + obj-$(CONFIG_SPI_IMX) += spi-imx.o + obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o ++obj-$(CONFIG_SPI_LOCOMO) += spi-locomo.o + obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o + obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o + obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o +diff --git a/drivers/spi/spi-locomo.c b/drivers/spi/spi-locomo.c +new file mode 100644 +index 0000000..71b36fd +--- /dev/null ++++ b/drivers/spi/spi-locomo.c +@@ -0,0 +1,363 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ */ ++#include <linux/delay.h> ++#include <linux/module.h> ++#include <linux/kernel.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/spi/spi.h> ++#include <linux/mfd/locomo.h> ++ ++struct locomospi_dev { ++ struct regmap *regmap; ++ ++ int clock_base; ++ int clock_div; ++ unsigned nsecs; ++ ++ unsigned int save_ct; ++ unsigned int save_md; ++}; ++ ++static int locomospi_reg_open(struct locomospi_dev *spidev) ++{ ++ regmap_write(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_MSB1ST | LOCOMO_SPIMD_DOSTAT | ++ LOCOMO_SPIMD_RCPOL | LOCOMO_SPIMD_TCPOL | ++ (spidev->clock_base << 3) | spidev->clock_div); ++ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_XON, ++ LOCOMO_SPIMD_XON); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_XEN, ++ LOCOMO_SPIMD_XEN); ++ ++ regmap_write(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPICT, ++ LOCOMO_SPICT_CEN | LOCOMO_SPICT_RXUEN | ++ LOCOMO_SPICT_ALIGNEN, ++ LOCOMO_SPICT_CEN | LOCOMO_SPICT_RXUEN | ++ LOCOMO_SPICT_ALIGNEN); ++ ++ usleep_range(200, 300); ++ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS, 0); ++ ++ return 0; ++} ++ ++static int locomospi_reg_release(struct locomospi_dev *spidev) ++{ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CEN, 0); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, LOCOMO_SPIMD_XEN, 0); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, LOCOMO_SPIMD_XON, 0); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPICT, ++ LOCOMO_SPIMD_XEN, ++ LOCOMO_SPIMD_XEN); ++ ++ return 0; ++} ++ ++ ++static void locomospi_chipselect(struct spi_device *spi, bool enable) ++{ ++ struct locomospi_dev *spidev; ++ ++ dev_dbg(&spi->dev, "SPI cs: %s\n", enable ? "enable" : "disable"); ++ ++ spidev = spi_master_get_devdata(spi->master); ++ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS, ++ enable ? LOCOMO_SPICT_CS : 0); ++} ++ ++static u32 locomospi_txrx_word(struct spi_device *spi, ++ unsigned nsecs, ++ u32 word) ++{ ++ struct locomospi_dev *spidev; ++ int wait; ++ int j; ++ unsigned int rx; ++ unsigned int r; ++ ++ spidev = spi_master_get_devdata(spi->master); ++ ++ if (spidev->clock_div == DIV_64) ++ wait = 0x10000; ++ else ++ wait = 8; ++ ++ for (j = 0; j < wait; j++) { ++ regmap_read(spidev->regmap, LOCOMO_SPIST, &r); ++ if (r & LOCOMO_SPI_RFW) ++ break; ++ } ++ if (j == wait) ++ dev_err(&spi->dev, "rfw timeout\n"); ++ ++ regmap_write(spidev->regmap, LOCOMO_SPITD, word); ++ ndelay(nsecs); ++ ++ for (j = 0; j < wait; j++) { ++ regmap_read(spidev->regmap, LOCOMO_SPIST, &r); ++ if (r & LOCOMO_SPI_RFR) ++ break; ++ } ++ if (j == wait) ++ dev_err(&spi->dev, "rfr timeout\n"); ++ ++ regmap_read(spidev->regmap, LOCOMO_SPIRD, &rx); ++ ndelay(nsecs); ++ ++ dev_dbg(&spi->dev, "SPI txrx: %02x/%02x\n", word, rx); ++ ++ return rx; ++} ++ ++static void locomo_spi_set_speed(struct locomospi_dev *spidev, u32 hz) ++{ ++ spidev->nsecs = (1000000000/2) / hz; ++ ++ if (hz >= 24576000) { ++ spidev->clock_base = CLOCK_25MHZ; ++ spidev->clock_div = DIV_1; ++ } else if (hz >= 22579200) { ++ spidev->clock_base = CLOCK_22MHZ; ++ spidev->clock_div = DIV_1; ++ } else if (hz >= 18432000) { ++ spidev->clock_base = CLOCK_18MHZ; ++ spidev->clock_div = DIV_1; ++ } else if (hz >= 12288000) { ++ spidev->clock_base = CLOCK_25MHZ; ++ spidev->clock_div = DIV_2; ++ } else if (hz >= 11289600) { ++ spidev->clock_base = CLOCK_22MHZ; ++ spidev->clock_div = DIV_2; ++ } else if (hz >= 9216000) { ++ spidev->clock_base = CLOCK_18MHZ; ++ spidev->clock_div = DIV_2; ++ } else if (hz >= 6144000) { ++ spidev->clock_base = CLOCK_25MHZ; ++ spidev->clock_div = DIV_4; ++ } else if (hz >= 5644800) { ++ spidev->clock_base = CLOCK_22MHZ; ++ spidev->clock_div = DIV_4; ++ } else if (hz >= 4608000) { ++ spidev->clock_base = CLOCK_18MHZ; ++ spidev->clock_div = DIV_4; ++ } else if (hz >= 3072000) { ++ spidev->clock_base = CLOCK_25MHZ; ++ spidev->clock_div = DIV_8; ++ } else if (hz >= 2822400) { ++ spidev->clock_base = CLOCK_22MHZ; ++ spidev->clock_div = DIV_8; ++ } else if (hz >= 2304000) { ++ spidev->clock_base = CLOCK_18MHZ; ++ spidev->clock_div = DIV_8; ++ } else if (hz >= 384000) { ++ spidev->clock_base = CLOCK_25MHZ; ++ spidev->clock_div = DIV_64; ++ } else if (hz >= 352800) { ++ spidev->clock_base = CLOCK_22MHZ; ++ spidev->clock_div = DIV_64; ++ } else { /* set to 288 Khz */ ++ spidev->clock_base = CLOCK_18MHZ; ++ spidev->clock_div = DIV_64; ++ } ++ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_XSEL | LOCOMO_SPIMD_CLKSEL | ++ LOCOMO_SPIMD_XEN, ++ 0); ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_XSEL | LOCOMO_SPIMD_CLKSEL | ++ LOCOMO_SPIMD_XEN, ++ spidev->clock_div | (spidev->clock_base << 3) | ++ LOCOMO_SPIMD_XEN); ++ ++ usleep_range(300, 400); ++} ++ ++static int locomo_spi_setup_transfer(struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct locomospi_dev *spidev; ++ u32 hz = 0; ++ ++ if (t) ++ hz = t->speed_hz; ++ if (!hz) ++ hz = spi->max_speed_hz; ++ ++ spidev = spi_master_get_devdata(spi->master); ++ ++ regmap_update_bits(spidev->regmap, LOCOMO_SPIMD, ++ LOCOMO_SPIMD_XON, ++ hz ? LOCOMO_SPIMD_XON : 0); ++ ++ if (hz != 0) ++ locomo_spi_set_speed(spidev, hz); ++ ++ return 0; ++} ++ ++static int locomospi_transfer_one(struct spi_master *master, ++ struct spi_device *spi, ++ struct spi_transfer *t) ++{ ++ struct locomospi_dev *spidev = spi_master_get_devdata(spi->master); ++ int rc; ++ unsigned count; ++ const u8 *tx = t->tx_buf; ++ u8 *rx = t->rx_buf; ++ ++ if (!tx && !rx && t->len) ++ return -EINVAL; ++ ++ rc = locomo_spi_setup_transfer(spi, t); ++ if (rc < 0) ++ return rc; ++ ++ if (!t->len) ++ return 0; ++ ++ for (count = t->len; likely(count > 0); count--) { ++ u8 word = 0; ++ ++ if (tx) ++ word = *tx++; ++ word = locomospi_txrx_word(spi, spidev->nsecs, word); ++ ++ if (rx) ++ *rx++ = word; ++ } ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomo_spi_suspend(struct device *dev) ++{ ++ struct spi_master *master = dev_get_drvdata(dev); ++ struct locomospi_dev *spidev = spi_master_get_devdata(master); ++ int ret; ++ ++ /* Stop the queue running */ ++ ret = spi_master_suspend(master); ++ if (ret) { ++ dev_warn(dev, "cannot suspend master\n"); ++ return ret; ++ } ++ ++ regmap_read(spidev->regmap, LOCOMO_SPICT, &spidev->save_ct); ++ regmap_write(spidev->regmap, LOCOMO_SPICT, LOCOMO_SPICT_CS); ++ regmap_read(spidev->regmap, LOCOMO_SPIMD, &spidev->save_ct); ++ regmap_write(spidev->regmap, LOCOMO_SPIMD, 0x3c14); ++ ++ ++ return 0; ++} ++ ++static int locomo_spi_resume(struct device *dev) ++{ ++ struct spi_master *master = dev_get_drvdata(dev); ++ struct locomospi_dev *spidev = spi_master_get_devdata(master); ++ int ret; ++ ++ regmap_write(spidev->regmap, LOCOMO_SPICT, spidev->save_ct); ++ regmap_write(spidev->regmap, LOCOMO_SPIMD, spidev->save_md); ++ ++ /* Start the queue running */ ++ ret = spi_master_resume(master); ++ if (ret) ++ dev_err(dev, "problem starting queue (%d)\n", ret); ++ ++ return ret; ++} ++ ++static SIMPLE_DEV_PM_OPS(locomo_spi_pm_ops, ++ locomo_spi_suspend, locomo_spi_resume); ++ ++#define LOCOMO_SPI_PM_OPS (&locomo_spi_pm_ops) ++#else ++#define LOCOMO_SPI_PM_OPS NULL ++#endif ++ ++static int locomo_spi_probe(struct platform_device *pdev) ++{ ++ struct spi_master *master; ++ struct locomospi_dev *spidev; ++ int ret = -ENODEV; ++ ++ master = spi_alloc_master(&pdev->dev, sizeof(struct locomospi_dev)); ++ if (!master) ++ return -ENOMEM; ++ ++ master->bus_num = 0; ++ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; ++ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(8, 8); ++ master->max_speed_hz = 24576000; ++ master->num_chipselect = 1; ++ master->set_cs = locomospi_chipselect; ++ master->transfer_one = locomospi_transfer_one; ++ ++ spidev = spi_master_get_devdata(master); ++ ++ spidev->regmap = dev_get_regmap(pdev->dev.parent, NULL); ++ if (!spidev->regmap) ++ goto out_put; ++ ++ spidev->clock_div = DIV_64; ++ spidev->clock_base = CLOCK_18MHZ; ++ ++ platform_set_drvdata(pdev, master); ++ ++ ret = locomospi_reg_open(spidev); ++ if (ret < 0) ++ goto out_put; ++ ++ ret = devm_spi_register_master(&pdev->dev, master); ++ if (ret) { ++ dev_err(&pdev->dev, "bitbang start failed with %d\n", ret); ++ goto out_put; ++ } ++ ++ return 0; ++ ++out_put: ++ spi_master_put(master); ++ return ret; ++} ++ ++static int locomo_spi_remove(struct platform_device *pdev) ++{ ++ struct spi_master *master = platform_get_drvdata(pdev); ++ struct locomospi_dev *spidev = spi_master_get_devdata(master); ++ ++ return locomospi_reg_release(spidev); ++} ++ ++static struct platform_driver locomo_spi_driver = { ++ .probe = locomo_spi_probe, ++ .remove = locomo_spi_remove, ++ .driver = { ++ .name = "locomo-spi", ++ .pm = LOCOMO_SPI_PM_OPS, ++ }, ++}; ++module_platform_driver(locomo_spi_driver); ++ ++MODULE_AUTHOR("Thomas Kunze thommy@tabao.de"); ++MODULE_DESCRIPTION("LoCoMo SPI driver"); ++MODULE_LICENSE("GPL"); ++MODULE_ALIAS("platform:locomo-spi"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0011-i2c-add-locomo-i2c-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0011-i2c-add-locomo-i2c-driver.patch new file mode 100644 index 0000000..43a2bd3 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0011-i2c-add-locomo-i2c-driver.patch @@ -0,0 +1,196 @@ +From 37279f73cbea78da52a4eac4a4c13406ff5500da Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Fri, 14 Nov 2014 16:07:58 +0300 +Subject: [PATCH 11/20] i2c: add locomo i2c driver + +LoCoMo chip contains a tiny i2c controller destined to control +M62332 DAC. Provide a separate I2C driver for this cell. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/i2c/busses/Kconfig | 12 ++++ + drivers/i2c/busses/Makefile | 1 + + drivers/i2c/busses/i2c-locomo.c | 136 ++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 149 insertions(+) + create mode 100644 drivers/i2c/busses/i2c-locomo.c + +diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig +index 22da9c2..a4b20ba 100644 +--- a/drivers/i2c/busses/Kconfig ++++ b/drivers/i2c/busses/Kconfig +@@ -584,6 +584,18 @@ config I2C_KEMPLD + This driver can also be built as a module. If so, the module + will be called i2c-kempld. + ++config I2C_LOCOMO ++ tristate "I2C bus support for LoCoMo chips" ++ depends on MFD_LOCOMO ++ select I2C_ALGOBIT ++ help ++ Say yes if you will run the kernel on Sharp SL-5x00 family of devices. ++ ++ If you don't know what to do here, say N. ++ ++ This driver can also be built as a module. If so, the module ++ will be called i2c-locomo. ++ + config I2C_MESON + tristate "Amlogic Meson I2C controller" + depends on ARCH_MESON +diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile +index 3638feb..d31ae1a 100644 +--- a/drivers/i2c/busses/Makefile ++++ b/drivers/i2c/busses/Makefile +@@ -56,6 +56,7 @@ obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o + obj-$(CONFIG_I2C_IMX) += i2c-imx.o + obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o + obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o ++obj-$(CONFIG_I2C_LOCOMO) += i2c-locomo.o + obj-$(CONFIG_I2C_MESON) += i2c-meson.o + obj-$(CONFIG_I2C_MPC) += i2c-mpc.o + obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o +diff --git a/drivers/i2c/busses/i2c-locomo.c b/drivers/i2c/busses/i2c-locomo.c +new file mode 100644 +index 0000000..640b46cd +--- /dev/null ++++ b/drivers/i2c/busses/i2c-locomo.c +@@ -0,0 +1,136 @@ ++/* ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License version 2 as ++ * published by the Free Software Foundation. ++ */ ++#include <linux/kernel.h> ++#include <linux/module.h> ++#include <linux/platform_device.h> ++#include <linux/regmap.h> ++#include <linux/slab.h> ++#include <linux/mfd/locomo.h> ++ ++#include <linux/i2c.h> ++#include <linux/i2c-algo-bit.h> ++ ++struct locomo_i2c { ++ struct regmap *regmap; ++ struct i2c_adapter adap; ++ struct i2c_algo_bit_data bit; ++}; ++ ++static void locomo_i2c_setsda(void *data, int state) ++{ ++ struct locomo_i2c *li2c = data; ++ ++ regmap_update_bits(li2c->regmap, LOCOMO_DAC, ++ LOCOMO_DAC_SDAOEB, ++ state ? LOCOMO_DAC_SDAOEB : 0); ++} ++ ++static void locomo_i2c_setscl(void *data, int state) ++{ ++ struct locomo_i2c *li2c = data; ++ ++ regmap_update_bits(li2c->regmap, LOCOMO_DAC, ++ LOCOMO_DAC_SCLOEB, ++ state ? LOCOMO_DAC_SCLOEB : 0); ++} ++ ++static int locomo_i2c_getsda(void *data) ++{ ++ struct locomo_i2c *li2c = data; ++ unsigned int r; ++ ++ regmap_read(li2c->regmap, LOCOMO_DAC, &r); ++ ++ return !!(r & LOCOMO_DAC_SDA); ++} ++ ++static int locomo_i2c_probe(struct platform_device *dev) ++{ ++ struct locomo_i2c *li2c; ++ int ret; ++ ++ li2c = devm_kzalloc(&dev->dev, sizeof(struct locomo_i2c), GFP_KERNEL); ++ if (li2c == NULL) ++ return -ENOMEM; ++ ++ li2c->regmap = dev_get_regmap(dev->dev.parent, NULL); ++ if (!li2c->regmap) ++ return -ENODEV; ++ ++ li2c->adap.owner = THIS_MODULE; ++ li2c->adap.dev.parent = &dev->dev; ++ li2c->adap.dev.of_node = dev->dev.of_node; ++ li2c->adap.algo_data = &li2c->bit; ++ li2c->adap.nr = 1; /* On poodle, 0 is pxa internal bus */ ++ ++ strlcpy(li2c->adap.name, "LoCoMo I2C", sizeof(li2c->adap.name)); ++ ++ li2c->bit.data = li2c; ++ li2c->bit.setsda = locomo_i2c_setsda; ++ li2c->bit.setscl = locomo_i2c_setscl; ++ li2c->bit.getsda = locomo_i2c_getsda; ++ li2c->bit.udelay = 6; ++ li2c->bit.timeout = HZ; ++ ++ ret = i2c_bit_add_numbered_bus(&li2c->adap); ++ if (ret) ++ return ret; ++ ++ platform_set_drvdata(dev, li2c); ++ ++ return 0; ++} ++ ++static int locomo_i2c_remove(struct platform_device *dev) ++{ ++ struct locomo_i2c *li2c = platform_get_drvdata(dev); ++ ++ i2c_del_adapter(&li2c->adap); ++ ++ return 0; ++} ++ ++#ifdef CONFIG_PM_SLEEP ++static int locomo_i2c_suspend(struct device *dev) ++{ ++ struct locomo_i2c *li2c = dev_get_drvdata(dev); ++ ++ regmap_write(li2c->regmap, LOCOMO_DAC, 0x00); ++ ++ return 0; ++} ++ ++static int locomo_i2c_resume(struct device *dev) ++{ ++ struct locomo_i2c *li2c = dev_get_drvdata(dev); ++ ++ regmap_write(li2c->regmap, LOCOMO_DAC, ++ LOCOMO_DAC_SDAOEB | LOCOMO_DAC_SCLOEB); ++ ++ return 0; ++} ++static SIMPLE_DEV_PM_OPS(locomo_i2c_pm, locomo_i2c_suspend, locomo_i2c_resume); ++#define LOCOMO_I2C_PM (&locomo_i2c_pm) ++#else ++#define LOCOMO_I2C_PM NULL ++#endif ++ ++ ++static struct platform_driver locomo_i2c_driver = { ++ .driver = { ++ .name = "locomo-i2c", ++ .pm = LOCOMO_I2C_PM, ++ }, ++ .probe = locomo_i2c_probe, ++ .remove = locomo_i2c_remove, ++}; ++ ++module_platform_driver(locomo_i2c_driver); ++ ++MODULE_DESCRIPTION("LoCoMo i2c bus driver"); ++MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>"); ++MODULE_LICENSE("GPL v2"); ++MODULE_ALIAS("platform:locomo-i2c"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0012-ARM-drop-old-LoCoMo-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0012-ARM-drop-old-LoCoMo-driver.patch new file mode 100644 index 0000000..dd2cade --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0012-ARM-drop-old-LoCoMo-driver.patch @@ -0,0 +1,1194 @@ +From 976687fce709a6b9e651a9eec3d930a69bd9b609 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 04:26:01 +0400 +Subject: [PATCH 12/20] ARM: drop old LoCoMo driver + +As there are no in-kernel users of old locomo driver, drop all +alltogether. Remove Kconfig entry, driver and header. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + arch/arm/common/Kconfig | 3 - + arch/arm/common/Makefile | 1 - + arch/arm/common/locomo.c | 914 --------------------------------- + arch/arm/include/asm/hardware/locomo.h | 221 -------- + 4 files changed, 1139 deletions(-) + delete mode 100644 arch/arm/common/locomo.c + delete mode 100644 arch/arm/include/asm/hardware/locomo.h + +diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig +index c3a4e9c..76c9970 100644 +--- a/arch/arm/common/Kconfig ++++ b/arch/arm/common/Kconfig +@@ -9,9 +9,6 @@ config DMABOUNCE + bool + select ZONE_DMA + +-config SHARP_LOCOMO +- bool +- + config SHARP_PARAM + bool + +diff --git a/arch/arm/common/Makefile b/arch/arm/common/Makefile +index 70b1eff..437c79a 100644 +--- a/arch/arm/common/Makefile ++++ b/arch/arm/common/Makefile +@@ -7,7 +7,6 @@ obj-y += firmware.o + obj-$(CONFIG_ICST) += icst.o + obj-$(CONFIG_SA1111) += sa1111.o + obj-$(CONFIG_DMABOUNCE) += dmabounce.o +-obj-$(CONFIG_SHARP_LOCOMO) += locomo.o + obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o + obj-$(CONFIG_SHARP_SCOOP) += scoop.o + obj-$(CONFIG_PCI_HOST_ITE8152) += it8152.o +diff --git a/arch/arm/common/locomo.c b/arch/arm/common/locomo.c +deleted file mode 100644 +index b55c362..0000000 +--- a/arch/arm/common/locomo.c ++++ /dev/null +@@ -1,914 +0,0 @@ +-/* +- * linux/arch/arm/common/locomo.c +- * +- * Sharp LoCoMo support +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- * 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 +- */ +- +-#include <linux/module.h> +-#include <linux/init.h> +-#include <linux/kernel.h> +-#include <linux/delay.h> +-#include <linux/errno.h> +-#include <linux/ioport.h> +-#include <linux/platform_device.h> +-#include <linux/slab.h> +-#include <linux/spinlock.h> +-#include <linux/io.h> +- +-#include <mach/hardware.h> +-#include <asm/irq.h> +-#include <asm/mach/irq.h> +- +-#include <asm/hardware/locomo.h> +- +-/* LoCoMo Interrupts */ +-#define IRQ_LOCOMO_KEY (0) +-#define IRQ_LOCOMO_GPIO (1) +-#define IRQ_LOCOMO_LT (2) +-#define IRQ_LOCOMO_SPI (3) +- +-/* 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; +- unsigned long phys; +- unsigned int irq; +- int irq_base; +- spinlock_t lock; +- void __iomem *base; +-#ifdef CONFIG_PM +- void *saved_state; +-#endif +-}; +- +-struct locomo_dev_info { +- unsigned long offset; +- unsigned long length; +- unsigned int devid; +- unsigned int irq[1]; +- const char * name; +-}; +- +-/* 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 */ +-static struct 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, +- +- }, +- { +- .devid = LOCOMO_DEVID_BACKLIGHT, +- .irq = {}, +- .name = "locomo-backlight", +- .offset = LOCOMO_BACKLIGHT, +- .length = 8, +- }, +- { +- .devid = LOCOMO_DEVID_AUDIO, +- .irq = {}, +- .name = "locomo-audio", +- .offset = LOCOMO_AUDIO, +- .length = 4, +- }, +- { +- .devid = LOCOMO_DEVID_LED, +- .irq = {}, +- .name = "locomo-led", +- .offset = LOCOMO_LED, +- .length = 8, +- }, +- { +- .devid = LOCOMO_DEVID_UART, +- .irq = {}, +- .name = "locomo-uart", +- .offset = 0, +- .length = 0, +- }, +- { +- .devid = LOCOMO_DEVID_SPI, +- .irq = {}, +- .name = "locomo-spi", +- .offset = LOCOMO_SPI, +- .length = 0x30, +- }, +-}; +- +-static void locomo_handler(unsigned int irq, struct irq_desc *desc) +-{ +- struct locomo *lchip = irq_get_chip_data(irq); +- int req, i; +- +- /* Acknowledge the parent IRQ */ +- desc->irq_data.chip->irq_ack(&desc->irq_data); +- +- /* check why this interrupt was generated */ +- req = locomo_readl(lchip->base + LOCOMO_ICR) & 0x0f00; +- +- if (req) { +- /* generate the next interrupt(s) */ +- irq = lchip->irq_base; +- for (i = 0; i <= 3; i++, irq++) { +- if (req & (0x0100 << i)) { +- generic_handle_irq(irq); +- } +- +- } +- } +-} +- +-static void locomo_ack_irq(struct irq_data *d) +-{ +-} +- +-static void locomo_mask_irq(struct irq_data *d) +-{ +- struct locomo *lchip = irq_data_get_irq_chip_data(d); +- unsigned int r; +- r = locomo_readl(lchip->base + LOCOMO_ICR); +- r &= ~(0x0010 << (d->irq - lchip->irq_base)); +- locomo_writel(r, lchip->base + LOCOMO_ICR); +-} +- +-static void locomo_unmask_irq(struct irq_data *d) +-{ +- struct locomo *lchip = irq_data_get_irq_chip_data(d); +- unsigned int r; +- r = locomo_readl(lchip->base + LOCOMO_ICR); +- r |= (0x0010 << (d->irq - lchip->irq_base)); +- locomo_writel(r, lchip->base + LOCOMO_ICR); +-} +- +-static struct irq_chip locomo_chip = { +- .name = "LOCOMO", +- .irq_ack = locomo_ack_irq, +- .irq_mask = locomo_mask_irq, +- .irq_unmask = locomo_unmask_irq, +-}; +- +-static void locomo_setup_irq(struct locomo *lchip) +-{ +- int irq = lchip->irq_base; +- +- /* +- * Install handler for IRQ_LOCOMO_HW. +- */ +- irq_set_irq_type(lchip->irq, IRQ_TYPE_EDGE_FALLING); +- irq_set_chip_data(lchip->irq, lchip); +- irq_set_chained_handler(lchip->irq, locomo_handler); +- +- /* Install handlers for IRQ_LOCOMO_* */ +- for ( ; irq <= lchip->irq_base + 3; irq++) { +- irq_set_chip_and_handler(irq, &locomo_chip, handle_level_irq); +- irq_set_chip_data(irq, lchip); +- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); +- } +-} +- +- +-static void locomo_dev_release(struct device *_dev) +-{ +- struct locomo_dev *dev = LOCOMO_DEV(_dev); +- +- kfree(dev); +-} +- +-static int +-locomo_init_one_child(struct locomo *lchip, struct locomo_dev_info *info) +-{ +- struct locomo_dev *dev; +- int ret; +- +- 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; +- } +- +- dev_set_name(&dev->dev, "%s", info->name); +- dev->devid = info->devid; +- dev->dev.parent = lchip->dev; +- dev->dev.bus = &locomo_bus_type; +- dev->dev.release = locomo_dev_release; +- dev->dev.coherent_dma_mask = lchip->dev->coherent_dma_mask; +- +- if (info->offset) +- dev->mapbase = lchip->base + info->offset; +- else +- dev->mapbase = 0; +- dev->length = info->length; +- +- dev->irq[0] = (lchip->irq_base == NO_IRQ) ? +- NO_IRQ : lchip->irq_base + info->irq[0]; +- +- ret = device_register(&dev->dev); +- if (ret) { +- out: +- kfree(dev); +- } +- return ret; +-} +- +-#ifdef CONFIG_PM +- +-struct locomo_save_data { +- u16 LCM_GPO; +- u16 LCM_SPICT; +- u16 LCM_GPE; +- u16 LCM_ASD; +- u16 LCM_SPIMD; +-}; +- +-static int locomo_suspend(struct platform_device *dev, pm_message_t state) +-{ +- struct locomo *lchip = platform_get_drvdata(dev); +- struct locomo_save_data *save; +- unsigned long flags; +- +- save = kmalloc(sizeof(struct locomo_save_data), GFP_KERNEL); +- if (!save) +- return -ENOMEM; +- +- lchip->saved_state = save; +- +- spin_lock_irqsave(&lchip->lock, flags); +- +- save->LCM_GPO = locomo_readl(lchip->base + LOCOMO_GPO); /* GPIO */ +- locomo_writel(0x00, lchip->base + LOCOMO_GPO); +- save->LCM_SPICT = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPICT); /* SPI */ +- locomo_writel(0x40, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); +- save->LCM_GPE = locomo_readl(lchip->base + LOCOMO_GPE); /* GPIO */ +- locomo_writel(0x00, lchip->base + LOCOMO_GPE); +- save->LCM_ASD = locomo_readl(lchip->base + LOCOMO_ASD); /* ADSTART */ +- locomo_writel(0x00, lchip->base + LOCOMO_ASD); +- save->LCM_SPIMD = locomo_readl(lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); /* SPI */ +- locomo_writel(0x3C14, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); +- +- locomo_writel(0x00, lchip->base + LOCOMO_PAIF); +- locomo_writel(0x00, lchip->base + LOCOMO_DAC); +- locomo_writel(0x00, lchip->base + LOCOMO_BACKLIGHT + LOCOMO_TC); +- +- if ((locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT0) & 0x88) && (locomo_readl(lchip->base + LOCOMO_LED + LOCOMO_LPT1) & 0x88)) +- locomo_writel(0x00, lchip->base + LOCOMO_C32K); /* CLK32 off */ +- else +- /* 18MHz already enabled, so no wait */ +- locomo_writel(0xc1, lchip->base + LOCOMO_C32K); /* CLK32 on */ +- +- locomo_writel(0x00, lchip->base + LOCOMO_TADC); /* 18MHz clock off*/ +- locomo_writel(0x00, lchip->base + LOCOMO_AUDIO + LOCOMO_ACC); /* 22MHz/24MHz clock off */ +- locomo_writel(0x00, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); /* FL */ +- +- spin_unlock_irqrestore(&lchip->lock, flags); +- +- return 0; +-} +- +-static int locomo_resume(struct platform_device *dev) +-{ +- struct locomo *lchip = platform_get_drvdata(dev); +- struct locomo_save_data *save; +- unsigned long r; +- unsigned long flags; +- +- save = lchip->saved_state; +- if (!save) +- return 0; +- +- spin_lock_irqsave(&lchip->lock, flags); +- +- locomo_writel(save->LCM_GPO, lchip->base + LOCOMO_GPO); +- locomo_writel(save->LCM_SPICT, lchip->base + LOCOMO_SPI + LOCOMO_SPICT); +- locomo_writel(save->LCM_GPE, lchip->base + LOCOMO_GPE); +- locomo_writel(save->LCM_ASD, lchip->base + LOCOMO_ASD); +- locomo_writel(save->LCM_SPIMD, lchip->base + LOCOMO_SPI + LOCOMO_SPIMD); +- +- locomo_writel(0x00, lchip->base + LOCOMO_C32K); +- locomo_writel(0x90, lchip->base + LOCOMO_TADC); +- +- locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KSC); +- r = locomo_readl(lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); +- r &= 0xFEFF; +- locomo_writel(r, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); +- locomo_writel(0x1, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KCMD); +- +- spin_unlock_irqrestore(&lchip->lock, flags); +- +- lchip->saved_state = NULL; +- kfree(save); +- +- return 0; +-} +-#endif +- +- +-/** +- * locomo_probe - probe for a single LoCoMo chip. +- * @phys_addr: physical address of device. +- * +- * Probe for a LoCoMo chip. This must be called +- * before any other locomo-specific code. +- * +- * Returns: +- * %-ENODEV device not found. +- * %-EBUSY physical address already marked in-use. +- * %0 successful. +- */ +-static int +-__locomo_probe(struct device *me, struct resource *mem, int irq) +-{ +- struct locomo_platform_data *pdata = me->platform_data; +- struct locomo *lchip; +- unsigned long r; +- int i, ret = -ENODEV; +- +- lchip = kzalloc(sizeof(struct locomo), GFP_KERNEL); +- if (!lchip) +- return -ENOMEM; +- +- spin_lock_init(&lchip->lock); +- +- lchip->dev = me; +- dev_set_drvdata(lchip->dev, lchip); +- +- lchip->phys = mem->start; +- lchip->irq = irq; +- lchip->irq_base = (pdata) ? pdata->irq_base : NO_IRQ; +- +- /* +- * 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; +- } +- +- /* locomo initialize */ +- locomo_writel(0, lchip->base + LOCOMO_ICR); +- /* KEYBOARD */ +- locomo_writel(0, lchip->base + LOCOMO_KEYBOARD + LOCOMO_KIC); +- +- /* GPIO */ +- locomo_writel(0, lchip->base + LOCOMO_GPO); +- locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) +- , lchip->base + LOCOMO_GPE); +- locomo_writel((LOCOMO_GPIO(1) | LOCOMO_GPIO(2) | LOCOMO_GPIO(13) | LOCOMO_GPIO(14)) +- , lchip->base + LOCOMO_GPD); +- locomo_writel(0, lchip->base + LOCOMO_GIE); +- +- /* Frontlight */ +- locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); +- locomo_writel(0, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); +- +- /* Longtime timer */ +- locomo_writel(0, lchip->base + LOCOMO_LTINT); +- /* SPI */ +- locomo_writel(0, lchip->base + LOCOMO_SPI + LOCOMO_SPIIE); +- +- locomo_writel(6 + 8 + 320 + 30 - 10, lchip->base + LOCOMO_ASD); +- r = locomo_readl(lchip->base + LOCOMO_ASD); +- r |= 0x8000; +- locomo_writel(r, lchip->base + LOCOMO_ASD); +- +- locomo_writel(6 + 8 + 320 + 30 - 10 - 128 + 4, lchip->base + LOCOMO_HSD); +- r = locomo_readl(lchip->base + LOCOMO_HSD); +- r |= 0x8000; +- locomo_writel(r, lchip->base + LOCOMO_HSD); +- +- locomo_writel(128 / 8, lchip->base + LOCOMO_HSC); +- +- /* XON */ +- locomo_writel(0x80, lchip->base + LOCOMO_TADC); +- udelay(1000); +- /* CLK9MEN */ +- r = locomo_readl(lchip->base + LOCOMO_TADC); +- r |= 0x10; +- locomo_writel(r, lchip->base + LOCOMO_TADC); +- udelay(100); +- +- /* init DAC */ +- r = locomo_readl(lchip->base + LOCOMO_DAC); +- r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; +- locomo_writel(r, lchip->base + LOCOMO_DAC); +- +- r = locomo_readl(lchip->base + LOCOMO_VER); +- printk(KERN_INFO "LoCoMo Chip: %lu%lu\n", (r >> 8), (r & 0xff)); +- +- /* +- * 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; +- +- out: +- kfree(lchip); +- return ret; +-} +- +-static int locomo_remove_child(struct device *dev, void *data) +-{ +- device_unregister(dev); +- return 0; +-} +- +-static void __locomo_remove(struct locomo *lchip) +-{ +- device_for_each_child(lchip->dev, NULL, locomo_remove_child); +- +- if (lchip->irq != NO_IRQ) { +- irq_set_chained_handler(lchip->irq, NULL); +- irq_set_handler_data(lchip->irq, NULL); +- } +- +- iounmap(lchip->base); +- kfree(lchip); +-} +- +-static int 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; +- +- return __locomo_probe(&dev->dev, mem, irq); +-} +- +-static int locomo_remove(struct platform_device *dev) +-{ +- struct locomo *lchip = platform_get_drvdata(dev); +- +- if (lchip) { +- __locomo_remove(lchip); +- platform_set_drvdata(dev, NULL); +- } +- +- return 0; +-} +- +-/* +- * 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. +- */ +-static struct 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 +- */ +-static inline struct locomo *locomo_chip_driver(struct locomo_dev *ldev) +-{ +- return (struct locomo *)dev_get_drvdata(ldev->dev.parent); +-} +- +-void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir) +-{ +- struct locomo *lchip = dev_get_drvdata(dev); +- unsigned long flags; +- unsigned int r; +- +- if (!lchip) +- return; +- +- spin_lock_irqsave(&lchip->lock, flags); +- +- r = locomo_readl(lchip->base + LOCOMO_GPD); +- if (dir) +- r |= bits; +- else +- r &= ~bits; +- locomo_writel(r, lchip->base + LOCOMO_GPD); +- +- r = locomo_readl(lchip->base + LOCOMO_GPE); +- if (dir) +- r |= bits; +- else +- r &= ~bits; +- locomo_writel(r, lchip->base + LOCOMO_GPE); +- +- spin_unlock_irqrestore(&lchip->lock, flags); +-} +-EXPORT_SYMBOL(locomo_gpio_set_dir); +- +-int locomo_gpio_read_level(struct device *dev, unsigned int bits) +-{ +- struct locomo *lchip = dev_get_drvdata(dev); +- unsigned long flags; +- unsigned int ret; +- +- if (!lchip) +- return -ENODEV; +- +- spin_lock_irqsave(&lchip->lock, flags); +- ret = locomo_readl(lchip->base + LOCOMO_GPL); +- spin_unlock_irqrestore(&lchip->lock, flags); +- +- ret &= bits; +- return ret; +-} +-EXPORT_SYMBOL(locomo_gpio_read_level); +- +-int locomo_gpio_read_output(struct device *dev, unsigned int bits) +-{ +- struct locomo *lchip = dev_get_drvdata(dev); +- unsigned long flags; +- unsigned int ret; +- +- if (!lchip) +- return -ENODEV; +- +- spin_lock_irqsave(&lchip->lock, flags); +- ret = locomo_readl(lchip->base + LOCOMO_GPO); +- spin_unlock_irqrestore(&lchip->lock, flags); +- +- ret &= bits; +- return ret; +-} +-EXPORT_SYMBOL(locomo_gpio_read_output); +- +-void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set) +-{ +- struct locomo *lchip = dev_get_drvdata(dev); +- unsigned long flags; +- unsigned int r; +- +- if (!lchip) +- return; +- +- spin_lock_irqsave(&lchip->lock, flags); +- +- r = locomo_readl(lchip->base + LOCOMO_GPO); +- if (set) +- r |= bits; +- else +- r &= ~bits; +- locomo_writel(r, lchip->base + LOCOMO_GPO); +- +- spin_unlock_irqrestore(&lchip->lock, flags); +-} +-EXPORT_SYMBOL(locomo_gpio_write); +- +-static void locomo_m62332_sendbit(void *mapbase, int bit) +-{ +- unsigned int r; +- +- 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_DATA_HOLD_TIME); /* 300 nsec */ +- 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 */ +- +- if (bit & 1) { +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r |= LOCOMO_DAC_SDAOEB; +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ +- } else { +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r &= ~(LOCOMO_DAC_SDAOEB); +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_LOW_SETUP_TIME); /* 300 nsec */ +- } +- +- udelay(DAC_DATA_SETUP_TIME); /* 250 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.0 usec */ +-} +- +-void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel) +-{ +- struct locomo *lchip = locomo_chip_driver(ldev); +- int i; +- unsigned char data; +- unsigned int r; +- void *mapbase = lchip->base; +- unsigned long flags; +- +- spin_lock_irqsave(&lchip->lock, flags); +- +- /* Start */ +- udelay(DAC_BUS_FREE_TIME); /* 5.0 usec */ +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ +- udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4.0 usec */ +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r &= ~(LOCOMO_DAC_SDAOEB); +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_START_HOLD_TIME); /* 5.0 usec */ +- udelay(DAC_DATA_HOLD_TIME); /* 300 nsec */ +- +- /* 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"); +- } +- +-out: +- /* stop */ +- 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_SCLOEB; +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ +- udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r |= LOCOMO_DAC_SDAOEB; +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_HIGH_SETUP_TIME); /* 1000 nsec */ +- udelay(DAC_SCL_HIGH_HOLD_TIME); /* 4 usec */ +- +- r = locomo_readl(mapbase + LOCOMO_DAC); +- r |= LOCOMO_DAC_SCLOEB | LOCOMO_DAC_SDAOEB; +- locomo_writel(r, mapbase + LOCOMO_DAC); +- udelay(DAC_LOW_SETUP_TIME); /* 1000 nsec */ +- udelay(DAC_SCL_LOW_HOLD_TIME); /* 4.7 usec */ +- +- spin_unlock_irqrestore(&lchip->lock, flags); +-} +-EXPORT_SYMBOL(locomo_m62332_senddata); +- +-/* +- * Frontlight control +- */ +- +-void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf) +-{ +- unsigned long flags; +- struct locomo *lchip = locomo_chip_driver(dev); +- +- if (vr) +- locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 1); +- else +- locomo_gpio_write(dev->dev.parent, LOCOMO_GPIO_FL_VR, 0); +- +- spin_lock_irqsave(&lchip->lock, flags); +- locomo_writel(bpwf, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); +- udelay(100); +- locomo_writel(duty, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALD); +- locomo_writel(bpwf | LOCOMO_ALC_EN, lchip->base + LOCOMO_FRONTLIGHT + LOCOMO_ALS); +- spin_unlock_irqrestore(&lchip->lock, flags); +-} +-EXPORT_SYMBOL(locomo_frontlight_set); +- +-/* +- * LoCoMo "Register Access Bus." +- * +- * We model this as a regular bus type, and hang devices directly +- * off this. +- */ +-static int locomo_match(struct device *_dev, struct device_driver *_drv) +-{ +- struct locomo_dev *dev = LOCOMO_DEV(_dev); +- struct locomo_driver *drv = LOCOMO_DRV(_drv); +- +- return dev->devid == drv->devid; +-} +- +-static int locomo_bus_suspend(struct device *dev, pm_message_t state) +-{ +- struct locomo_dev *ldev = LOCOMO_DEV(dev); +- struct locomo_driver *drv = LOCOMO_DRV(dev->driver); +- int ret = 0; +- +- if (drv && drv->suspend) +- ret = drv->suspend(ldev, state); +- return ret; +-} +- +-static int locomo_bus_resume(struct device *dev) +-{ +- struct locomo_dev *ldev = LOCOMO_DEV(dev); +- struct locomo_driver *drv = LOCOMO_DRV(dev->driver); +- int ret = 0; +- +- if (drv && drv->resume) +- ret = drv->resume(ldev); +- return ret; +-} +- +-static int 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; +-} +- +-static int locomo_bus_remove(struct device *dev) +-{ +- struct locomo_dev *ldev = LOCOMO_DEV(dev); +- struct locomo_driver *drv = LOCOMO_DRV(dev->driver); +- int ret = 0; +- +- if (drv->remove) +- ret = drv->remove(ldev); +- return ret; +-} +- +-struct bus_type locomo_bus_type = { +- .name = "locomo-bus", +- .match = locomo_match, +- .probe = locomo_bus_probe, +- .remove = locomo_bus_remove, +- .suspend = locomo_bus_suspend, +- .resume = locomo_bus_resume, +-}; +- +-int locomo_driver_register(struct locomo_driver *driver) +-{ +- driver->drv.bus = &locomo_bus_type; +- return driver_register(&driver->drv); +-} +-EXPORT_SYMBOL(locomo_driver_register); +- +-void locomo_driver_unregister(struct locomo_driver *driver) +-{ +- driver_unregister(&driver->drv); +-} +-EXPORT_SYMBOL(locomo_driver_unregister); +- +-static int __init locomo_init(void) +-{ +- int ret = bus_register(&locomo_bus_type); +- if (ret == 0) +- platform_driver_register(&locomo_device_driver); +- return ret; +-} +- +-static void __exit locomo_exit(void) +-{ +- platform_driver_unregister(&locomo_device_driver); +- bus_unregister(&locomo_bus_type); +-} +- +-module_init(locomo_init); +-module_exit(locomo_exit); +- +-MODULE_DESCRIPTION("Sharp LoCoMo core driver"); +-MODULE_LICENSE("GPL"); +-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>"); +diff --git a/arch/arm/include/asm/hardware/locomo.h b/arch/arm/include/asm/hardware/locomo.h +deleted file mode 100644 +index 74e51d6b..0000000 +--- a/arch/arm/include/asm/hardware/locomo.h ++++ /dev/null +@@ -1,221 +0,0 @@ +-/* +- * arch/arm/include/asm/hardware/locomo.h +- * +- * This file contains the definitions for the LoCoMo G/A Chip +- * +- * (C) Copyright 2004 John Lenz +- * +- * May be copied or modified under the terms of the GNU General Public +- * License. See linux/COPYING for more information. +- * +- * Based on sa1111.h +- */ +-#ifndef _ASM_ARCH_LOCOMO +-#define _ASM_ARCH_LOCOMO +- +-#define locomo_writel(val,addr) ({ *(volatile u16 *)(addr) = (val); }) +-#define locomo_readl(addr) (*(volatile u16 *)(addr)) +- +-/* LOCOMO version */ +-#define LOCOMO_VER 0x00 +- +-/* Pin status */ +-#define LOCOMO_ST 0x04 +- +-/* Pin status */ +-#define LOCOMO_C32K 0x08 +- +-/* Interrupt controller */ +-#define LOCOMO_ICR 0x0C +- +-/* MCS decoder for boot selecting */ +-#define LOCOMO_MCSX0 0x10 +-#define LOCOMO_MCSX1 0x14 +-#define LOCOMO_MCSX2 0x18 +-#define LOCOMO_MCSX3 0x1c +- +-/* Touch panel controller */ +-#define LOCOMO_ASD 0x20 /* AD start delay */ +-#define LOCOMO_HSD 0x28 /* HSYS delay */ +-#define LOCOMO_HSC 0x2c /* HSYS period */ +-#define LOCOMO_TADC 0x30 /* tablet ADC clock */ +- +- +-/* Long time timer */ +-#define LOCOMO_LTC 0xd8 /* LTC interrupt setting */ +-#define LOCOMO_LTINT 0xdc /* LTC interrupt */ +- +-/* DAC control signal for LCD (COMADJ ) */ +-#define LOCOMO_DAC 0xe0 +-/* DAC control */ +-#define LOCOMO_DAC_SCLOEB 0x08 /* SCL pin output data */ +-#define LOCOMO_DAC_TEST 0x04 /* Test bit */ +-#define LOCOMO_DAC_SDA 0x02 /* SDA pin level (read-only) */ +-#define LOCOMO_DAC_SDAOEB 0x01 /* SDA pin output data */ +- +-/* SPI interface */ +-#define LOCOMO_SPI 0x60 +-#define LOCOMO_SPIMD 0x00 /* SPI mode setting */ +-#define LOCOMO_SPICT 0x04 /* SPI mode control */ +-#define LOCOMO_SPIST 0x08 /* SPI status */ +-#define LOCOMO_SPI_TEND (1 << 3) /* Transfer end bit */ +-#define LOCOMO_SPI_REND (1 << 2) /* Receive end bit */ +-#define LOCOMO_SPI_RFW (1 << 1) /* write buffer bit */ +-#define LOCOMO_SPI_RFR (1) /* read buffer bit */ +- +-#define LOCOMO_SPIIS 0x10 /* SPI interrupt status */ +-#define LOCOMO_SPIWE 0x14 /* SPI interrupt status write enable */ +-#define LOCOMO_SPIIE 0x18 /* SPI interrupt enable */ +-#define LOCOMO_SPIIR 0x1c /* SPI interrupt request */ +-#define LOCOMO_SPITD 0x20 /* SPI transfer data write */ +-#define LOCOMO_SPIRD 0x24 /* SPI receive data read */ +-#define LOCOMO_SPITS 0x28 /* SPI transfer data shift */ +-#define LOCOMO_SPIRS 0x2C /* SPI receive data shift */ +- +-/* GPIO */ +-#define LOCOMO_GPD 0x90 /* GPIO direction */ +-#define LOCOMO_GPE 0x94 /* GPIO input enable */ +-#define LOCOMO_GPL 0x98 /* GPIO level */ +-#define LOCOMO_GPO 0x9c /* GPIO out data setting */ +-#define LOCOMO_GRIE 0xa0 /* GPIO rise detection */ +-#define LOCOMO_GFIE 0xa4 /* GPIO fall detection */ +-#define LOCOMO_GIS 0xa8 /* GPIO edge detection status */ +-#define LOCOMO_GWE 0xac /* GPIO status write enable */ +-#define LOCOMO_GIE 0xb0 /* GPIO interrupt enable */ +-#define LOCOMO_GIR 0xb4 /* GPIO interrupt request */ +-#define LOCOMO_GPIO(Nb) (0x01 << (Nb)) +-#define LOCOMO_GPIO_RTS LOCOMO_GPIO(0) +-#define LOCOMO_GPIO_CTS LOCOMO_GPIO(1) +-#define LOCOMO_GPIO_DSR LOCOMO_GPIO(2) +-#define LOCOMO_GPIO_DTR LOCOMO_GPIO(3) +-#define LOCOMO_GPIO_LCD_VSHA_ON LOCOMO_GPIO(4) +-#define LOCOMO_GPIO_LCD_VSHD_ON LOCOMO_GPIO(5) +-#define LOCOMO_GPIO_LCD_VEE_ON LOCOMO_GPIO(6) +-#define LOCOMO_GPIO_LCD_MOD LOCOMO_GPIO(7) +-#define LOCOMO_GPIO_DAC_ON LOCOMO_GPIO(8) +-#define LOCOMO_GPIO_FL_VR LOCOMO_GPIO(9) +-#define LOCOMO_GPIO_DAC_SDATA LOCOMO_GPIO(10) +-#define LOCOMO_GPIO_DAC_SCK LOCOMO_GPIO(11) +-#define LOCOMO_GPIO_DAC_SLOAD LOCOMO_GPIO(12) +-#define LOCOMO_GPIO_CARD_DETECT LOCOMO_GPIO(13) +-#define LOCOMO_GPIO_WRITE_PROT LOCOMO_GPIO(14) +-#define LOCOMO_GPIO_CARD_POWER LOCOMO_GPIO(15) +- +-/* Start the definitions of the devices. Each device has an initial +- * base address and a series of offsets from that base address. */ +- +-/* Keyboard controller */ +-#define LOCOMO_KEYBOARD 0x40 +-#define LOCOMO_KIB 0x00 /* KIB level */ +-#define LOCOMO_KSC 0x04 /* KSTRB control */ +-#define LOCOMO_KCMD 0x08 /* KSTRB command */ +-#define LOCOMO_KIC 0x0c /* Key interrupt */ +- +-/* Front light adjustment controller */ +-#define LOCOMO_FRONTLIGHT 0xc8 +-#define LOCOMO_ALS 0x00 /* Adjust light cycle */ +-#define LOCOMO_ALD 0x04 /* Adjust light duty */ +- +-#define LOCOMO_ALC_EN 0x8000 +- +-/* Backlight controller: TFT signal */ +-#define LOCOMO_BACKLIGHT 0x38 +-#define LOCOMO_TC 0x00 /* TFT control signal */ +-#define LOCOMO_CPSD 0x04 /* CPS delay */ +- +-/* Audio controller */ +-#define LOCOMO_AUDIO 0x54 +-#define LOCOMO_ACC 0x00 /* Audio clock */ +-#define LOCOMO_PAIF 0xD0 /* PCM audio interface */ +-/* Audio clock */ +-#define LOCOMO_ACC_XON 0x80 +-#define LOCOMO_ACC_XEN 0x40 +-#define LOCOMO_ACC_XSEL0 0x00 +-#define LOCOMO_ACC_XSEL1 0x20 +-#define LOCOMO_ACC_MCLKEN 0x10 +-#define LOCOMO_ACC_64FSEN 0x08 +-#define LOCOMO_ACC_CLKSEL000 0x00 /* mclk 2 */ +-#define LOCOMO_ACC_CLKSEL001 0x01 /* mclk 3 */ +-#define LOCOMO_ACC_CLKSEL010 0x02 /* mclk 4 */ +-#define LOCOMO_ACC_CLKSEL011 0x03 /* mclk 6 */ +-#define LOCOMO_ACC_CLKSEL100 0x04 /* mclk 8 */ +-#define LOCOMO_ACC_CLKSEL101 0x05 /* mclk 12 */ +-/* PCM audio interface */ +-#define LOCOMO_PAIF_SCINV 0x20 +-#define LOCOMO_PAIF_SCEN 0x10 +-#define LOCOMO_PAIF_LRCRST 0x08 +-#define LOCOMO_PAIF_LRCEVE 0x04 +-#define LOCOMO_PAIF_LRCINV 0x02 +-#define LOCOMO_PAIF_LRCEN 0x01 +- +-/* LED controller */ +-#define LOCOMO_LED 0xe8 +-#define LOCOMO_LPT0 0x00 +-#define LOCOMO_LPT1 0x04 +-/* LED control */ +-#define LOCOMO_LPT_TOFH 0x80 +-#define LOCOMO_LPT_TOFL 0x08 +-#define LOCOMO_LPT_TOH(TOH) ((TOH & 0x7) << 4) +-#define LOCOMO_LPT_TOL(TOL) ((TOL & 0x7)) +- +-extern struct bus_type locomo_bus_type; +- +-#define LOCOMO_DEVID_KEYBOARD 0 +-#define LOCOMO_DEVID_FRONTLIGHT 1 +-#define LOCOMO_DEVID_BACKLIGHT 2 +-#define LOCOMO_DEVID_AUDIO 3 +-#define LOCOMO_DEVID_LED 4 +-#define LOCOMO_DEVID_UART 5 +-#define LOCOMO_DEVID_SPI 6 +- +-struct locomo_dev { +- struct device dev; +- unsigned int devid; +- unsigned int irq[1]; +- +- void *mapbase; +- unsigned long length; +- +- u64 dma_mask; +-}; +- +-#define LOCOMO_DEV(_d) container_of((_d), struct locomo_dev, dev) +- +-#define locomo_get_drvdata(d) dev_get_drvdata(&(d)->dev) +-#define locomo_set_drvdata(d,p) dev_set_drvdata(&(d)->dev, p) +- +-struct locomo_driver { +- struct device_driver drv; +- unsigned int devid; +- int (*probe)(struct locomo_dev *); +- int (*remove)(struct locomo_dev *); +- int (*suspend)(struct locomo_dev *, pm_message_t); +- int (*resume)(struct locomo_dev *); +-}; +- +-#define LOCOMO_DRV(_d) container_of((_d), struct locomo_driver, drv) +- +-#define LOCOMO_DRIVER_NAME(_ldev) ((_ldev)->dev.driver->name) +- +-void locomo_lcd_power(struct locomo_dev *, int, unsigned int); +- +-int locomo_driver_register(struct locomo_driver *); +-void locomo_driver_unregister(struct locomo_driver *); +- +-/* GPIO control functions */ +-void locomo_gpio_set_dir(struct device *dev, unsigned int bits, unsigned int dir); +-int locomo_gpio_read_level(struct device *dev, unsigned int bits); +-int locomo_gpio_read_output(struct device *dev, unsigned int bits); +-void locomo_gpio_write(struct device *dev, unsigned int bits, unsigned int set); +- +-/* M62332 control function */ +-void locomo_m62332_senddata(struct locomo_dev *ldev, unsigned int dac_data, int channel); +- +-/* Frontlight control */ +-void locomo_frontlight_set(struct locomo_dev *dev, int duty, int vr, int bpwf); +- +-struct locomo_platform_data { +- int irq_base; /* IRQ base for cascaded on-chip IRQs */ +-}; +- +-#endif +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0013-video-backlight-drop-old-locomo-bl-lcd-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0013-video-backlight-drop-old-locomo-bl-lcd-driver.patch new file mode 100644 index 0000000..1713af7 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0013-video-backlight-drop-old-locomo-bl-lcd-driver.patch @@ -0,0 +1,278 @@ +From 19c650358a308711b8f7e6e46acf778596f8c45a Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Thu, 5 Dec 2013 00:07:17 +0400 +Subject: [PATCH 13/20] video: backlight: drop old locomo bl/lcd driver + +Old locomolcd driver is now completely obsolete by new locomo_bl and +locomo_lcd drivers, so let's drop it. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/video/backlight/locomolcd.c | 255 ------------------------------------ + 1 file changed, 255 deletions(-) + delete mode 100644 drivers/video/backlight/locomolcd.c + +diff --git a/drivers/video/backlight/locomolcd.c b/drivers/video/backlight/locomolcd.c +deleted file mode 100644 +index 6c3ec42..0000000 +--- a/drivers/video/backlight/locomolcd.c ++++ /dev/null +@@ -1,255 +0,0 @@ +-/* +- * Backlight control code for Sharp Zaurus SL-5500 +- * +- * Copyright 2005 John Lenz <lenz@cs.wisc.edu> +- * Maintainer: Pavel Machek <pavel@ucw.cz> (unless John wants to :-) +- * GPL v2 +- * +- * This driver assumes single CPU. That's okay, because collie is +- * slightly old hardware, and no one is going to retrofit second CPU to +- * old PDA. +- */ +- +-/* LCD power functions */ +-#include <linux/module.h> +-#include <linux/init.h> +-#include <linux/delay.h> +-#include <linux/device.h> +-#include <linux/interrupt.h> +-#include <linux/fb.h> +-#include <linux/backlight.h> +- +-#include <asm/hardware/locomo.h> +-#include <asm/irq.h> +-#include <asm/mach/sharpsl_param.h> +-#include <asm/mach-types.h> +- +-#include "../../../arch/arm/mach-sa1100/generic.h" +- +-static struct backlight_device *locomolcd_bl_device; +-static struct locomo_dev *locomolcd_dev; +-static unsigned long locomolcd_flags; +-#define LOCOMOLCD_SUSPENDED 0x01 +- +-static void locomolcd_on(int comadj) +-{ +- locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 1); +- mdelay(2); +- +- locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 1); +- mdelay(2); +- +- locomo_m62332_senddata(locomolcd_dev, comadj, 0); +- mdelay(5); +- +- locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 1); +- mdelay(10); +- +- /* TFTCRST | CPSOUT=0 | CPSEN */ +- locomo_writel(0x01, locomolcd_dev->mapbase + LOCOMO_TC); +- +- /* Set CPSD */ +- locomo_writel(6, locomolcd_dev->mapbase + LOCOMO_CPSD); +- +- /* TFTCRST | CPSOUT=0 | CPSEN */ +- locomo_writel((0x04 | 0x01), locomolcd_dev->mapbase + LOCOMO_TC); +- mdelay(10); +- +- locomo_gpio_set_dir(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 1); +-} +- +-static void locomolcd_off(int comadj) +-{ +- /* TFTCRST=1 | CPSOUT=1 | CPSEN = 0 */ +- locomo_writel(0x06, locomolcd_dev->mapbase + LOCOMO_TC); +- mdelay(1); +- +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHA_ON, 0); +- mdelay(110); +- +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VEE_ON, 0); +- mdelay(700); +- +- /* TFTCRST=0 | CPSOUT=0 | CPSEN = 0 */ +- locomo_writel(0, locomolcd_dev->mapbase + LOCOMO_TC); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_MOD, 0); +- locomo_gpio_write(locomolcd_dev->dev.parent, LOCOMO_GPIO_LCD_VSHD_ON, 0); +-} +- +-void locomolcd_power(int on) +-{ +- int comadj = sharpsl_param.comadj; +- unsigned long flags; +- +- local_irq_save(flags); +- +- if (!locomolcd_dev) { +- local_irq_restore(flags); +- return; +- } +- +- /* read comadj */ +- if (comadj == -1 && machine_is_collie()) +- comadj = 128; +- if (comadj == -1 && machine_is_poodle()) +- comadj = 118; +- +- if (on) +- locomolcd_on(comadj); +- else +- locomolcd_off(comadj); +- +- local_irq_restore(flags); +-} +-EXPORT_SYMBOL(locomolcd_power); +- +-static int current_intensity; +- +-static int locomolcd_set_intensity(struct backlight_device *bd) +-{ +- int intensity = bd->props.brightness; +- +- if (bd->props.power != FB_BLANK_UNBLANK) +- intensity = 0; +- if (bd->props.fb_blank != FB_BLANK_UNBLANK) +- intensity = 0; +- if (locomolcd_flags & LOCOMOLCD_SUSPENDED) +- intensity = 0; +- +- switch (intensity) { +- /* +- * AC and non-AC are handled differently, +- * but produce same results in sharp code? +- */ +- case 0: +- locomo_frontlight_set(locomolcd_dev, 0, 0, 161); +- break; +- case 1: +- locomo_frontlight_set(locomolcd_dev, 117, 0, 161); +- break; +- case 2: +- locomo_frontlight_set(locomolcd_dev, 163, 0, 148); +- break; +- case 3: +- locomo_frontlight_set(locomolcd_dev, 194, 0, 161); +- break; +- case 4: +- locomo_frontlight_set(locomolcd_dev, 194, 1, 161); +- break; +- default: +- return -ENODEV; +- } +- current_intensity = intensity; +- return 0; +-} +- +-static int locomolcd_get_intensity(struct backlight_device *bd) +-{ +- return current_intensity; +-} +- +-static const struct backlight_ops locomobl_data = { +- .get_brightness = locomolcd_get_intensity, +- .update_status = locomolcd_set_intensity, +-}; +- +-#ifdef CONFIG_PM_SLEEP +-static int locomolcd_suspend(struct device *dev) +-{ +- locomolcd_flags |= LOCOMOLCD_SUSPENDED; +- locomolcd_set_intensity(locomolcd_bl_device); +- return 0; +-} +- +-static int locomolcd_resume(struct device *dev) +-{ +- locomolcd_flags &= ~LOCOMOLCD_SUSPENDED; +- locomolcd_set_intensity(locomolcd_bl_device); +- return 0; +-} +-#endif +- +-static SIMPLE_DEV_PM_OPS(locomolcd_pm_ops, locomolcd_suspend, locomolcd_resume); +- +-static int locomolcd_probe(struct locomo_dev *ldev) +-{ +- struct backlight_properties props; +- unsigned long flags; +- +- local_irq_save(flags); +- locomolcd_dev = ldev; +- +- locomo_gpio_set_dir(ldev->dev.parent, LOCOMO_GPIO_FL_VR, 0); +- +- /* +- * the poodle_lcd_power function is called for the first time +- * from fs_initcall, which is before locomo is activated. +- * We need to recall poodle_lcd_power here +- */ +- if (machine_is_poodle()) +- locomolcd_power(1); +- +- local_irq_restore(flags); +- +- memset(&props, 0, sizeof(struct backlight_properties)); +- props.type = BACKLIGHT_RAW; +- props.max_brightness = 4; +- locomolcd_bl_device = backlight_device_register("locomo-bl", +- &ldev->dev, NULL, +- &locomobl_data, &props); +- +- if (IS_ERR(locomolcd_bl_device)) +- return PTR_ERR(locomolcd_bl_device); +- +- /* Set up frontlight so that screen is readable */ +- locomolcd_bl_device->props.brightness = 2; +- locomolcd_set_intensity(locomolcd_bl_device); +- +- return 0; +-} +- +-static int locomolcd_remove(struct locomo_dev *dev) +-{ +- unsigned long flags; +- +- locomolcd_bl_device->props.brightness = 0; +- locomolcd_bl_device->props.power = 0; +- locomolcd_set_intensity(locomolcd_bl_device); +- +- backlight_device_unregister(locomolcd_bl_device); +- local_irq_save(flags); +- locomolcd_dev = NULL; +- local_irq_restore(flags); +- return 0; +-} +- +-static struct locomo_driver poodle_lcd_driver = { +- .drv = { +- .name = "locomo-backlight", +- .pm = &locomolcd_pm_ops, +- }, +- .devid = LOCOMO_DEVID_BACKLIGHT, +- .probe = locomolcd_probe, +- .remove = locomolcd_remove, +-}; +- +-static int __init locomolcd_init(void) +-{ +- return locomo_driver_register(&poodle_lcd_driver); +-} +- +-static void __exit locomolcd_exit(void) +-{ +- locomo_driver_unregister(&poodle_lcd_driver); +-} +- +-module_init(locomolcd_init); +-module_exit(locomolcd_exit); +- +-MODULE_AUTHOR("John Lenz <lenz@cs.wisc.edu>, Pavel Machek <pavel@ucw.cz>"); +-MODULE_DESCRIPTION("Collie LCD driver"); +-MODULE_LICENSE("GPL"); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0014-ARM-sa1100-make-collie-use-new-locomo-drivers.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0014-ARM-sa1100-make-collie-use-new-locomo-drivers.patch new file mode 100644 index 0000000..31a72d5 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0014-ARM-sa1100-make-collie-use-new-locomo-drivers.patch @@ -0,0 +1,408 @@ +From 3b7a269471c659761c7e2dfef772404270612b4e Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 03:12:39 +0400 +Subject: [PATCH 14/20] ARM: sa1100: make collie use new locomo drivers + +Switch collie to new mfd-based locomo driver. Update platform data and +add necessary spi, i2c and regulator devices. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + arch/arm/mach-sa1100/Kconfig | 1 - + arch/arm/mach-sa1100/collie.c | 213 ++++++++++++++++++++++------- + arch/arm/mach-sa1100/include/mach/collie.h | 25 +++- + 3 files changed, 187 insertions(+), 52 deletions(-) + +diff --git a/arch/arm/mach-sa1100/Kconfig b/arch/arm/mach-sa1100/Kconfig +index c6f6ed1..37af126 100644 +--- a/arch/arm/mach-sa1100/Kconfig ++++ b/arch/arm/mach-sa1100/Kconfig +@@ -48,7 +48,6 @@ endchoice + config SA1100_COLLIE + bool "Sharp Zaurus SL5500" + # FIXME: select ARM_SA11x0_CPUFREQ +- select SHARP_LOCOMO + select SHARP_PARAM + select SHARP_SCOOP + help +diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c +index 3cc2b71..5bdc4bd 100644 +--- a/arch/arm/mach-sa1100/collie.c ++++ b/arch/arm/mach-sa1100/collie.c +@@ -24,13 +24,21 @@ + #include <linux/platform_data/sa11x0-serial.h> + #include <linux/platform_device.h> + #include <linux/mfd/ucb1x00.h> ++#include <linux/mfd/locomo.h> + #include <linux/mtd/mtd.h> + #include <linux/mtd/partitions.h> + #include <linux/timer.h> + #include <linux/gpio_keys.h> + #include <linux/input.h> ++#include <linux/i2c.h> + #include <linux/gpio.h> ++#include <linux/gpio/machine.h> + #include <linux/power/gpio-charger.h> ++#include <linux/iio/machine.h> ++#include <linux/mmc/host.h> ++#include <linux/regulator/fixed.h> ++#include <linux/regulator/machine.h> ++#include <linux/spi/mmc_spi.h> + + #include <video/sa1100fb.h> + +@@ -47,7 +55,6 @@ + + #include <asm/hardware/scoop.h> + #include <asm/mach/sharpsl_param.h> +-#include <asm/hardware/locomo.h> + #include <linux/platform_data/mfd-mcp-sa11x0.h> + #include <mach/irqs.h> + +@@ -151,36 +158,54 @@ static struct platform_device collie_power_device = { + .dev.platform_data = &collie_power_data, + }; + +-#ifdef CONFIG_SHARP_LOCOMO + /* + * low-level UART features. + */ +-struct platform_device collie_locomo_device; ++static struct gpio collie_uart_gpio[] = { ++ { COLLIE_GPIO_CTS, GPIOF_IN, "CTS" }, ++ { COLLIE_GPIO_RTS, GPIOF_OUT_INIT_LOW, "RTS" }, ++ { COLLIE_GPIO_DTR, GPIOF_OUT_INIT_LOW, "DTR" }, ++ { COLLIE_GPIO_DSR, GPIOF_IN, "DSR" }, ++}; ++ ++static bool collie_uart_gpio_ok; + + static void collie_uart_set_mctrl(struct uart_port *port, u_int mctrl) + { +- if (mctrl & TIOCM_RTS) +- locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 0); +- else +- locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_RTS, 1); +- +- if (mctrl & TIOCM_DTR) +- locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 0); +- else +- locomo_gpio_write(&collie_locomo_device.dev, LOCOMO_GPIO_DTR, 1); ++ if (!collie_uart_gpio_ok) { ++ int rc = gpio_request_array(collie_uart_gpio, ++ ARRAY_SIZE(collie_uart_gpio)); ++ if (rc) ++ pr_err("collie_uart_set_mctrl: gpio request %d\n", rc); ++ else ++ collie_uart_gpio_ok = true; ++ } ++ ++ if (collie_uart_gpio_ok) { ++ gpio_set_value(COLLIE_GPIO_RTS, !(mctrl & TIOCM_RTS)); ++ gpio_set_value(COLLIE_GPIO_DTR, !(mctrl & TIOCM_DTR)); ++ } + } + + static u_int collie_uart_get_mctrl(struct uart_port *port) + { + int ret = TIOCM_CD; +- unsigned int r; + +- r = locomo_gpio_read_output(&collie_locomo_device.dev, LOCOMO_GPIO_CTS & LOCOMO_GPIO_DSR); +- if (r == -ENODEV) ++ if (!collie_uart_gpio_ok) { ++ int rc = gpio_request_array(collie_uart_gpio, ++ ARRAY_SIZE(collie_uart_gpio)); ++ if (rc) ++ pr_err("collie_uart_get_mctrl: gpio request %d\n", rc); ++ else ++ collie_uart_gpio_ok = true; ++ } ++ ++ if (!collie_uart_gpio_ok) + return ret; +- if (r & LOCOMO_GPIO_CTS) ++ ++ if (gpio_get_value(COLLIE_GPIO_CTS)) + ret |= TIOCM_CTS; +- if (r & LOCOMO_GPIO_DSR) ++ if (gpio_get_value(COLLIE_GPIO_DSR)) + ret |= TIOCM_DSR; + + return ret; +@@ -191,33 +216,35 @@ static struct sa1100_port_fns collie_port_fns __initdata = { + .get_mctrl = collie_uart_get_mctrl, + }; + +-static int collie_uart_probe(struct locomo_dev *dev) +-{ +- return 0; +-} +- +-static int collie_uart_remove(struct locomo_dev *dev) +-{ +- return 0; +-} ++static struct regulator_consumer_supply collie_amp_on_consumer_supplies[] = { ++ REGULATOR_SUPPLY("VCC", "1-004e"), ++}; + +-static struct locomo_driver collie_uart_driver = { +- .drv = { +- .name = "collie_uart", ++static struct regulator_init_data collie_amp_on_init_data = { ++ .constraints = { ++ .name = "AMP_ON", ++ .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, +- .devid = LOCOMO_DEVID_UART, +- .probe = collie_uart_probe, +- .remove = collie_uart_remove, ++ .consumer_supplies = collie_amp_on_consumer_supplies, ++ .num_consumer_supplies = ARRAY_SIZE(collie_amp_on_consumer_supplies), + }; + +-static int __init collie_uart_init(void) +-{ +- return locomo_driver_register(&collie_uart_driver); +-} +-device_initcall(collie_uart_init); +- +-#endif ++static struct fixed_voltage_config collie_amp_on_data = { ++ .supply_name = "amp_on", ++ .microvolts = 3300000, ++ .gpio = COLLIE_GPIO_AMP2_ON, ++ .startup_delay = 5, ++ .enable_high = 1, ++ .init_data = &collie_amp_on_init_data, ++}; + ++static struct platform_device collie_amp_on_device = { ++ .name = "reg-fixed-voltage", ++ .id = -1, ++ .dev = { ++ .platform_data = &collie_amp_on_data, ++ }, ++}; + + static struct resource locomo_resources[] = { + [0] = DEFINE_RES_MEM(0x40000000, SZ_8K), +@@ -225,14 +252,15 @@ static struct resource locomo_resources[] = { + }; + + static struct locomo_platform_data locomo_info = { +- .irq_base = IRQ_BOARD_START, ++ .gpio_base = COLLIE_LOCOMO_GPIO_BASE, ++ .comadj = 128, + }; + +-struct platform_device collie_locomo_device = { ++static struct platform_device collie_locomo_device = { + .name = "locomo", + .id = 0, + .dev = { +- .platform_data = &locomo_info, ++ .platform_data = &locomo_info, + }, + .num_resources = ARRAY_SIZE(locomo_resources), + .resource = locomo_resources, +@@ -270,7 +298,55 @@ static struct platform_device collie_gpio_keys_device = { + }, + }; + ++static int collie_mmc_init(struct device *dev, ++ irqreturn_t (*isr)(int, void*), void *mmc) ++{ ++ int ret; ++ ++ ret = gpio_request(COLLIE_GPIO_CARD_POWER, "MMC power"); ++ if (!ret) ++ ret = gpio_direction_output(COLLIE_GPIO_CARD_POWER, 0); ++ if (ret) ++ gpio_free(COLLIE_GPIO_CARD_POWER); ++ return ret; ++} ++ ++static void collie_mmc_exit(struct device *dev, void *mmc) ++{ ++ gpio_free(COLLIE_GPIO_CARD_POWER); ++} ++ ++static void collie_mmc_setpower(struct device *dev, unsigned int mask) ++{ ++ gpio_set_value(COLLIE_GPIO_CARD_POWER, !!mask); ++} ++ ++static struct mmc_spi_platform_data collie_mmc_data = { ++ .init = collie_mmc_init, ++ .exit = collie_mmc_exit, ++ .setpower = collie_mmc_setpower, ++ .detect_delay = 200, ++ .powerup_msecs = 200, ++ .ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, ++ .flags = MMC_SPI_USE_CD_GPIO | MMC_SPI_USE_RO_GPIO, ++ .cd_gpio = COLLIE_GPIO_CARD_DETECT, ++ .ro_gpio = COLLIE_GPIO_CARD_RO, ++ .caps2 = MMC_CAP2_RO_ACTIVE_HIGH, ++}; ++ ++static struct spi_board_info collie_spi_board_info[] __initdata = { ++ { ++ .modalias = "mmc_spi", ++ .platform_data = &collie_mmc_data, ++ .max_speed_hz = 25000000, ++ .bus_num = 0, ++ .chip_select = 0, ++ .mode = SPI_MODE_0, ++ }, ++}; ++ + static struct platform_device *devices[] __initdata = { ++ &collie_amp_on_device, + &collie_locomo_device, + &colliescoop_device, + &collie_power_device, +@@ -347,10 +423,39 @@ static struct sa1100fb_mach_info collie_lcd_info = { + + .lccr0 = LCCR0_Color | LCCR0_Sngl | LCCR0_Act, + .lccr3 = LCCR3_OutEnH | LCCR3_PixRsEdg | LCCR3_ACBsDiv(2), ++}; + +-#ifdef CONFIG_BACKLIGHT_LOCOMO +- .lcd_power = locomolcd_power +-#endif ++static struct iio_map locomo_iio_map[] = { ++ { ++ .consumer_dev_name = "locomo-lcd.0", ++ .consumer_channel = "comadj", ++ .adc_channel_label = "CH0", ++ }, ++ { } ++}; ++ ++static struct i2c_board_info locomo_i2c_devs[] __initdata = { ++ { ++ I2C_BOARD_INFO("m62332", 0x4e), ++ .platform_data = locomo_iio_map, ++ }, ++}; ++ ++static struct gpiod_lookup_table collie_bl_gpios_table = { ++ .dev_id = "locomo-backlight.0", ++ .table = { ++ GPIO_LOOKUP("locomo-gpio", 9, "flvr", GPIO_ACTIVE_HIGH), ++ { }, ++ }, ++}, collie_lcd_gpios_table = { ++ .dev_id = "locomo-lcd.0", ++ .table = { ++ GPIO_LOOKUP("locomo-gpio", 4, "VSHA", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 5, "VSHD", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 6, "Vee", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 7, "MOD", GPIO_ACTIVE_HIGH), ++ { }, ++ }, + }; + + static void __init collie_init(void) +@@ -381,11 +486,19 @@ static void __init collie_init(void) + + GPSR |= _COLLIE_GPIO_UCB1x00_RESET; + ++ sharpsl_save_param(); ++ + sa11x0_ppc_configure_mcp(); + + + platform_scoop_config = &collie_pcmcia_config; + ++ if (sharpsl_param.comadj != -1) ++ locomo_info.comadj = sharpsl_param.comadj; ++ ++ gpiod_add_lookup_table(&collie_bl_gpios_table); ++ gpiod_add_lookup_table(&collie_lcd_gpios_table); ++ + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + if (ret) { + printk(KERN_WARNING "collie: Unable to register LoCoMo device\n"); +@@ -397,7 +510,13 @@ static void __init collie_init(void) + sa11x0_register_mcp(&collie_mcp_data); + sa11x0_register_irda(&collie_ir_data); + +- sharpsl_save_param(); ++ i2c_register_board_info(1, ++ locomo_i2c_devs, ARRAY_SIZE(locomo_i2c_devs)); ++ ++ spi_register_board_info(collie_spi_board_info, ++ ARRAY_SIZE(collie_spi_board_info)); ++ ++ regulator_has_full_constraints(); + } + + static struct map_desc collie_io_desc[] __initdata = { +@@ -419,9 +538,7 @@ static void __init collie_map_io(void) + sa1100_map_io(); + iotable_init(collie_io_desc, ARRAY_SIZE(collie_io_desc)); + +-#ifdef CONFIG_SHARP_LOCOMO + sa1100_register_uart_fns(&collie_port_fns); +-#endif + sa1100_register_uart(0, 3); + sa1100_register_uart(1, 1); + } +diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h +index b478ca1..a66319a 100644 +--- a/arch/arm/mach-sa1100/include/mach/collie.h ++++ b/arch/arm/mach-sa1100/include/mach/collie.h +@@ -24,12 +24,12 @@ extern void locomolcd_power(int on); + #define COLLIE_SCP_MUTE_L SCOOP_GPCR_PA14 + #define COLLIE_SCP_MUTE_R SCOOP_GPCR_PA15 + #define COLLIE_SCP_5VON SCOOP_GPCR_PA16 +-#define COLLIE_SCP_AMP_ON SCOOP_GPCR_PA17 ++#define COLLIE_GPIO_AMP2_ON (COLLIE_SCOOP_GPIO_BASE + 6) + #define COLLIE_GPIO_VPEN (COLLIE_SCOOP_GPIO_BASE + 7) + #define COLLIE_SCP_LB_VOL_CHG SCOOP_GPCR_PA19 + + #define COLLIE_SCOOP_IO_DIR (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \ +- COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \ ++ COLLIE_SCP_5VON | \ + COLLIE_SCP_LB_VOL_CHG) + #define COLLIE_SCOOP_IO_OUT (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R) + +@@ -81,7 +81,7 @@ extern void locomolcd_power(int on); + #define COLLIE_TC35143_GPIO_TBL_CHK UCB_IO_1 + #define COLLIE_TC35143_GPIO_VPEN_ON UCB_IO_2 + #define COLLIE_GPIO_IR_ON (COLLIE_TC35143_GPIO_BASE + 3) +-#define COLLIE_TC35143_GPIO_AMP_ON UCB_IO_4 ++#define COLLIE_GPIO_AMP1_ON (COLLIE_TC35143_GPIO_BASE + 4) + #define COLLIE_TC35143_GPIO_VERSION1 UCB_IO_5 + #define COLLIE_TC35143_GPIO_FS8KLPF UCB_IO_5 + #define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6 +@@ -92,4 +92,23 @@ extern void locomolcd_power(int on); + #define COLLIE_TC35143_GPIO_OUT (UCB_IO_1 | UCB_IO_3 | UCB_IO_4 \ + | UCB_IO_6) + ++/* GPIOs on LoCoMo GA */ ++#define COLLIE_LOCOMO_GPIO_BASE (GPIO_MAX + 23) ++#define COLLIE_GPIO_RTS (COLLIE_LOCOMO_GPIO_BASE + 0) ++#define COLLIE_GPIO_CTS (COLLIE_LOCOMO_GPIO_BASE + 1) ++#define COLLIE_GPIO_DSR (COLLIE_LOCOMO_GPIO_BASE + 2) ++#define COLLIE_GPIO_DTR (COLLIE_LOCOMO_GPIO_BASE + 3) ++#define COLLIE_GPIO_LCD_VSHA_ON (COLLIE_LOCOMO_GPIO_BASE + 4) ++#define COLLIE_GPIO_LCD_VSHD_ON (COLLIE_LOCOMO_GPIO_BASE + 5) ++#define COLLIE_GPIO_LCD_VEE_ON (COLLIE_LOCOMO_GPIO_BASE + 6) ++#define COLLIE_GPIO_LCD_MOD (COLLIE_LOCOMO_GPIO_BASE + 7) ++#define COLLIE_LOCOMO_GPIO_DAC_ON LOCOMO_GPIO(8) ++#define COLLIE_GPIO_FL_VR (COLLIE_LOCOMO_GPIO_BASE + 9) ++#define COLLIE_LOCOMO_GPIO_DAC_SDATA LOCOMO_GPIO(10) ++#define COLLIE_LOCOMO_GPIO_DAC_SCK LOCOMO_GPIO(11) ++#define COLLIE_LOCOMO_GPIO_DAC_SLOAD LOCOMO_GPIO(12) ++#define COLLIE_GPIO_CARD_DETECT (COLLIE_LOCOMO_GPIO_BASE + 13) ++#define COLLIE_GPIO_CARD_RO (COLLIE_LOCOMO_GPIO_BASE + 14) ++#define COLLIE_GPIO_CARD_POWER (COLLIE_LOCOMO_GPIO_BASE + 15) ++ + #endif +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0015-ARM-sa1100-don-t-preallocate-IRQ-space-for-locomo.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0015-ARM-sa1100-don-t-preallocate-IRQ-space-for-locomo.patch new file mode 100644 index 0000000..40d68ee --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0015-ARM-sa1100-don-t-preallocate-IRQ-space-for-locomo.patch @@ -0,0 +1,45 @@ +From 5cbe80e1ddbaf8cb3ac4865d4eaf6b1618ff6c04 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Wed, 6 Nov 2013 01:18:03 +0400 +Subject: [PATCH 15/20] ARM: sa1100: don't preallocate IRQ space for locomo + +As new locomo driver properly supports SPARSE_IRQ, stop playing with +NR_IRQS on sa1100 (locomo was the last chip requiring NR_IRQ tricks). + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + arch/arm/mach-sa1100/include/mach/irqs.h | 19 ++----------------- + 1 file changed, 2 insertions(+), 17 deletions(-) + +diff --git a/arch/arm/mach-sa1100/include/mach/irqs.h b/arch/arm/mach-sa1100/include/mach/irqs.h +index 734e30e..b4b9608 100644 +--- a/arch/arm/mach-sa1100/include/mach/irqs.h ++++ b/arch/arm/mach-sa1100/include/mach/irqs.h +@@ -79,22 +79,7 @@ + #define IRQ_BOARD_START 61 + #define IRQ_BOARD_END 77 + +-/* +- * Figure out the MAX IRQ number. +- * +- * Neponset, SA1111 and UCB1x00 are sparse IRQ aware, so can dynamically +- * allocate their IRQs above NR_IRQS. +- * +- * LoCoMo has 4 additional IRQs, but is not sparse IRQ aware, and so has +- * to be included in the NR_IRQS calculation. +- */ +-#ifdef CONFIG_SHARP_LOCOMO +-#define NR_IRQS_LOCOMO 4 +-#else +-#define NR_IRQS_LOCOMO 0 +-#endif +- + #ifndef NR_IRQS +-#define NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO) ++#define NR_IRQS IRQ_BOARD_START + #endif +-#define SA1100_NR_IRQS (IRQ_BOARD_START + NR_IRQS_LOCOMO) ++#define SA1100_NR_IRQS IRQ_BOARD_START +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0016-ARM-pxa-poodle-use-new-LoCoMo-driver.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0016-ARM-pxa-poodle-use-new-LoCoMo-driver.patch new file mode 100644 index 0000000..355efc0 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0016-ARM-pxa-poodle-use-new-LoCoMo-driver.patch @@ -0,0 +1,174 @@ +From cbf023b8fa98ea2f1ebd116d5eef8889ba882dca Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Mon, 11 Nov 2013 04:23:00 +0400 +Subject: [PATCH 16/20] ARM: pxa: poodle: use new LoCoMo driver + +Convert poodle to use new mfd-based LoCoMo driver. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + arch/arm/mach-pxa/Kconfig | 1 - + arch/arm/mach-pxa/include/mach/poodle.h | 16 ++++++--- + arch/arm/mach-pxa/poodle.c | 58 ++++++++++++++++++++++++++++++--- + 3 files changed, 65 insertions(+), 10 deletions(-) + +diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig +index 8896e71..a2756b0 100644 +--- a/arch/arm/mach-pxa/Kconfig ++++ b/arch/arm/mach-pxa/Kconfig +@@ -481,7 +481,6 @@ config MACH_POODLE + bool "Enable Sharp SL-5600 (Poodle) Support" + depends on PXA_SHARPSL + select PXA25x +- select SHARP_LOCOMO + + config MACH_CORGI + bool "Enable Sharp SL-C700 (Corgi) Support" +diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h +index b56b193..dd4afae 100644 +--- a/arch/arm/mach-pxa/include/mach/poodle.h ++++ b/arch/arm/mach-pxa/include/mach/poodle.h +@@ -81,11 +81,17 @@ + #define POODLE_GPIO_L_LCLK (POODLE_SCOOP_GPIO_BASE + 10) + #define POODLE_GPIO_HS_OUT (POODLE_SCOOP_GPIO_BASE + 11) + +-#define POODLE_LOCOMO_GPIO_AMP_ON LOCOMO_GPIO(8) +-#define POODLE_LOCOMO_GPIO_MUTE_L LOCOMO_GPIO(10) +-#define POODLE_LOCOMO_GPIO_MUTE_R LOCOMO_GPIO(11) +-#define POODLE_LOCOMO_GPIO_232VCC_ON LOCOMO_GPIO(12) +-#define POODLE_LOCOMO_GPIO_JK_B LOCOMO_GPIO(13) ++#define POODLE_LOCOMO_GPIO_BASE (PXA_NR_BUILTIN_GPIO + 12) ++#define POODLE_GPIO_LCD_VSHA_ON (POODLE_LOCOMO_GPIO_BASE + 4) ++#define POODLE_GPIO_LCD_VSHD_ON (POODLE_LOCOMO_GPIO_BASE + 5) ++#define POODLE_GPIO_LCD_VEE_ON (POODLE_LOCOMO_GPIO_BASE + 6) ++#define POODLE_GPIO_LCD_MOD (POODLE_LOCOMO_GPIO_BASE + 7) ++#define POODLE_GPIO_AMP_ON (POODLE_LOCOMO_GPIO_BASE + 8) ++#define POODLE_GPIO_FL_VR (POODLE_LOCOMO_GPIO_BASE + 9) ++#define POODLE_GPIO_MUTE_L (POODLE_LOCOMO_GPIO_BASE + 10) ++#define POODLE_GPIO_MUTE_R (POODLE_LOCOMO_GPIO_BASE + 11) ++#define POODLE_GPIO_232VCC_ON (POODLE_LOCOMO_GPIO_BASE + 12) ++#define POODLE_GPIO_JK_B (POODLE_LOCOMO_GPIO_BASE + 13) + + #define POODLE_NR_IRQS (IRQ_BOARD_START + 4) /* 4 for LoCoMo */ + +diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c +index 195b112..6002112 100644 +--- a/arch/arm/mach-pxa/poodle.c ++++ b/arch/arm/mach-pxa/poodle.c +@@ -23,6 +23,7 @@ + #include <linux/delay.h> + #include <linux/mtd/physmap.h> + #include <linux/gpio.h> ++#include <linux/gpio/machine.h> + #include <linux/i2c.h> + #include <linux/i2c/pxa-i2c.h> + #include <linux/regulator/machine.h> +@@ -31,6 +32,8 @@ + #include <linux/spi/pxa2xx_spi.h> + #include <linux/mtd/sharpsl.h> + #include <linux/memblock.h> ++#include <linux/iio/machine.h> ++#include <linux/mfd/locomo.h> + + #include <mach/hardware.h> + #include <asm/mach-types.h> +@@ -49,7 +52,6 @@ + #include <linux/platform_data/video-pxafb.h> + + #include <asm/hardware/scoop.h> +-#include <asm/hardware/locomo.h> + #include <asm/mach/sharpsl_param.h> + + #include "generic.h" +@@ -179,7 +181,8 @@ static struct resource locomo_resources[] = { + }; + + static struct locomo_platform_data locomo_info = { +- .irq_base = IRQ_BOARD_START, ++ .gpio_base = POODLE_LOCOMO_GPIO_BASE, ++ .comadj = 118, + }; + + struct platform_device poodle_locomo_device = { +@@ -192,8 +195,6 @@ struct platform_device poodle_locomo_device = { + }, + }; + +-EXPORT_SYMBOL(poodle_locomo_device); +- + #if defined(CONFIG_SPI_PXA2XX) || defined(CONFIG_SPI_PXA2XX_MODULE) + static struct pxa2xx_spi_master poodle_spi_info = { + .num_chipselect = 1, +@@ -424,6 +425,47 @@ static struct i2c_board_info __initdata poodle_i2c_devices[] = { + { I2C_BOARD_INFO("wm8731", 0x1b) }, + }; + ++static struct iio_map locomo_iio_map[] = { ++ { ++ .consumer_dev_name = "locomo-lcd.0", ++ .consumer_channel = "comadj", ++ .adc_channel_label = "CH0", ++ }, ++ { } ++}; ++ ++static struct i2c_board_info locomo_i2c_devs[] __initdata = { ++ { ++ I2C_BOARD_INFO("m62332", 0x4e), ++ .platform_data = locomo_iio_map, ++ }, ++}; ++ ++static struct gpiod_lookup_table poodle_audio_gpios_table = { ++ .dev_id = "poodle-audio", ++ .table = { ++ GPIO_LOOKUP("locomo-gpio", 10, "mute-l", GPIO_ACTIVE_LOW), ++ GPIO_LOOKUP("locomo-gpio", 11, "mute-r", GPIO_ACTIVE_LOW), ++ GPIO_LOOKUP("locomo-gpio", 8, "amp-on", GPIO_ACTIVE_LOW), ++ { }, ++ }, ++}, poodle_bl_gpios_table = { ++ .dev_id = "locomo-backlight.0", ++ .table = { ++ GPIO_LOOKUP("locomo-gpio", 9, "flvr", GPIO_ACTIVE_HIGH), ++ { }, ++ }, ++}, poodle_lcd_gpios_table = { ++ .dev_id = "locomo-lcd.0", ++ .table = { ++ GPIO_LOOKUP("locomo-gpio", 4, "VSHA", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 5, "VSHD", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 6, "Vee", GPIO_ACTIVE_HIGH), ++ GPIO_LOOKUP("locomo-gpio", 7, "MOD", GPIO_ACTIVE_HIGH), ++ { }, ++ }, ++}; ++ + static void poodle_poweroff(void) + { + pxa_restart(REBOOT_HARD, NULL); +@@ -445,6 +487,13 @@ static void __init poodle_init(void) + + platform_scoop_config = &poodle_pcmcia_config; + ++ if (sharpsl_param.comadj != -1) ++ locomo_info.comadj = sharpsl_param.comadj; ++ ++ gpiod_add_lookup_table(&poodle_audio_gpios_table); ++ gpiod_add_lookup_table(&poodle_bl_gpios_table); ++ gpiod_add_lookup_table(&poodle_lcd_gpios_table); ++ + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + if (ret) + pr_warn("poodle: Unable to register LoCoMo device\n"); +@@ -455,6 +504,7 @@ static void __init poodle_init(void) + pxa_set_ficp_info(&poodle_ficp_platform_data); + pxa_set_i2c_info(NULL); + i2c_register_board_info(0, ARRAY_AND_SIZE(poodle_i2c_devices)); ++ i2c_register_board_info(1, ARRAY_AND_SIZE(locomo_i2c_devs)); + poodle_init_spi(); + regulator_has_full_constraints(); + } +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0017-ARM-pxa-poodle-don-t-preallocate-IRQ-space-for-locom.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0017-ARM-pxa-poodle-don-t-preallocate-IRQ-space-for-locom.patch new file mode 100644 index 0000000..dbaf549 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0017-ARM-pxa-poodle-don-t-preallocate-IRQ-space-for-locom.patch @@ -0,0 +1,30 @@ +From 9b81cda92cccc3f875a5a32e112742d81fd109d8 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Wed, 6 Nov 2013 01:21:01 +0400 +Subject: [PATCH 17/20] ARM: pxa: poodle: don't preallocate IRQ space for + locomo + +As new locomo driver supports SPARSE_IRQ, don't preallocate NR_IRQS +space for it on poodle. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + arch/arm/mach-pxa/include/mach/poodle.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/arch/arm/mach-pxa/include/mach/poodle.h b/arch/arm/mach-pxa/include/mach/poodle.h +index dd4afae..1fdde6b 100644 +--- a/arch/arm/mach-pxa/include/mach/poodle.h ++++ b/arch/arm/mach-pxa/include/mach/poodle.h +@@ -93,7 +93,7 @@ + #define POODLE_GPIO_232VCC_ON (POODLE_LOCOMO_GPIO_BASE + 12) + #define POODLE_GPIO_JK_B (POODLE_LOCOMO_GPIO_BASE + 13) + +-#define POODLE_NR_IRQS (IRQ_BOARD_START + 4) /* 4 for LoCoMo */ ++#define POODLE_NR_IRQS IRQ_BOARD_START + + extern struct platform_device poodle_locomo_device; + +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0018-ASoC-pxa-poodle-make-use-of-new-locomo-GPIO-interfac.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0018-ASoC-pxa-poodle-make-use-of-new-locomo-GPIO-interfac.patch new file mode 100644 index 0000000..3d78ec4 --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0018-ASoC-pxa-poodle-make-use-of-new-locomo-GPIO-interfac.patch @@ -0,0 +1,120 @@ +From ec10362336c5c49c14c1490600a0b6a01460cb83 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Fri, 24 Oct 2014 23:35:07 +0400 +Subject: [PATCH 18/20] ASoC: pxa: poodle: make use of new locomo GPIO + interface + +Since LoCoMo driver has been converted to provide proper gpiolib +interface, make poodle ASoC platform driver use gpiolib API. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Acked-by: Mark Brown <broonie@kernel.org> +--- + sound/soc/pxa/poodle.c | 52 +++++++++++++++++++------------------------------- + 1 file changed, 20 insertions(+), 32 deletions(-) + +diff --git a/sound/soc/pxa/poodle.c b/sound/soc/pxa/poodle.c +index 0fce8c4..c5b7c5e 100644 +--- a/sound/soc/pxa/poodle.c ++++ b/sound/soc/pxa/poodle.c +@@ -20,15 +20,11 @@ + #include <linux/i2c.h> + #include <linux/interrupt.h> + #include <linux/platform_device.h> ++#include <linux/gpio/consumer.h> + #include <sound/core.h> + #include <sound/pcm.h> + #include <sound/soc.h> + +-#include <asm/mach-types.h> +-#include <asm/hardware/locomo.h> +-#include <mach/poodle.h> +-#include <mach/audio.h> +- + #include "../codecs/wm8731.h" + #include "pxa2xx-i2s.h" + +@@ -42,22 +38,18 @@ + + static int poodle_jack_func; + static int poodle_spk_func; ++static struct gpio_desc *poodle_mute_l, *poodle_mute_r, *poodle_amp_on; + + static void poodle_ext_control(struct snd_soc_dapm_context *dapm) + { + /* set up jack connection */ + if (poodle_jack_func == POODLE_HP) { +- /* set = unmute headphone */ +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_L, 1); +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_R, 1); ++ gpiod_set_value(poodle_mute_l, 0); ++ gpiod_set_value(poodle_mute_r, 0); + snd_soc_dapm_enable_pin(dapm, "Headphone Jack"); + } else { +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_L, 0); +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_R, 0); ++ gpiod_set_value(poodle_mute_l, 1); ++ gpiod_set_value(poodle_mute_r, 1); + snd_soc_dapm_disable_pin(dapm, "Headphone Jack"); + } + +@@ -84,11 +76,8 @@ static int poodle_startup(struct snd_pcm_substream *substream) + /* we need to unmute the HP at shutdown as the mute burns power on poodle */ + static void poodle_shutdown(struct snd_pcm_substream *substream) + { +- /* set = unmute headphone */ +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_L, 1); +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_R, 1); ++ gpiod_set_value(poodle_mute_l, 0); ++ gpiod_set_value(poodle_mute_r, 0); + } + + static int poodle_hw_params(struct snd_pcm_substream *substream, +@@ -178,12 +167,7 @@ static int poodle_set_spk(struct snd_kcontrol *kcontrol, + static int poodle_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *k, int event) + { +- if (SND_SOC_DAPM_EVENT_ON(event)) +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_AMP_ON, 0); +- else +- locomo_gpio_write(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_AMP_ON, 1); ++ gpiod_set_value(poodle_amp_on, (SND_SOC_DAPM_EVENT_ON(event))); + + return 0; + } +@@ -268,13 +252,17 @@ static int poodle_probe(struct platform_device *pdev) + struct snd_soc_card *card = &poodle; + int ret; + +- locomo_gpio_set_dir(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_AMP_ON, 0); +- /* should we mute HP at startup - burning power ?*/ +- locomo_gpio_set_dir(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_L, 0); +- locomo_gpio_set_dir(&poodle_locomo_device.dev, +- POODLE_LOCOMO_GPIO_MUTE_R, 0); ++ poodle_mute_l = devm_gpiod_get(&pdev->dev, "mute-l", GPIOD_OUT_HIGH); ++ if (IS_ERR(poodle_mute_l)) ++ return PTR_ERR(poodle_mute_l); ++ ++ poodle_mute_r = devm_gpiod_get(&pdev->dev, "mute-r", GPIOD_OUT_HIGH); ++ if (IS_ERR(poodle_mute_r)) ++ return PTR_ERR(poodle_mute_l); ++ ++ poodle_amp_on = devm_gpiod_get(&pdev->dev, "amp-on", GPIOD_OUT_LOW); ++ if (IS_ERR(poodle_amp_on)) ++ return PTR_ERR(poodle_amp_on); + + card->dev = &pdev->dev; + +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0019-poodle-gpio-uart-hack.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0019-poodle-gpio-uart-hack.patch new file mode 100644 index 0000000..c42f21b --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0019-poodle-gpio-uart-hack.patch @@ -0,0 +1,26 @@ +From 8bab2ab9f758aa15ea1f97e4c11f27bcd094b4d1 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Fri, 28 Nov 2014 15:27:51 +0300 +Subject: [PATCH 19/20] poodle gpio uart hack + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + drivers/gpio/gpio-locomo.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/drivers/gpio/gpio-locomo.c b/drivers/gpio/gpio-locomo.c +index d8e5880..c8510fa 100644 +--- a/drivers/gpio/gpio-locomo.c ++++ b/drivers/gpio/gpio-locomo.c +@@ -224,7 +224,7 @@ static int locomo_gpio_probe(struct platform_device *pdev) + + platform_set_drvdata(pdev, lg); + +- regmap_write(lg->regmap, LOCOMO_GPO, 0x00); ++ regmap_write(lg->regmap, LOCOMO_GPO, 1 << 12); + regmap_write(lg->regmap, LOCOMO_GPE, 0x00); + regmap_write(lg->regmap, LOCOMO_GPD, 0x00); + regmap_write(lg->regmap, LOCOMO_GIE, 0x00); +-- +1.9.1 + diff --git a/recipes-kernel/linux/linux-handheld-4.0/locomo/0020-irq-HACK-around-for-handling-irq0-when-we-should.patch b/recipes-kernel/linux/linux-handheld-4.0/locomo/0020-irq-HACK-around-for-handling-irq0-when-we-should.patch new file mode 100644 index 0000000..afbc61b --- /dev/null +++ b/recipes-kernel/linux/linux-handheld-4.0/locomo/0020-irq-HACK-around-for-handling-irq0-when-we-should.patch @@ -0,0 +1,29 @@ +From c87b3232a374940cf5cf45242eeae2da48395799 Mon Sep 17 00:00:00 2001 +From: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +Date: Wed, 24 Dec 2014 12:27:21 +0300 +Subject: [PATCH 20/20] irq: HACK around for handling irq0 when we should + +Instead of backporting large patches changing IRQ handling on sa1100, +just make handle_domain_irq handle irq 0 as usual. + +Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> +--- + kernel/irq/irqdesc.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c +index 99793b9..06ca4e6 100644 +--- a/kernel/irq/irqdesc.c ++++ b/kernel/irq/irqdesc.c +@@ -381,7 +381,7 @@ int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq, + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ +- if (unlikely(!irq || irq >= nr_irqs)) { ++ if (unlikely(/*!irq || */irq >= nr_irqs)) { + ack_bad_irq(irq); + ret = -EINVAL; + } else { +-- +1.9.1 + |