BigW Consortium Gitlab

Commit 33b7040e by David Frey

Introduce IoT slot kernel driver

The IoT slot driver provides a more modular replacement for the mangoh driver which is part of the legato framework. The idea is to separate out the installation of various sensor devices and the IoT card framework.
parent a1d14f8f
sources: sources:
{ {
mangoh_iot.c iot-slot-core.c
green.c iot-slot-eeprom.c
eeprom.c
} }
params: params:
{ {
model = "green"
} }
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
*/ */
#ifndef MANGOH_IOT_EEPROM_1V0_H #ifndef IOT_SLOT_EEPROM_1V0_H
#define MANGOH_IOT_EEPROM_1V0_H #define IOT_SLOT_EEPROM_1V0_H
typedef struct eeprom_if_reserved_ { typedef struct eeprom_if_reserved_ {
char reserved[63]; char reserved[63];
...@@ -66,4 +66,4 @@ typedef struct eeprom_if_1v0_ { ...@@ -66,4 +66,4 @@ typedef struct eeprom_if_1v0_ {
#define EEPROM_1V0_INTERFACE_OFFSET 192 #define EEPROM_1V0_INTERFACE_OFFSET 192
#endif /* MANGOH_IOT_EEPROM_1V0_H */ #endif /* IOT_SLOT_EEPROM_1V0_H */
...@@ -55,8 +55,8 @@ ...@@ -55,8 +55,8 @@
#include <linux/gpio/driver.h> #include <linux/gpio/driver.h>
#include <linux/platform_data/at24.h> #include <linux/platform_data/at24.h>
#include "eeprom.h" #include "iot-slot-eeprom.h"
#include "eeprom_1v0.h" #include "iot-slot-eeprom-1v0.h"
#define HOST_UINT8(buffer, offset) (*(uint8_t*)(&(buffer)[(offset)])) #define HOST_UINT8(buffer, offset) (*(uint8_t*)(&(buffer)[(offset)]))
#define HOST_UINT16(buffer, offset) ntohs(*(uint16_t*)(&(buffer)[(offset)])) #define HOST_UINT16(buffer, offset) ntohs(*(uint16_t*)(&(buffer)[(offset)]))
...@@ -66,22 +66,6 @@ ...@@ -66,22 +66,6 @@
#define EEPROM_VERSION_MAJOR(version) (((version) & 0xff00) >> 8) #define EEPROM_VERSION_MAJOR(version) (((version) & 0xff00) >> 8)
#define EEPROM_VERSION_MINOR(version) ((version) & 0xff) #define EEPROM_VERSION_MINOR(version) ((version) & 0xff)
typedef enum eeprom_if_t_ {
eeprom_if_gpio = 0,
eeprom_if_i2c = 1,
eeprom_if_spi = 2,
eeprom_if_usb = 3,
eeprom_if_sdio = 4,
eeprom_if_adc = 5,
eeprom_if_pcm = 6,
eeprom_if_clk = 7,
eeprom_if_uart = 8,
eeprom_if_plat = 9,
/* add more interface types here */
eeprom_if_last_supported,
eeprom_if_last = 0xff
} eeprom_if_t;
#define IOT_EEPROM_SIZE 4096 #define IOT_EEPROM_SIZE 4096
/* /*
* Map in which EEPROM contents are read. This is global so make sure * Map in which EEPROM contents are read. This is global so make sure
...@@ -165,7 +149,7 @@ static void *eeprom_if_first(struct i2c_client *eeprom) ...@@ -165,7 +149,7 @@ static void *eeprom_if_first(struct i2c_client *eeprom)
uint8_t *buffer = to_eeprom_buffer(eeprom); uint8_t *buffer = to_eeprom_buffer(eeprom);
eeprom_if_1v0 *ifc = eeprom_if_1v0 *ifc =
(eeprom_if_1v0*)&buffer[EEPROM_1V0_INTERFACE_OFFSET]; (eeprom_if_1v0*)&buffer[EEPROM_1V0_INTERFACE_OFFSET];
return (eeprom_if_last == ifc->type ? NULL : ifc); return (ifc->type == EEPROM_IF_LAST ? NULL : ifc);
} }
default: default:
BUG(); BUG();
...@@ -178,7 +162,7 @@ static void *eeprom_if_next(struct i2c_client *eeprom, void *prev) ...@@ -178,7 +162,7 @@ static void *eeprom_if_next(struct i2c_client *eeprom, void *prev)
switch (eeprom_version(eeprom)) { switch (eeprom_version(eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *ifc = (eeprom_if_1v0*)prev; eeprom_if_1v0 *ifc = (eeprom_if_1v0*)prev;
return (eeprom_if_last == ifc->type ? NULL : ++ifc); return (ifc->type == EEPROM_IF_LAST ? NULL : ++ifc);
} }
default: default:
BUG(); BUG();
...@@ -219,18 +203,19 @@ static int eeprom_load_interfaces(struct i2c_client *eeprom) ...@@ -219,18 +203,19 @@ static int eeprom_load_interfaces(struct i2c_client *eeprom)
} }
/* Public functions */ /* Public functions */
struct i2c_client *eeprom_load(int slot) struct i2c_client *eeprom_load(struct i2c_adapter *i2c_adapter)
{ {
struct i2c_adapter *adapter;
struct i2c_client *eeprom; struct i2c_client *eeprom;
adapter = i2c_get_adapter(1 + slot); if (!i2c_adapter)
if (!adapter)
return NULL; return NULL;
/* This automatically runs the setup() function */ /* This automatically runs the setup() function */
eeprom = i2c_new_device(adapter, &at24_eeprom_info); eeprom = i2c_new_device(i2c_adapter, &at24_eeprom_info);
i2c_put_adapter(adapter);
/* If no eeprom is detected, return NULL */
if (eeprom == NULL)
return NULL;
/* Validate EEPROM header */ /* Validate EEPROM header */
if (!to_eeprom_buffer(eeprom)) { if (!to_eeprom_buffer(eeprom)) {
...@@ -256,44 +241,39 @@ int eeprom_num_slots(struct i2c_client *eeprom) ...@@ -256,44 +241,39 @@ int eeprom_num_slots(struct i2c_client *eeprom)
return 1; /* for now */ return 1; /* for now */
} }
#define __DECLARE_IS_IF(bus) \
__DECLARE_IS_IF_PROTOTYPE(bus, i) { \
struct eeprom_if_map *m = to_eeprom_if_map(i); \
struct i2c_client *eeprom = m->eeprom; \
switch (eeprom_version(eeprom)) { \
case EEPROM_VERSION(1, 0): { \
eeprom_if_1v0 *i = (eeprom_if_1v0*)m->contents; \
return (eeprom_if_##bus == i->type); \
} \
default: \
BUG(); \
return 0; \
} \
}
__DECLARE_IS_IF(gpio)
__DECLARE_IS_IF(i2c)
__DECLARE_IS_IF(spi)
__DECLARE_IS_IF(usb)
__DECLARE_IS_IF(sdio)
__DECLARE_IS_IF(adc)
__DECLARE_IS_IF(pcm)
__DECLARE_IS_IF(clk)
__DECLARE_IS_IF(uart)
__DECLARE_IS_IF(plat)
struct list_head *eeprom_if_list(struct i2c_client *eeprom) struct list_head *eeprom_if_list(struct i2c_client *eeprom)
{ {
return to_eeprom_if_list(eeprom); return to_eeprom_if_list(eeprom);
} }
enum EepromInterface eeprom_if_type(struct list_head *item)
{
enum EepromInterface result;
struct eeprom_if_map *m = to_eeprom_if_map(item);
switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0):
{
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
result = eif->type;
break;
}
default:
BUG();
result = EEPROM_IF_LAST;
break;
}
return result;
}
uint8_t eeprom_if_gpio_cfg(struct list_head *item, unsigned int pin) uint8_t eeprom_if_gpio_cfg(struct list_head *item, unsigned int pin)
{ {
struct eeprom_if_map *m = to_eeprom_if_map(item); struct eeprom_if_map *m = to_eeprom_if_map(item);
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_gpio != eif->type); BUG_ON(eif->type != EEPROM_IF_GPIO);
BUG_ON(pin >= ARRAY_SIZE(eif->ifc.gpio.cfg)); BUG_ON(pin >= ARRAY_SIZE(eif->ifc.gpio.cfg));
return eif->ifc.gpio.cfg[pin]; return eif->ifc.gpio.cfg[pin];
} }
...@@ -309,7 +289,7 @@ char *eeprom_if_spi_modalias(struct list_head *item) ...@@ -309,7 +289,7 @@ char *eeprom_if_spi_modalias(struct list_head *item)
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_spi != eif->type); BUG_ON(eif->type != EEPROM_IF_SPI);
return (eif->ifc.spi.modalias); return (eif->ifc.spi.modalias);
} }
default: default:
...@@ -325,7 +305,7 @@ int eeprom_if_spi_irq_gpio(struct list_head *item) ...@@ -325,7 +305,7 @@ int eeprom_if_spi_irq_gpio(struct list_head *item)
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_spi != eif->type); BUG_ON(eif->type != EEPROM_IF_SPI);
return eif->ifc.spi.irq_gpio; return eif->ifc.spi.irq_gpio;
} }
default: default:
...@@ -341,7 +321,7 @@ char *eeprom_if_i2c_modalias(struct list_head *item) ...@@ -341,7 +321,7 @@ char *eeprom_if_i2c_modalias(struct list_head *item)
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_i2c != eif->type); BUG_ON(eif->type != EEPROM_IF_I2C);
return (eif->ifc.i2c.modalias); return (eif->ifc.i2c.modalias);
} }
default: default:
...@@ -357,7 +337,7 @@ int eeprom_if_i2c_irq_gpio(struct list_head *item) ...@@ -357,7 +337,7 @@ int eeprom_if_i2c_irq_gpio(struct list_head *item)
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_i2c != eif->type); BUG_ON(eif->type != EEPROM_IF_I2C);
return eif->ifc.i2c.irq_gpio; return eif->ifc.i2c.irq_gpio;
} }
default: default:
...@@ -373,7 +353,7 @@ uint8_t eeprom_if_i2c_address(struct list_head *item) ...@@ -373,7 +353,7 @@ uint8_t eeprom_if_i2c_address(struct list_head *item)
switch (eeprom_version(m->eeprom)) { switch (eeprom_version(m->eeprom)) {
case EEPROM_VERSION(1, 0): { case EEPROM_VERSION(1, 0): {
eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents; eeprom_if_1v0 *eif = (eeprom_if_1v0*)m->contents;
BUG_ON(eeprom_if_i2c != eif->type); BUG_ON(eif->type != EEPROM_IF_I2C);
return (eif->ifc.i2c.address); return (eif->ifc.i2c.address);
} }
default: default:
......
...@@ -10,8 +10,8 @@ ...@@ -10,8 +10,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
* *
*/ */
#ifndef MANGOH_IOT_EEPROM_H #ifndef IOT_SLOT_EEPROM_H
#define MANGOH_IOT_EEPROM_H #define IOT_SLOT_EEPROM_H
#include <linux/i2c.h> #include <linux/i2c.h>
...@@ -24,29 +24,36 @@ ...@@ -24,29 +24,36 @@
#define EEPROM_GPIO_CFG_OUTPUT_LOW (0x4) #define EEPROM_GPIO_CFG_OUTPUT_LOW (0x4)
#define EEPROM_GPIO_CFG_OUTPUT_HIGH (0x5) #define EEPROM_GPIO_CFG_OUTPUT_HIGH (0x5)
struct i2c_client *eeprom_load(int slot); enum EepromInterface
{
EEPROM_IF_GPIO,
EEPROM_IF_I2C,
EEPROM_IF_SPI,
EEPROM_IF_USB,
EEPROM_IF_SDIO,
EEPROM_IF_ADC,
EEPROM_IF_PCM,
EEPROM_IF_CLK,
EEPROM_IF_UART,
EEPROM_IF_PLAT,
/* add more interface types here */
EEPROM_IF_LAST_SUPPORTED,
EEPROM_IF_LAST = 0xFF,
};
struct i2c_client *eeprom_load(struct i2c_adapter *i2c_adapter);
void eeprom_unload(struct i2c_client *eeprom); void eeprom_unload(struct i2c_client *eeprom);
struct list_head *eeprom_if_list(struct i2c_client *eeprom); struct list_head *eeprom_if_list(struct i2c_client *eeprom);
int eeprom_num_slots(struct i2c_client *eeprom); int eeprom_num_slots(struct i2c_client *eeprom);
#define __DECLARE_IS_IF_PROTOTYPE(bus, ifc) \
bool eeprom_is_if_##bus(struct list_head *ifc)
__DECLARE_IS_IF_PROTOTYPE(gpio, ifc);
__DECLARE_IS_IF_PROTOTYPE(i2c, ifc);
__DECLARE_IS_IF_PROTOTYPE(spi, ifc);
__DECLARE_IS_IF_PROTOTYPE(usb, ifc);
__DECLARE_IS_IF_PROTOTYPE(sdio, ifc);
__DECLARE_IS_IF_PROTOTYPE(adc, ifc);
__DECLARE_IS_IF_PROTOTYPE(pcm, ifc);
__DECLARE_IS_IF_PROTOTYPE(clk, ifc);
__DECLARE_IS_IF_PROTOTYPE(uart, ifc);
__DECLARE_IS_IF_PROTOTYPE(plat, ifc);
enum EepromInterface eeprom_if_type(struct list_head *item);
uint8_t eeprom_if_gpio_cfg(struct list_head *item, unsigned int pin); uint8_t eeprom_if_gpio_cfg(struct list_head *item, unsigned int pin);
char *eeprom_if_spi_modalias(struct list_head *item); char *eeprom_if_spi_modalias(struct list_head *item);
int eeprom_if_spi_irq_gpio(struct list_head *item); int eeprom_if_spi_irq_gpio(struct list_head *item);
char *eeprom_if_i2c_modalias(struct list_head *item); char *eeprom_if_i2c_modalias(struct list_head *item);
int eeprom_if_i2c_irq_gpio(struct list_head *item); int eeprom_if_i2c_irq_gpio(struct list_head *item);
uint8_t eeprom_if_i2c_address(struct list_head *item); uint8_t eeprom_if_i2c_address(struct list_head *item);
#endif /* MANGOH_IOT_EEPROM_H */
#endif /* IOT_SLOT_EEPROM_H */
#ifndef IOT_SLOT_H
#define IOT_SLOT_H
struct spi_master;
struct i2c_adapter;
/*
* TODO:
* Need to decide whether an absent function pointer means that no action is
* needed to acquire the interface or that the interface is not supported on the
* IoT slot. I think not supported makes more sense unless we separate out
* muxing from getting. Eg. have a require_x, get_x, release_x functions.
*/
struct iot_slot_platform_data {
int gpio[4];
int reset_gpio;
int card_detect_gpio;
int (*request_i2c)(struct i2c_adapter **adapter);
int (*release_i2c)(struct i2c_adapter **adapter);
int (*request_spi)(struct spi_master **spi_master, int *cs);
int (*release_spi)(void);
/* TODO: what output param(s) for uart? */
int (*request_uart)(void);
int (*release_uart)(void);
/* TODO: how are adc's managed in the kernel? */
int (*request_adc)(void);
int (*release_adc)(void);
/* TODO: output params? */
int (*request_sdio)(void);
int (*release_sdio)(void);
/* TODO: output params? */
int (*request_pcm)(void);
int (*release_pcm)(void);
};
#endif /* IOT_SLOT_H */
/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
#ifndef MANGOH_IOT_MANGOH_H
#define MANGOH_IOT_MANGOH_H
#include <linux/platform_device.h>
#include <linux/i2c.h>
#include <linux/spi/spi.h>
typedef enum {
mangoh_bus_i2c,
mangoh_bus_spi,
mangoh_bus_uart,
mangoh_bus_sdio,
mangoh_bus_usb,
mangoh_bus_gpio,
mangoh_bus_pcm,
mangoh_bus_adc,
mangoh_bus_last,
} mangoh_bus_t;
struct mangoh_desc {
char *type;
int (*map)(struct platform_device *pdev);
int (*unmap)(struct platform_device *pdev);
};
extern struct mangoh_desc mangoh_green_desc;
extern struct platform_device mangoh_green;
#endif /* MANGOH_IOT_MANGOH_H */
/* Copyright (c) 2009-2012, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* 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.
*
*/
/*
* IoT expansion platform driver for Sierra Wireless MangOH board(s).
* Currently supporting only MangOH green platform.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include "mangoh.h"
static char *model = "green";
module_param(model, charp, S_IRUGO);
MODULE_PARM_DESC(model, "MangOH board model.");
static const struct platform_device_id mangoh_iot_ids[] = {
{"mangoh-green", (kernel_ulong_t)&mangoh_green_desc},
{},
};
MODULE_DEVICE_TABLE(platform, mangoh_iot_ids);
static int mangoh_iot_probe(struct platform_device *pdev)
{
struct mangoh_desc *desc;
desc = (struct mangoh_desc *)platform_get_device_id(pdev)->driver_data;
if (!desc || !desc->map)
return -ENODEV;
platform_set_drvdata(pdev, desc);
return desc->map(pdev);
}
static int mangoh_iot_remove(struct platform_device *pdev)
{
struct mangoh_desc *desc = platform_get_drvdata(pdev);
if (desc && desc->unmap)
desc->unmap(pdev);
/* desc will be freed with device removal, so we're done */
dev_info(&pdev->dev, "Removed.\n");
return 0;
}
static struct platform_driver mangoh_iot_driver = {
.probe = mangoh_iot_probe,
.remove = mangoh_iot_remove,
.driver = {
.name = "mangoh-iot",
.owner = THIS_MODULE,
.bus = &platform_bus_type,
},
.id_table = mangoh_iot_ids,
};
static int __init mangoh_iot_init(void)
{
struct platform_device *pdev;
if (!strcasecmp(model, "green"))
pdev = &mangoh_green;
else
pdev = NULL;
if (!pdev) {
pr_err("%s: unknown model 'mangoh-%s'.\n", __func__, model);
return -ENODEV;
}
platform_driver_register(&mangoh_iot_driver);
if (platform_device_register(pdev)) {
platform_driver_unregister(&mangoh_iot_driver);
return -ENODEV;
}
return 0;
}
static void __exit mangoh_iot_exit(void)
{
platform_device_unregister(&mangoh_green);
platform_driver_unregister(&mangoh_iot_driver);
}
module_init(mangoh_iot_init);
module_exit(mangoh_iot_exit);
MODULE_ALIAS("platform:mangoh-iot");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sierra Wireless");
MODULE_DESCRIPTION("Linux driver for MangOH IoT expander");
MODULE_VERSION("0.1");
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment