#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_SSD1306_DEBUG #define dbg(msg...) printk(KERN_INFO msg) #else #define dbg(msg...) do{}while(0) #endif struct gpio gsc3280_gpio[1] = { {GSC3280_GPA(31), GPIOF_OUT_INIT_HIGH, "OLED_RST"}, }; #define gsc3280_set_gpio_reg_bit(reg) do{\ unsigned int reg_val = 0; \ reg_val = __raw_readl((volatile unsigned int *)(reg));\ reg_val |= (0x1<",30*/ {0x00,0x00,0x0E,0x00,0x12,0x00,0x10,0x0C,0x10,0x6C,0x10,0x80,0x0F,0x00,0x00,0x00},/*"?",31*/ {0x03,0xE0,0x0C,0x18,0x13,0xE4,0x14,0x24,0x17,0xC4,0x08,0x28,0x07,0xD0,0x00,0x00},/*"@",32*/ {0x00,0x04,0x00,0x3C,0x03,0xC4,0x1C,0x40,0x07,0x40,0x00,0xE4,0x00,0x1C,0x00,0x04},/*"A",33*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x11,0x04,0x0E,0x88,0x00,0x70,0x00,0x00},/*"B",34*/ {0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x1C,0x10,0x00,0x00},/*"C",35*/ {0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"D",36*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x04,0x17,0xC4,0x10,0x04,0x08,0x18,0x00,0x00},/*"E",37*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x17,0xC0,0x10,0x00,0x08,0x00,0x00,0x00},/*"F",38*/ {0x03,0xE0,0x0C,0x18,0x10,0x04,0x10,0x04,0x10,0x44,0x1C,0x78,0x00,0x40,0x00,0x00},/*"G",39*/ {0x10,0x04,0x1F,0xFC,0x10,0x84,0x00,0x80,0x00,0x80,0x10,0x84,0x1F,0xFC,0x10,0x04},/*"H",40*/ {0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x04,0x00,0x00,0x00,0x00},/*"I",41*/ {0x00,0x03,0x00,0x01,0x10,0x01,0x10,0x01,0x1F,0xFE,0x10,0x00,0x10,0x00,0x00,0x00},/*"J",42*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x03,0x80,0x14,0x64,0x18,0x1C,0x10,0x04,0x00,0x00},/*"K",43*/ {0x10,0x04,0x1F,0xFC,0x10,0x04,0x00,0x04,0x00,0x04,0x00,0x04,0x00,0x0C,0x00,0x00},/*"L",44*/ {0x10,0x04,0x1F,0xFC,0x1F,0x00,0x00,0xFC,0x1F,0x00,0x1F,0xFC,0x10,0x04,0x00,0x00},/*"M",45*/ {0x10,0x04,0x1F,0xFC,0x0C,0x04,0x03,0x00,0x00,0xE0,0x10,0x18,0x1F,0xFC,0x10,0x00},/*"N",46*/ {0x07,0xF0,0x08,0x08,0x10,0x04,0x10,0x04,0x10,0x04,0x08,0x08,0x07,0xF0,0x00,0x00},/*"O",47*/ {0x10,0x04,0x1F,0xFC,0x10,0x84,0x10,0x80,0x10,0x80,0x10,0x80,0x0F,0x00,0x00,0x00},/*"P",48*/ {0x07,0xF0,0x08,0x18,0x10,0x24,0x10,0x24,0x10,0x1C,0x08,0x0A,0x07,0xF2,0x00,0x00},/*"Q",49*/ {0x10,0x04,0x1F,0xFC,0x11,0x04,0x11,0x00,0x11,0xC0,0x11,0x30,0x0E,0x0C,0x00,0x04},/*"R",50*/ {0x00,0x00,0x0E,0x1C,0x11,0x04,0x10,0x84,0x10,0x84,0x10,0x44,0x1C,0x38,0x00,0x00},/*"S",51*/ {0x18,0x00,0x10,0x00,0x10,0x04,0x1F,0xFC,0x10,0x04,0x10,0x00,0x18,0x00,0x00,0x00},/*"T",52*/ {0x10,0x00,0x1F,0xF8,0x10,0x04,0x00,0x04,0x00,0x04,0x10,0x04,0x1F,0xF8,0x10,0x00},/*"U",53*/ {0x10,0x00,0x1E,0x00,0x11,0xE0,0x00,0x1C,0x00,0x70,0x13,0x80,0x1C,0x00,0x10,0x00},/*"V",54*/ {0x1F,0xC0,0x10,0x3C,0x00,0xE0,0x1F,0x00,0x00,0xE0,0x10,0x3C,0x1F,0xC0,0x00,0x00},/*"W",55*/ {0x10,0x04,0x18,0x0C,0x16,0x34,0x01,0xC0,0x01,0xC0,0x16,0x34,0x18,0x0C,0x10,0x04},/*"X",56*/ {0x10,0x00,0x1C,0x00,0x13,0x04,0x00,0xFC,0x13,0x04,0x1C,0x00,0x10,0x00,0x00,0x00},/*"Y",57*/ {0x08,0x04,0x10,0x1C,0x10,0x64,0x10,0x84,0x13,0x04,0x1C,0x04,0x10,0x18,0x00,0x00},/*"Z",58*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x40,0x02,0x40,0x02,0x40,0x02,0x00,0x00},/*"[",59*/ {0x00,0x00,0x30,0x00,0x0C,0x00,0x03,0x80,0x00,0x60,0x00,0x1C,0x00,0x03,0x00,0x00},/*"\",60*/ {0x00,0x00,0x40,0x02,0x40,0x02,0x40,0x02,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00},/*"]",61*/ {0x00,0x00,0x00,0x00,0x20,0x00,0x40,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00},/*"^",62*/ {0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01},/*"_",63*/ {0x00,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"`",64*/ {0x00,0x00,0x00,0x98,0x01,0x24,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xFC,0x00,0x04},/*"a",65*/ {0x10,0x00,0x1F,0xFC,0x00,0x88,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"b",66*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x00},/*"c",67*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x11,0x08,0x1F,0xFC,0x00,0x04},/*"d",68*/ {0x00,0x00,0x00,0xF8,0x01,0x44,0x01,0x44,0x01,0x44,0x01,0x44,0x00,0xC8,0x00,0x00},/*"e",69*/ {0x00,0x00,0x01,0x04,0x01,0x04,0x0F,0xFC,0x11,0x04,0x11,0x04,0x11,0x00,0x18,0x00},/*"f",70*/ {0x00,0x00,0x00,0xD6,0x01,0x29,0x01,0x29,0x01,0x29,0x01,0xC9,0x01,0x06,0x00,0x00},/*"g",71*/ {0x10,0x04,0x1F,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"h",72*/ {0x00,0x00,0x01,0x04,0x19,0x04,0x19,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"i",73*/ {0x00,0x00,0x00,0x03,0x00,0x01,0x01,0x01,0x19,0x01,0x19,0xFE,0x00,0x00,0x00,0x00},/*"j",74*/ {0x10,0x04,0x1F,0xFC,0x00,0x24,0x00,0x40,0x01,0xB4,0x01,0x0C,0x01,0x04,0x00,0x00},/*"k",75*/ {0x00,0x00,0x10,0x04,0x10,0x04,0x1F,0xFC,0x00,0x04,0x00,0x04,0x00,0x00,0x00,0x00},/*"l",76*/ {0x01,0x04,0x01,0xFC,0x01,0x04,0x01,0x00,0x01,0xFC,0x01,0x04,0x01,0x00,0x00,0xFC},/*"m",77*/ {0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x00,0x01,0x00,0x01,0x04,0x00,0xFC,0x00,0x04},/*"n",78*/ {0x00,0x00,0x00,0xF8,0x01,0x04,0x01,0x04,0x01,0x04,0x01,0x04,0x00,0xF8,0x00,0x00},/*"o",79*/ {0x01,0x01,0x01,0xFF,0x00,0x85,0x01,0x04,0x01,0x04,0x00,0x88,0x00,0x70,0x00,0x00},/*"p",80*/ {0x00,0x00,0x00,0x70,0x00,0x88,0x01,0x04,0x01,0x04,0x01,0x05,0x01,0xFF,0x00,0x01},/*"q",81*/ {0x01,0x04,0x01,0x04,0x01,0xFC,0x00,0x84,0x01,0x04,0x01,0x00,0x01,0x80,0x00,0x00},/*"r",82*/ {0x00,0x00,0x00,0xCC,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x24,0x01,0x98,0x00,0x00},/*"s",83*/ {0x00,0x00,0x01,0x00,0x01,0x00,0x07,0xF8,0x01,0x04,0x01,0x04,0x00,0x00,0x00,0x00},/*"t",84*/ {0x01,0x00,0x01,0xF8,0x00,0x04,0x00,0x04,0x00,0x04,0x01,0x08,0x01,0xFC,0x00,0x04},/*"u",85*/ {0x01,0x00,0x01,0x80,0x01,0x70,0x00,0x0C,0x00,0x10,0x01,0x60,0x01,0x80,0x01,0x00},/*"v",86*/ {0x01,0xF0,0x01,0x0C,0x00,0x30,0x01,0xC0,0x00,0x30,0x01,0x0C,0x01,0xF0,0x01,0x00},/*"w",87*/ {0x00,0x00,0x01,0x04,0x01,0x8C,0x00,0x74,0x01,0x70,0x01,0x8C,0x01,0x04,0x00,0x00},/*"x",88*/ {0x01,0x01,0x01,0x81,0x01,0x71,0x00,0x0E,0x00,0x18,0x01,0x60,0x01,0x80,0x01,0x00},/*"y",89*/ {0x00,0x00,0x01,0x84,0x01,0x0C,0x01,0x34,0x01,0x44,0x01,0x84,0x01,0x0C,0x00,0x00},/*"z",90*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x3E,0xFC,0x40,0x02,0x40,0x02},/*"{",91*/ {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0x00,0x00,0x00,0x00,0x00,0x00},/*"|",92*/ {0x00,0x00,0x40,0x02,0x40,0x02,0x3E,0xFC,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"}",93*/ {0x00,0x00,0x60,0x00,0x80,0x00,0x80,0x00,0x40,0x00,0x40,0x00,0x20,0x00,0x20,0x00},/*"~",94*/ }; struct i2c_client *ssd1306_client; static void ssd1306_write_byte(uint8_t chData, uint8_t chCmd) { uint8_t cmd = 0x00; uint8_t tmp[2]; memset(tmp,0,2); if (chCmd) { cmd = 0x40; } else { cmd = 0x00; } tmp[0] = cmd; tmp[1] = chData; i2c_master_send(ssd1306_client, tmp , 2); } #if 0 int ssd1306_read_bytes(uint8_t *data, uint16_t len) { return i2c_master_recv(ssd1306_client, data, len); } #endif void ssd1306_display_on(void) { printk(KERN_INFO "ssd1306_display_on\n"); ssd1306_write_byte(0x8D, SSD1306_CMD); ssd1306_write_byte(0x14, SSD1306_CMD); ssd1306_write_byte(0xAF, SSD1306_CMD); } /** * @brief OLED turns off * * @param None * * @retval None **/ void ssd1306_display_off(void) { ssd1306_write_byte(0x8D, SSD1306_CMD); ssd1306_write_byte(0x10, SSD1306_CMD); ssd1306_write_byte(0xAE, SSD1306_CMD); } void ssd1306_refresh_gram(void) { uint8_t i, j; for (i = 0; i < 8; i ++) { ssd1306_write_byte(0xB0 + i, SSD1306_CMD); ssd1306_write_byte(0x02, SSD1306_CMD); ssd1306_write_byte(0x10, SSD1306_CMD); for (j = 0; j < 128; j ++) { ssd1306_write_byte(s_chDispalyBuffer[j][i], SSD1306_DAT); } } } void ssd1306_clear_screen(uint8_t chFill) { memset(s_chDispalyBuffer,chFill, sizeof(s_chDispalyBuffer)); ssd1306_refresh_gram(); } /** * @brief Draws a piont on the screen * * @param chXpos: Specifies the X position * @param chYpos: Specifies the Y position * @param chPoint: 0: the point turns off 1: the piont turns on * * @retval None **/ void ssd1306_draw_point(uint8_t chXpos, uint8_t chYpos, uint8_t chPoint) { uint8_t chPos, chBx, chTemp = 0; if (chXpos > 127 || chYpos > 63) { return; } chPos = 7 - chYpos / 8; // chBx = chYpos % 8; chTemp = 1 << (7 - chBx); if (chPoint) { s_chDispalyBuffer[chXpos][chPos] |= chTemp; } else { s_chDispalyBuffer[chXpos][chPos] &= ~chTemp; } } /** * @brief Fills a rectangle * * @param chXpos1: Specifies the X position 1 (X top left position) * @param chYpos1: Specifies the Y position 1 (Y top left position) * @param chXpos2: Specifies the X position 2 (X bottom right position) * @param chYpos3: Specifies the Y position 2 (Y bottom right position) * * @retval **/ void ssd1306_fill_screen(uint8_t chXpos1, uint8_t chYpos1, uint8_t chXpos2, uint8_t chYpos2, uint8_t chDot) { uint8_t chXpos, chYpos; for (chXpos = chXpos1; chXpos <= chXpos2; chXpos ++) { for (chYpos = chYpos1; chYpos <= chYpos2; chYpos ++) { ssd1306_draw_point(chXpos, chYpos, chDot); } } ssd1306_refresh_gram(); } /** * @brief Displays one character at the specified position * * @param chXpos: Specifies the X position * @param chYpos: Specifies the Y position * @param chSize: * @param chMode * @retval **/ void ssd1306_display_char(uint8_t chXpos, uint8_t chYpos, uint8_t chChr, uint8_t chSize, uint8_t chMode) { uint8_t i, j; uint8_t chTemp, chYpos0 = chYpos; chChr = chChr - ' '; for (i = 0; i < chSize; i ++) { if (chMode) { chTemp = c_chFont1608[chChr][i]; } else { chTemp = ~c_chFont1608[chChr][i]; } for (j = 0; j < 8; j ++) { if (chTemp & 0x80) { ssd1306_draw_point(chXpos, chYpos, 1); } else { ssd1306_draw_point(chXpos, chYpos, 0); } chTemp <<= 1; chYpos ++; if ((chYpos - chYpos0) == chSize) { chYpos = chYpos0; chXpos ++; break; } } } } /** * @brief Displays a string on the screen * * @param chXpos: Specifies the X position * @param chYpos: Specifies the Y position * @param pchString: Pointer to a string to display on the screen * * @retval None **/ void ssd1306_display_string(uint8_t chXpos, uint8_t chYpos, const uint8_t *pchString, uint8_t chSize, uint8_t chMode) { while (*pchString != '\0') { if (chXpos > (SSD1306_WIDTH - chSize / 2)) { chXpos = 0; chYpos += chSize; if (chYpos > (SSD1306_HEIGHT - chSize)) { chYpos = chXpos = 0; ssd1306_clear_screen(0x00); } } ssd1306_display_char(chXpos, chYpos, *pchString, chSize, chMode); chXpos += chSize / 2; pchString ++; } } void ssd1306_init(void) { printk(KERN_INFO "ssd1306_init\n"); ssd1306_write_byte(0xAE, SSD1306_CMD);//--turn off oled panel ssd1306_write_byte(0x00, SSD1306_CMD);//---set low column address ssd1306_write_byte(0x10, SSD1306_CMD);//---set high column address ssd1306_write_byte(0x40, SSD1306_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F) ssd1306_write_byte(0x81, SSD1306_CMD);//--set contrast control register ssd1306_write_byte(0xCF, SSD1306_CMD);// Set SEG Output Current Brightness ssd1306_write_byte(0xA1, SSD1306_CMD);//--Set SEG/Column Mapping ssd1306_write_byte(0xC0, SSD1306_CMD);//Set COM/Row Scan Direction ssd1306_write_byte(0xA6, SSD1306_CMD);//--set normal display ssd1306_write_byte(0xA8, SSD1306_CMD);//--set multiplex ratio(1 to 64) ssd1306_write_byte(0x3f, SSD1306_CMD);//--1/64 duty ssd1306_write_byte(0xD3, SSD1306_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) ssd1306_write_byte(0x00, SSD1306_CMD);//-not offset ssd1306_write_byte(0xd5, SSD1306_CMD);//--set display clock divide ratio/oscillator frequency ssd1306_write_byte(0x80, SSD1306_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec ssd1306_write_byte(0xD9, SSD1306_CMD);//--set pre-charge period ssd1306_write_byte(0xF1, SSD1306_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock ssd1306_write_byte(0xDA, SSD1306_CMD);//--set com pins hardware configuration ssd1306_write_byte(0x12, SSD1306_CMD); ssd1306_write_byte(0xDB, SSD1306_CMD);//--set vcomh ssd1306_write_byte(0x40, SSD1306_CMD);//Set VCOM Deselect Level ssd1306_write_byte(0x20, SSD1306_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02) ssd1306_write_byte(0x02, SSD1306_CMD);// ssd1306_write_byte(0x8D, SSD1306_CMD);//--set Charge Pump enable/disable ssd1306_write_byte(0x14, SSD1306_CMD);//--set(0x10) disable ssd1306_write_byte(0xA4, SSD1306_CMD);// Disable Entire Display On (0xa4/0xa5) ssd1306_write_byte(0xA6, SSD1306_CMD);// Disable Inverse Display On (0xa6/a7) ssd1306_write_byte(0xAF, SSD1306_CMD);//--turn on oled panel ssd1306_display_on(); ssd1306_clear_screen(0xff); } #if 0 static int ssd1306_detect(struct i2c_adapter *adapter, int address, int kind) { printk(KERN_INFO "ssd1306_detect\n"); ssd1306_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); ssd1306_client->addr = address; ssd1306_client->adapter = adapter; ssd1306_client->driver = &ssd1306_driver; strcpy(ssd1306_client->name, "ssd1306"); i2c_attach_client(ssd1306_client); ssd1306_init(); ssd1306_clear_screen(0x00); ssd1306_display_off(); ssd1306_display_string(18, 0, "hello, Linux!", 16, 1); ssd1306_display_string(0, 16, "this is an i2c driver demo!", 16, 1); ssd1306_refresh_gram(); ssd1306_display_on(); return 0; } static int ssd1306_probe(struct i2c_adapter *adapter) { return i2c_probe(adapter, &addr_data, ssd1306_detect); } #endif static int ssd1306_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; printk(KERN_INFO "________________________ssd1306_probe\n"); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { err = -ENODEV; return err; } ssd1306_client = client; ssd1306_client->addr = client->addr; ssd1306_dev = kzalloc(sizeof(*ssd1306_dev),GFP_KERNEL); if(!ssd1306_dev) { err = -ENOMEM; return -1; } i2c_set_clientdata(ssd1306_client, ssd1306_dev); ssd1306_init(); ssd1306_clear_screen(0x00); ssd1306_display_off(); ssd1306_display_string(18, 0, "hello, Linux!", 16, 1); ssd1306_display_string(0, 16, "this is an i2c driver demo!", 16, 1); ssd1306_refresh_gram(); ssd1306_display_on(); printk(KERN_INFO "ssd1306_work_ok\n"); return 0; } static int __devexit ssd1306_remove(struct i2c_client *client) { printk(KERN_INFO "ssd1306_detach\n"); ssd1306_display_off(); ssd1306_clear_screen(0x00); return 0; } static const struct i2c_device_id ssd1306_id[]={ {"ssd1306", 0}, { }, }; static struct i2c_driver ssd1306_driver = { .driver = { .name = "ssd1306", .owner = THIS_MODULE, }, .probe = ssd1306_probe, .remove = __devexit_p(ssd1306_remove), .id_table = ssd1306_id, }; static int __init ssd1306_module_init(void) { int ret = -1; printk(KERN_INFO "ssd1306 driver init...\n"); ret = i2c_add_driver(&ssd1306_driver); if(ret < 0) printk(KERN_INFO "add ssd1306 driver fail......\n"); return ret; } static void __exit ssd1306_module_exit(void) { printk(KERN_INFO "ssd1306 driver exit...\n"); i2c_del_driver(&ssd1306_driver); } module_init(ssd1306_module_init); module_exit(ssd1306_module_exit); MODULE_AUTHOR("songxingjia@china-cpu.com"); MODULE_DESCRIPTION("OLED SSD1306 DRIVER"); MODULE_LICENSE("GPL");