I have an i2c device (touch controller). Usually I would add it to the .dts file like this when it is connected to the SoC i2c master (a tegra chip in my case):
i2c#7000c000 {
st1332: touchscreen#55 {
compatible = "sitronix,st1232";
reg = <0x55>;
interrupt-parent = <&gpio>;
interrupts = <189 IRQ_TYPE_EDGE_FALLING>;
};
};
With the i2c controler i2c#7000c000 being defined in the SoC's .dtsi file:
i2c1: i2c#7000c000 {
#address-cells = <1>;
#size-cells = <0>;
compatible = "nvidia,tegra124-i2c";
reg = <0x0 0x7000c000 0x0 0x100>;
interrupts = <0 38 0x04>;
scl-gpio = <&gpio 20 0>; /* gpio PC4 */
sda-gpio = <&gpio 21 0>; /* gpio PC5 */
nvidia,memory-clients = <14>;
status = "okay";
clock-frequency = <400000>;
};
However, I don't want to connect the touch controller to one of the i2c masters from the SoC. Instead I have it connected to a cp2112 USB to i2c bridge.
The cp2112 driver works fine: I can use commands such as i2cget to access it from the command line. But how do I add it to the .dts file so that the touch controller driver will talk to it?
Because USB devices are enumerated automatically, I don't have a node in my .dts file that I can use as parent for the touch controller node. I would assume that I need to create a placeholder node in the .dts file under the usb controller (xusb#70090000 in my case), that is then associated with the enumerated USB device by the kernel, and move the touch controller into this node, but I don't know how to do that. What would such a node for a USB device look like? Or is there a completely different solution to the problem?
I am running Linux 3.10.40 with a backported version of hid-cp2112 from Linux v4.1.0-rc5.
As the hid-cp2112 driver is probed by the USB device enumeration, it does not even try to find itself in the device tree. I have created the following patch to hid-cp2112.c that links the found cp2112 device to a /i2c#cp2112 node in the devie tree. (This of course only works for situations where there is only one cp2112 chip on the USB.)
diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c
index 2bd7f97..fa88590 100644
--- a/drivers/hid/hid-cp2112.c
+++ b/drivers/hid/hid-cp2112.c
## -31,6 +31,8 ##
#include <linux/module.h>
#include <linux/nls.h>
#include <linux/usb/ch9.h>
+#include <linux/of.h>
+#include <linux/of_i2c.h>
#include "hid-ids.h"
enum {
## -1014,6 +1016,7 ## static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
dev->adap.algo = &smbus_algorithm;
dev->adap.algo_data = dev;
dev->adap.dev.parent = &hdev->dev;
+ dev->adap.dev.of_node = of_find_node_by_path("/i2c#cp2112");
snprintf(dev->adap.name, sizeof(dev->adap.name),
"CP2112 SMBus Bridge on hiddev%d", hdev->minor);
init_waitqueue_head(&dev->wait);
## -1029,6 +1032,8 ## static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
hid_dbg(hdev, "adapter registered\n");
+ of_i2c_register_devices(&dev->adap);
+
dev->gc.label = "cp2112_gpio";
dev->gc.direction_input = cp2112_gpio_direction_input;
dev->gc.direction_output = cp2112_gpio_direction_output;
The entry in the .dts file for the touch controller looks like this:
i2c#cp2112 {
#address-cells = <1>;
#size-cells = <0>;
st1332: touchscreen#55 {
compatible = "sitronix,st1232";
reg = <0x55>;
interrupt-parent = <&gpio>;
interrupts = <189 IRQ_TYPE_EDGE_FALLING>;
};
};
As a reference for those who may encounter similar problems notice that Clifford was backporting the cp2112 driver from Linux 4+ back to v3.10.40.
If you look at the kernel source for i2c busses it seems that they had to register themselves by using of_i2c_register_devices, but this need was removed from kernel v3.12 onwards. This is why the cp2112 driver does not call of_i2c_register_devices.
Related
I have this project that my boss asked me to do and the first step is to figure out how to set a given I2C register to high or low using the silicon lab library, if anyone knows any good sources for this type of problem please provide them thank you. The pic that I am using is the pic16f1823, I've already looked at the documentation of the pic but into only states how to read and write to an I2c.
I use this as a header file and seems to work well for PIC16F1827 which is basically the same as the 1823. It used the peripheral of the PIC. Just include in in any c file you want to use i2c in. Make sure you #define FOSC in order to calculate the correct baud rate. Also double check the port and tris assignments are correct for your device and make adjustments.
It uses polling instead of an interrupt. Uncomment the interrupt setup code and write an interrupt service routine to catch the interrupts.
#ifndef I2C_H
#define I2C_H
#ifdef __cplusplus
extern "C" {
#endif
/*
* Hi-Tech C I2C library for 12F1822
* Master mode routines for I2C MSSP port to read and write to slave device
* Copyright (C)2011 HobbyTronics.co.uk 2011
* Freely distributable.
*/
#define I2C_WRITE 0
#define I2C_READ 1
// Initialise MSSP port. (12F1822 - other devices may differ)
void i2c_Init(void){
// Initialise I2C MSSP
// Master 100KHz
TRISB2 = 1;
TRISB5 = 1;
SSP1CON1 = 0b00101000; // I2C Master mode
SSP1CON2 = 0b00000000;
SSP1CON3 = 0b00000000;
//SSP1MSK = 0b00000000;
SSP1ADD = I2C_BRG; // clock = FOSC/(4 * (SSPxADD+1))
//SSP1IE = 1; // enable interrupt
SSP1STAT = 0b10000000;
}
// i2c_Wait - wait for I2C transfer to finish
void i2c_Wait(void){
while ( ( SSP1CON2 & 0x1F ) || ( SSPSTAT & 0x04 ) );
}
// i2c_Start - Start I2C communication
void i2c_Start(void)
{
i2c_Wait();
SSP1CON2bits.SEN=1;
}
// i2c_Restart - Re-Start I2C communication
void i2c_Restart(void){
i2c_Wait();
SSP1CON2bits.RSEN=1;
}
// i2c_Stop - Stop I2C communication
void i2c_Stop(void)
{
i2c_Wait();
SSP1CON2bits.PEN=1;
}
// i2c_Write - Sends one byte of data
void i2c_Write(unsigned char data)
{
i2c_Wait();
SSPBUF = data;
}
// i2c_Address - Sends Slave Address and Read/Write mode
// mode is either I2C_WRITE or I2C_READ
void i2c_Address(unsigned char address, unsigned char mode)
{
unsigned char l_address;
l_address=address<<1;
l_address+=mode;
i2c_Wait();
SSPBUF = l_address;
}
// i2c_Read - Reads a byte from Slave device
unsigned char i2c_Read(unsigned char ack)
{
// Read data from slave
// ack should be 1 if there is going to be more data read
// ack should be 0 if this is the last byte of data read
unsigned char i2cReadData;
i2c_Wait();
SSP1CON2bits.RCEN=1;
i2c_Wait();
i2cReadData = SSPBUF;
i2c_Wait();
if ( ack ) SSP1CON2bits.ACKDT=0; // Ack
else SSP1CON2bits.ACKDT=1; // NAck
SSP1CON2bits.ACKEN=1; // send acknowledge sequence
return( i2cReadData );
}
#ifdef __cplusplus
}
#endif
#endif /* I2C_H */
Then you can use the higher level functions defined above to control a device, which is described in the datasheet of the slave device.
For example, to read from an eeprom:
#include <xc.h>
#define FOSC 16000000
#include "i2c.h"
unsigned char i2c_read_eeprom( unsigned char slaveaddress, unsigned char memaddress )
{
unsigned char data;
data = 123;
i2c_Start();
i2c_Address( slaveaddress, I2C_WRITE);
i2c_Write(memaddress);
if( SSP1CON2bits.ACKSTAT )
txstring("ACK!\r\n");
else txstring("nACK!\r\n");
i2c_Start();
i2c_Address( slaveaddress, I2C_READ);
data = i2c_Read(0);
i2c_Stop();
return data;
}
I am currently writing a device driver for Linux for use of PowerPC.
The device tree entry is as follows:
// PPS Interrupt client
pps_hwirq {
compatible = "pps-hwirq";
interrupts = <17 0x02>; // IPIC 17 = IRQ1, 0x02 = falling edge
interrupt-parent = < &ipic >;
};
The 0x02 flag is quite important - the PPS is aligned with the falling edge, but this is not universal on GPS receivers and therefore should be configurable.
In the probe() function of the driver, obtaining the IRQ number is straightforward:
hwirq = irq_of_parse_and_map(np, 0);
if (hwirq == NO_IRQ) {
dev_err(&pdev->dev, "No interrupt found in the device tree\n");
return -EINVAL;
}
But how does one map the the IRQ flags from the device tree to the driver?
/* ****TODO****: Get the interrupt flags from the device tree
* For now, hard code to suit my problem, but since this differs
* by GPS receiver, it should be configurable.
*/
flags = IRQF_TRIGGER_FALLING;
/* register IRQ interrupt handler */
ret = devm_request_irq(&pdev->dev, data->irq, pps_hwint_irq_handler,
flags, data->info.name, data);
Unfortunately, there are few - if any - examples in the tree that actually do this job - most leave this flag as 0 (leave as-is) - here's a snippet of the results when grep for devm_request_irq, noting the values for the flags:
./drivers/crypto/mxs-dcp.c: ret = devm_request_irq(dev, dcp_vmi_irq, mxs_dcp_irq, 0,
./drivers/crypto/mxs-dcp.c: ret = devm_request_irq(dev, dcp_irq, mxs_dcp_irq, 0,
./drivers/crypto/omap-sham.c: err = devm_request_irq(dev, dd->irq, dd->pdata->intr_hdlr,
./drivers/crypto/omap-aes.c: err = devm_request_irq(dev, irq, omap_aes_irq, 0,
./drivers/crypto/picoxcell_crypto.c: if (devm_request_irq(&pdev->dev, irq->start, spacc_spacc_irq, 0,
Or hard code it to what the hardware actually asserts:
./drivers/crypto/tegra-aes.c: err = devm_request_irq(dev, dd->irq, aes_irq, IRQF_TRIGGER_HIGH |
So how does one cleanly associate this property from the device tree to the actual driver?
Further I'm gonna show how to obtain IRQ number and IRQ flags from Device Tree in some common cases:
in I2C drivers
in platform drivers
manually
In I2C drivers
In short
If you're writing an I2C driver, you don't need to read IRQ parameters from DT manually. You can rely on I2C core to populate IRQ parameters for you:
in your probe() function, client->irq will contain the IRQ number
devm_request_irq() will use IRQ flags from DT automatically (just don't pass any IRQ trigger flags to that function).
Details
Let's look at the i2c_device_probe() function (it's where your driver's probe() function is being called from):
static int i2c_device_probe(struct device *dev)
{
...
if (dev->of_node) {
...
irq = of_irq_get(dev->of_node, 0);
}
...
client->irq = irq;
...
status = driver->probe(client, i2c_match_id(driver->id_table, client));
}
So, client->irq will already contain IRQ number in your driver's probe function.
As for IRQ flags: of_irq_get() (in code above) eventually calls irqd_set_trigger_type(), which internally stores IRQ flags (read from device tree) for your interrupt number. So, when you call devm_request_irq(), it eventually ends up in __setup_irq(), and it does next:
/*
* If the trigger type is not specified by the caller,
* then use the default for this interrupt.
*/
if (!(new->flags & IRQF_TRIGGER_MASK))
new->flags |= irqd_get_trigger_type(&desc->irq_data);
where:
new->flags contains flags you provided to devm_request_irq()
irqd_get_trigger_type() returns flags obtained from DT
In other words, if you don't pass IRQ flags to devm_request_irq() (e.g. pass 0), it will use IRQ flags obtained from device tree.
See also this question for details.
In platform drivers
You can use platform_get_irq() to obtain IRQ number. It also stores (internally) IRQ flags obtained from DT, so if you pass flags=0 to devm_request_irq(), flags from DT will be used.
Manually
If your driver doesn't rely on kernel frameworks, you have to obtain IRQ values manually:
IRQ number can be obtained (as you mentioned) by irq_of_parse_and_map(); this function not only returns IRQ number, but also stores IRQ flags for your IRQ number (by calling irqd_set_trigger_type() eventually); stored IRQ flags will be automatically used in devm_request_irq(), if you don't pass IRQ trigger type to it (e.g. you can pass flags=0)
IRQ flags can be obtained by irq_get_trigger_type(), but only after executing irq_of_parse_and_map()
So probably you only need to run irq_of_parse_and_map() and let devm_request_irq() handle flags for you (just make sure you don't pass trigger flags to it).
I am writing pci driver to access the Intel device with ID PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0., which is at ff:12.0 (device ID 0x6fa0).
But, turned out sbridge_edac driver was already installed and associated with that PCI device. This causes my pci_register_driver() to return error.
Is there a way to make my PCI driver use that PCI device if another driver already associated with it?
#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0 0x6fa0
static const struct pci_device_id sbridge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KNL_IMC_SAD0)},
{0,} /* 0 terminated list. */
};
MODULE_DEVICE_TABLE(pci, sbridge_pci_tbl);
static struct pci_driver discovery_pci_driver ={
.name = DRIVER_NAME,
.probe = discovery_probe,
.remove = discovery_remove,
.id_table = sbridge_pci_tbl,
};
static int __init discovery_init(void)
{
int res;
res = pci_register_driver(&discovery_pci_driver);
if(res<0) {
PERR("Adding driver to pci core failed\n");
return res;
}
return 0;
}
$lspci -x
ff:12.0 System peripheral: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0
Subsystem: Intel Corporation Xeon E7 v4/Xeon E5 v4/Xeon E3 v4/Xeon D Home Agent 0
Kernel driver in use: sbridge_edac
Since you want to create your own driver and associate it with the Intel hardware you can do one of the following:
Remove the sbridge_edac driver from the kernel config and recompile. You could also add your driver at this time.
Create a startup script that unloads the sbridge_edac driver and then loads in your driver.
Extend the sbridge_edac driver with your functionality (edit their code).
Create a function in your user space code that determines what driver is running and call it accordingly. You would have to put your driver functionality in your user space code and work with the sbridge_edac. But other user programs could access this one program instead of a driver.
I am trying to write a simple routine that will change the operating channel of the wireless device.
So far, I have:
/* These are function arguments */
struct ieee80211_local *local;
struct ieee80211_sub_if_data *sdata;
/* Declare a struct for the new channel */
struct cfg80211_chan_def new_channel;
/* Testing with 5765MHz */
new_channel.center_freq1 = 5765;
new_channel.center_freq2 = 0;
new_channel.chan = ieee80211_get_channel(sdata->local->hw.wiphy, 5765);
local->_oper_chandef = new_channel;
/* Reconfigure hardware */
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL);
However, I get plenty of Kernel level warnings due to invalid channel configuration, plus the channel does not change.
Hardware/software specifications:
Fujitsu Lifebook S
Atheros wireless card (ath9k)
Linux kernel 3.14 (mptcp-0.89, to be more precise)
I am using zynq-microzed board and I want to access GPIO with kernel space.
Can anyone please tell me how can i attempt doing this?
*NOTE: This is from the Zynq-7000. I believe it's largely the same.
Assuming you're using a devicetree, this is an example entry (in the devicetree):
gpio-device {
compatible = "gpio-control";
gpios = <&gpio0 54 0>; //(Add 32 to get the actual pin number. This is GPIO 86)
};
And you need to state in the driver that you're compatible with the devicetree entry (look at other drivers to see where to put this line):
.compatible = "gpio-control"
In your driver, include #include <linux/gpio.h> and read the pin from the devicetree:
struct device_node *np = pdev->dev.of_node;
int pin;
pin = of_get_gpio(np, 0);
if (pin < 0) {
pr_err("failed to get GPIO from device tree\n");
return -1;
}
Request the use of the GPIO:
int ret = gpio_request(pin, "Some name"); //Name it whatever you want
And set it's direction:
int ret = gpio_direction_output(pin, 0); //The second parameter is the initial value. 0 is low, 1 is high.
Afterwards, set the value like so:
gpio_set_value(pin, 1);
For input:
ret = gpio_direction_input(pin);
value = gpio_get_value(pin);
Free the GPIO when you're finished with it (including on error!):
gpio_free(pin);
At the end of the day, a good method is to grep around the kernel to find drivers that do what you want. In fact grep -r gpio <<kernel_source>> will tell you everything in this answer and more.
Check the following link: enter link description here
Summarizing:
There is an include file for working with GPIOs:
#include <linux/gpio.h>
GPIOs must be allocated before use:
int gpio_request(unsigned int gpio, const char *label);
And GPIO can be returned to the system with:
void gpio_free(unsigned int gpio);
Configure GPIO as Input/Output:
int gpio_direction_input(unsigned int gpio);
int gpio_direction_output(unsigned int gpio, int value);
Operations:
int gpio_get_value(unsigned int gpio);
void gpio_set_value(unsigned int gpio, int value);
Regards.