aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/omap_hsi/hsi_driver.h
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/omap_hsi/hsi_driver.h')
-rw-r--r--drivers/omap_hsi/hsi_driver.h398
1 files changed, 398 insertions, 0 deletions
diff --git a/drivers/omap_hsi/hsi_driver.h b/drivers/omap_hsi/hsi_driver.h
new file mode 100644
index 0000000..0991d98
--- /dev/null
+++ b/drivers/omap_hsi/hsi_driver.h
@@ -0,0 +1,398 @@
+/*
+ * hsi_driver.h
+ *
+ * Header file for the HSI driver low level interface.
+ *
+ * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved.
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Author: Carlos Chinea <carlos.chinea@nokia.com>
+ * Author: Sebastien JAN <s-jan@ti.com>
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef __HSI_DRIVER_H__
+#define __HSI_DRIVER_H__
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/spinlock.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/gpio.h>
+#include <linux/notifier.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/pm_runtime.h>
+
+#include <linux/hsi_driver_if.h>
+#include <plat/omap_hsi.h>
+
+/* Channel states */
+#define HSI_CH_OPEN 0x01
+#define HSI_CH_RX_POLL 0x10
+#define HSI_CH_ACWAKE 0x02 /* ACWAKE line status */
+
+#define HSI_CH_NUMBER_NONE 0xFF
+/*
+ * The number of channels handled by the driver in the ports, or the highest
+ * port channel number (+1) used. (MAX:8 for SSI; 16 for HSI)
+ * Reducing this value optimizes the driver memory footprint.
+ */
+#define HSI_PORT_MAX_CH HSI_CHANNELS_MAX
+
+/* Number of DMA channels when nothing is defined for the device */
+#define HSI_DMA_CHANNEL_DEFAULT 8
+
+
+#define LOG_NAME "OMAP HSI: "
+
+/* SW strategies for HSI FIFO mapping */
+enum {
+ HSI_FIFO_MAPPING_UNDEF = 0,
+ HSI_FIFO_MAPPING_SSI, /* 8 FIFOs per port (SSI compatible mode) */
+ HSI_FIFO_MAPPING_ALL_PORT1, /* ALL FIFOs mapped on 1st port */
+};
+#define HSI_FIFO_MAPPING_DEFAULT HSI_FIFO_MAPPING_ALL_PORT1
+
+/* Device identifying constants */
+enum {
+ HSI_DRV_DEVICE_HSI,
+ HSI_DRV_DEVICE_SSI
+};
+
+/**
+ * struct hsi_data - HSI buffer descriptor
+ * @addr: pointer to the buffer where to send or receive data
+ * @size: size in words (32 bits) of the buffer
+ * @lch: associated GDD (DMA) logical channel number, if any
+ */
+struct hsi_data {
+ u32 *addr;
+ unsigned int size;
+ int lch;
+};
+
+/**
+ * struct hsi_channel - HSI channel data
+ * @read_data: Incoming HSI buffer descriptor
+ * @write_data: Outgoing HSI buffer descriptor
+ * @hsi_port: Reference to port where the channel belongs to
+ * @flags: Tracks if channel has been open
+ * @channel_number: HSI channel number
+ * @rw_lock: Read/Write lock to serialize access to callback and hsi_device
+ * @dev: Reference to the associated hsi_device channel
+ * @write_done: Callback to signal TX completed.
+ * @read_done: Callback to signal RX completed.
+ * @port_event: Callback to signal port events (RX Error, HWBREAK, CAWAKE ...)
+ */
+struct hsi_channel {
+ struct hsi_data read_data;
+ struct hsi_data write_data;
+ struct hsi_port *hsi_port;
+ u8 flags;
+ u8 channel_number;
+ rwlock_t rw_lock;
+ struct hsi_device *dev;
+ void (*write_done) (struct hsi_device *dev, unsigned int size);
+ void (*read_done) (struct hsi_device *dev, unsigned int size);
+ void (*port_event) (struct hsi_device *dev, unsigned int event,
+ void *arg);
+};
+
+/**
+ * struct hsi_port - hsi port driver data
+ * @hsi_channel: Array of channels in the port
+ * @hsi_controller: Reference to the HSI controller
+ * @port_number: port number
+ * @max_ch: maximum number of channels supported on the port
+ * @n_irq: HSI irq line use to handle interrupts (0 or 1)
+ * @irq: IRQ number
+ * @cawake_gpio: GPIO number for cawake line (-1 if none)
+ * @cawake_gpio_irq: IRQ number for cawake gpio events
+ * @cawake_status: Tracks CAWAKE line status
+ * @cawake_off_event: True if CAWAKE event was detected from OFF mode
+ * @acwake_status: Bitmap to track ACWAKE line status per channel
+ * @in_int_tasklet: True if interrupt tasklet for this port is currently running
+ * @in_cawake_tasklet: True if CAWAKE tasklet for this port is currently running
+ * @counters_on: indicates if the HSR counters are in use or not
+ * @reg_counters: stores the previous counters values when deactivated
+ * @lock: Serialize access to the port registers and internal data
+ * @hsi_tasklet: Bottom half for interrupts when clocks are enabled
+ * @cawake_tasklet: Bottom half for cawake events
+ */
+struct hsi_port {
+ struct hsi_channel hsi_channel[HSI_PORT_MAX_CH];
+ struct hsi_dev *hsi_controller;
+ u8 flags;
+ u8 port_number; /* Range [1,2] */
+ u8 max_ch;
+ u8 n_irq;
+ int irq;
+ int cawake_gpio;
+ int cawake_gpio_irq;
+ int cawake_status;
+ bool cawake_off_event;
+ unsigned int acwake_status; /* HSI_TODO : fine tune init values */
+ bool in_int_tasklet;
+ bool in_cawake_tasklet;
+ int counters_on;
+ unsigned long reg_counters;
+ spinlock_t lock; /* access to the port registers and internal data */
+ struct tasklet_struct hsi_tasklet;
+ struct tasklet_struct cawake_tasklet; /* SSI_TODO : need to replace */
+ /* by a workqueue */
+};
+
+/**
+ * struct hsi_dev - hsi controller driver data
+ * This structure is saved into platform_device->dev->p->driver_data
+ *
+ * @hsi_port: Array of hsi ports enabled in the controller
+ * @id: HSI controller platform id number
+ * @max_p: Number of ports enabled in the controller
+ * @hsi_clk: Reference to the HSI custom clock
+ * @base: HSI registers base virtual address
+ * @phy_base: HSI registers base physical address
+ * @lock: Serializes access to internal data and regs
+ * @clock_enabled: Indicates if HSI Clocks are ON
+ * @gdd_irq: GDD (DMA) irq number
+ * @fifo_mapping_strategy: Selected strategy for fifo to ports/channels mapping
+ * @gdd_usecount: Holds the number of ongoning DMA transfers
+ * @last_gdd_lch: Last used GDD logical channel
+ * @gdd_chan_count: Number of available DMA channels on the device (must be ^2)
+ * @in_dma_tasklet: True if DMA tasklet for the controller is currently running
+ * @set_min_bus_tput: (PM) callback to set minimun bus throuput
+ * @clk_notifier_register: (PM) callabck for DVFS support
+ * @clk_notifier_unregister: (PM) callabck for DVFS support
+ * @hsi_nb: (PM) Notification block for DVFS notification chain
+ * @hsi_gdd_tasklet: Bottom half for DMA Interrupts when clocks are enabled
+ * @dir: debugfs base directory
+ * @dev: Reference to the HSI platform device
+ */
+struct hsi_dev { /* HSI_TODO: should be later renamed into hsi_controller*/
+ struct hsi_port hsi_port[HSI_MAX_PORTS];
+ int id;
+ u8 max_p;
+ void __iomem *base;
+ unsigned long phy_base;
+ spinlock_t lock; /* Serializes access to internal data and regs */
+ bool clock_enabled;
+ int gdd_irq;
+ unsigned int fifo_mapping_strategy;
+ unsigned int gdd_usecount;
+ unsigned int last_gdd_lch;
+ unsigned int gdd_chan_count;
+ bool in_dma_tasklet;
+ void (*set_min_bus_tput) (struct device *dev, u8 agent_id,
+ unsigned long r);
+ struct notifier_block hsi_nb;
+ struct tasklet_struct hsi_gdd_tasklet;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dir;
+#endif
+ struct device *dev;
+};
+
+/**
+ * struct hsi_platform_data - Board specific data
+*/
+struct hsi_platform_data {
+ void (*set_min_bus_tput) (struct device *dev, u8 agent_id,
+ unsigned long r);
+ int (*device_enable) (struct platform_device *pdev);
+ int (*device_shutdown) (struct platform_device *pdev);
+ int (*device_idle) (struct platform_device *pdev);
+ int (*wakeup_enable) (int hsi_port);
+ int (*wakeup_disable) (int hsi_port);
+ int (*wakeup_is_from_hsi) (void);
+ int (*board_suspend)(int hsi_port, bool dev_may_wakeup);
+ int (*board_resume)(int hsi_port);
+ u8 num_ports;
+ struct ctrl_ctx *ctx;
+ u8 hsi_gdd_chan_count;
+ unsigned long default_hsi_fclk;
+};
+
+/* HSI Bus */
+extern struct bus_type hsi_bus_type;
+
+int hsi_port_event_handler(struct hsi_port *p, unsigned int event, void *arg);
+int hsi_bus_init(void);
+void hsi_bus_exit(void);
+/* End HSI Bus */
+
+void hsi_reset_ch_read(struct hsi_channel *ch);
+void hsi_reset_ch_write(struct hsi_channel *ch);
+bool hsi_is_channel_busy(struct hsi_channel *ch);
+bool hsi_is_hsi_port_busy(struct hsi_port *pport);
+bool hsi_is_hsi_controller_busy(struct hsi_dev *hsi_ctrl);
+bool hsi_is_hst_port_busy(struct hsi_port *pport);
+bool hsi_is_hst_controller_busy(struct hsi_dev *hsi_ctrl);
+
+int hsi_driver_enable_interrupt(struct hsi_port *pport, u32 flag);
+int hsi_driver_enable_read_interrupt(struct hsi_channel *hsi_channel,
+ u32 *data);
+int hsi_driver_enable_write_interrupt(struct hsi_channel *hsi_channel,
+ u32 *data);
+bool hsi_is_dma_read_int_pending(struct hsi_dev *hsi_ctrl);
+int hsi_driver_read_dma(struct hsi_channel *hsi_channel, u32 * data,
+ unsigned int count);
+int hsi_driver_write_dma(struct hsi_channel *hsi_channel, u32 * data,
+ unsigned int count);
+
+int hsi_driver_cancel_read_interrupt(struct hsi_channel *ch);
+int hsi_driver_cancel_write_interrupt(struct hsi_channel *ch);
+void hsi_driver_disable_read_interrupt(struct hsi_channel *ch);
+void hsi_driver_disable_write_interrupt(struct hsi_channel *ch);
+int hsi_driver_cancel_write_dma(struct hsi_channel *ch);
+int hsi_driver_cancel_read_dma(struct hsi_channel *ch);
+int hsi_do_cawake_process(struct hsi_port *pport);
+
+int hsi_driver_device_is_hsi(struct platform_device *dev);
+
+int hsi_mpu_init(struct hsi_port *hsi_p, const char *irq_name);
+void hsi_mpu_exit(struct hsi_port *hsi_p);
+
+int hsi_gdd_init(struct hsi_dev *hsi_ctrl, const char *irq_name);
+void hsi_gdd_exit(struct hsi_dev *hsi_ctrl);
+
+int hsi_cawake_init(struct hsi_port *port, const char *irq_name);
+void hsi_cawake_exit(struct hsi_port *port);
+
+int hsi_fifo_get_id(struct hsi_dev *hsi_ctrl, unsigned int channel,
+ unsigned int port);
+int hsi_fifo_get_chan(struct hsi_dev *hsi_ctrl, unsigned int fifo,
+ unsigned int *channel, unsigned int *port);
+int hsi_fifo_mapping(struct hsi_dev *hsi_ctrl, unsigned int mtype);
+long hsi_hst_bufstate_f_reg(struct hsi_dev *hsi_ctrl,
+ unsigned int port, unsigned int channel);
+long hsi_hsr_bufstate_f_reg(struct hsi_dev *hsi_ctrl,
+ unsigned int port, unsigned int channel);
+long hsi_hst_buffer_reg(struct hsi_dev *hsi_ctrl,
+ unsigned int port, unsigned int channel);
+long hsi_hsr_buffer_reg(struct hsi_dev *hsi_ctrl,
+ unsigned int port, unsigned int channel);
+u8 hsi_get_rx_fifo_occupancy(struct hsi_dev *hsi_ctrl, u8 fifo);
+void hsi_set_pm_force_hsi_on(struct hsi_dev *hsi_ctrl);
+void hsi_set_pm_default(struct hsi_dev *hsi_ctrl);
+int hsi_softreset(struct hsi_dev *hsi_ctrl);
+void hsi_softreset_driver(struct hsi_dev *hsi_ctrl);
+
+void hsi_clocks_disable_channel(struct device *dev, u8 channel_number,
+ const char *s);
+int hsi_clocks_enable_channel(struct device *dev, u8 channel_number,
+ const char *s);
+#ifdef CONFIG_PM_RUNTIME
+extern int hsi_runtime_resume(struct device *dev);
+extern int hsi_runtime_suspend(struct device *dev);
+#else
+static inline int hsi_runtime_resume(struct device *dev) { return -ENOSYS; }
+static inline int hsi_runtime_suspend(struct device *dev) { return -ENOSYS; }
+#endif
+void hsi_save_ctx(struct hsi_dev *hsi_ctrl);
+void hsi_restore_ctx(struct hsi_dev *hsi_ctrl);
+
+
+#ifdef CONFIG_DEBUG_FS
+int hsi_debug_init(void);
+void hsi_debug_exit(void);
+int hsi_debug_add_ctrl(struct hsi_dev *hsi_ctrl);
+void hsi_debug_remove_ctrl(struct hsi_dev *hsi_ctrl);
+#else
+#define hsi_debug_add_ctrl(hsi_ctrl) 0
+#define hsi_debug_remove_ctrl(hsi_ctrl)
+#define hsi_debug_init() 0
+#define hsi_debug_exit()
+#endif /* CONFIG_DEBUG_FS */
+
+static inline struct hsi_channel *hsi_ctrl_get_ch(struct hsi_dev *hsi_ctrl,
+ unsigned int port,
+ unsigned int channel)
+{
+ return &hsi_ctrl->hsi_port[port - 1].hsi_channel[channel];
+}
+
+/* HSI IO access */
+static inline u32 hsi_inl(void __iomem *base, u32 offset)
+{
+ return inl((unsigned int)base + offset);
+}
+
+static inline void hsi_outl(u32 data, void __iomem *base, u32 offset)
+{
+ outl(data, (unsigned int)base + offset);
+}
+
+static inline void hsi_outl_or(u32 data, void __iomem *base, u32 offset)
+{
+ u32 tmp = hsi_inl(base, offset);
+ hsi_outl((tmp | data), base, offset);
+}
+
+static inline void hsi_outl_and(u32 data, void __iomem *base, u32 offset)
+{
+ u32 tmp = hsi_inl(base, offset);
+ hsi_outl((tmp & data), base, offset);
+}
+
+static inline u16 hsi_inw(void __iomem *base, u32 offset)
+{
+ return inw((unsigned int)base + offset);
+}
+
+static inline void hsi_outw(u16 data, void __iomem *base, u32 offset)
+{
+ outw(data, (unsigned int)base + offset);
+}
+
+static inline void hsi_outw_or(u16 data, void __iomem *base, u32 offset)
+{
+ u16 tmp = hsi_inw(base, offset);
+ hsi_outw((tmp | data), base, offset);
+}
+
+static inline void hsi_outw_and(u16 data, void __iomem *base, u32 offset)
+{
+ u16 tmp = hsi_inw(base, offset);
+ hsi_outw((tmp & data), base, offset);
+}
+
+static inline int hsi_get_cawake(struct hsi_port *port)
+{
+ struct platform_device *pdev =
+ to_platform_device(port->hsi_controller->dev);
+
+ if (hsi_driver_device_is_hsi(pdev))
+ return (HSI_HSR_MODE_WAKE_STATUS ==
+ (hsi_inl(port->hsi_controller->base,
+ HSI_HSR_MODE_REG(port->port_number)) &
+ HSI_HSR_MODE_WAKE_STATUS));
+ else if (port->cawake_gpio >= 0)
+ return gpio_get_value(port->cawake_gpio);
+ else
+ return -ENXIO;
+}
+
+static inline void hsi_clocks_disable(struct device *dev, const char *s)
+{
+ hsi_clocks_disable_channel(dev, HSI_CH_NUMBER_NONE, s);
+}
+
+static inline int hsi_clocks_enable(struct device *dev, const char *s)
+{
+ return hsi_clocks_enable_channel(dev, HSI_CH_NUMBER_NONE, s);
+}
+
+#endif /* __HSI_DRIVER_H__ */